From ec59a762007bce31b5ec78cd90f0aee66b36b641 Mon Sep 17 00:00:00 2001 From: DeltaMikeCharlie <127641886+DeltaMikeCharlie@users.noreply.github.com> Date: Wed, 21 Aug 2024 11:11:25 +1000 Subject: [PATCH] Add support for TVH Parental Rating fields (Piers). --- src/Tvheadend.cpp | 59 ++++++++++++++++++++++++++++++++ src/tvheadend/HTSPConnection.cpp | 2 +- src/tvheadend/entity/Event.h | 17 ++++++++- src/tvheadend/entity/Recording.h | 24 +++++++++++-- 4 files changed, 98 insertions(+), 4 deletions(-) diff --git a/src/Tvheadend.cpp b/src/Tvheadend.cpp index b9fb15b9..28e6ce1a 100644 --- a/src/Tvheadend.cpp +++ b/src/Tvheadend.cpp @@ -592,6 +592,18 @@ PVR_ERROR CTvheadend::GetRecordings(bool deleted, kodi::addon::PVRRecordingsResu break; } + /* parental age rating */ + rec.SetParentalRating(recording.GetAgeRating()); + + /* parental age rating code*/ + rec.SetParentalRatingCode(recording.GetRatingLabel()); + + /* parental age rating icon URL*/ + rec.SetParentalRatingIcon(recording.GetRatingIcon()); + + /* parental age rating source*/ + rec.SetParentalRatingSource(recording.GetRatingSource()); + recs.emplace_back(rec); } } @@ -1360,6 +1372,9 @@ void CTvheadend::CreateEvent(const Event& event, kodi::addon::PVREPGTag& epg) } epg.SetFirstAired(event.GetAired()); epg.SetParentalRating(event.GetAge()); + epg.SetParentalRatingCode(event.GetRatingLabel()); + epg.SetParentalRatingIcon(event.GetRatingIcon()); + epg.SetParentalRatingSource(event.GetRatingSource()); epg.SetStarRating(event.GetStars()); epg.SetSeriesNumber(event.GetSeason()); epg.SetEpisodeNumber(event.GetEpisode()); @@ -2530,6 +2545,30 @@ void CTvheadend::ParseRecordingAddOrUpdate(htsmsg_t* msg, bool bAdd) if (str) rec.SetFanartImage(GetImageURL(str)); + uint32_t ageRating = 0; + if (!htsmsg_get_u32(msg, "ageRating", &ageRating)) + rec.SetAgeRating(ageRating); + + str = htsmsg_get_str(msg, "ratingLabel"); + if (str) + rec.SetRatingLabel(str); + + str = htsmsg_get_str(msg, "ratingIcon"); + if (str) + rec.SetRatingIcon(GetImageURL(str)); + + str = htsmsg_get_str(msg, "ratingAuthority"); + if (str) + { + rec.SetRatingSource(str); + } + else + { + str = htsmsg_get_str(msg, "ratingCountry"); + if (str) + rec.SetRatingSource(str); + } + if (m_conn->GetProtocol() >= 32) { if (rec.GetDescription().empty() && !rec.GetSubtitle().empty()) @@ -2706,6 +2745,26 @@ bool CTvheadend::ParseEvent(htsmsg_t* msg, bool bAdd, Event& evt) if (!htsmsg_get_u32(msg, "ageRating", &u32)) evt.SetAge(u32); + str = htsmsg_get_str(msg, "ratingLabel"); // HTSP v36 required + if (str) + evt.SetRatingLabel(str); + + str = htsmsg_get_str(msg, "ratingIcon"); // HTSP v36 required + if (str) + evt.SetRatingIcon(GetImageURL(str)); + + str = htsmsg_get_str(msg, "ratingAuthority"); + if (str) + { + evt.SetRatingSource(str); + } + else + { + str = htsmsg_get_str(msg, "ratingCountry"); + if (str) + evt.SetRatingSource(str); + } + int64_t s64 = 0; if (!htsmsg_get_s64(msg, "firstAired", &s64)) evt.SetAired(static_cast(s64)); diff --git a/src/tvheadend/HTSPConnection.cpp b/src/tvheadend/HTSPConnection.cpp index 76b7d18f..2e08f259 100644 --- a/src/tvheadend/HTSPConnection.cpp +++ b/src/tvheadend/HTSPConnection.cpp @@ -34,7 +34,7 @@ using namespace tvheadend::utilities; #define HTSP_MIN_SERVER_VERSION (26) // Server must support at least this htsp version #define HTSP_CLIENT_VERSION \ - (35) // Client uses HTSP features up to this version. If the respective \ + (37) // Client uses HTSP features up to this version. If the respective \ // addon feature requires htsp features introduced after \ // HTSP_MIN_SERVER_VERSION this feature will only be available if the \ // actual server HTSP version matches (runtime htsp version check). diff --git a/src/tvheadend/entity/Event.h b/src/tvheadend/entity/Event.h index 513bdaa3..f78afa99 100644 --- a/src/tvheadend/entity/Event.h +++ b/src/tvheadend/entity/Event.h @@ -56,7 +56,10 @@ class Event : public Entity m_recordingId == other.m_recordingId && m_seriesLink == other.m_seriesLink && m_year == other.m_year && m_writers == other.m_writers && m_directors == other.m_directors && m_cast == other.m_cast && - m_categories == other.m_categories; + m_categories == other.m_categories && + m_ratingLabel == other.m_ratingLabel && + m_ratingIcon == other.m_ratingIcon && + m_ratingSource == other.m_ratingSource; } bool operator!=(const Event& other) const { return !(*this == other); } @@ -84,6 +87,15 @@ class Event : public Entity uint32_t GetAge() const { return m_age; } void SetAge(uint32_t age) { m_age = age; } + const std::string& GetRatingLabel() const { return m_ratingLabel; } + void SetRatingLabel(const std::string& ratingLabel) { m_ratingLabel = ratingLabel; } + + const std::string& GetRatingIcon() const { return m_ratingIcon; } + void SetRatingIcon(const std::string& ratingIcon) { m_ratingIcon = ratingIcon; } + + const std::string& GetRatingSource() const { return m_ratingSource; } + void SetRatingSource(const std::string& ratingSource) { m_ratingSource = ratingSource; } + int32_t GetSeason() const { return m_season; } void SetSeason(int32_t season) { m_season = season; } @@ -157,6 +169,9 @@ class Event : public Entity std::string m_cast; std::string m_categories; std::string m_aired; + std::string m_ratingLabel; // Label like 'PG' or 'FSK 12' + std::string m_ratingIcon; // Path to graphic for the above label. + std::string m_ratingSource; // Parental rating source. }; } // namespace entity diff --git a/src/tvheadend/entity/Recording.h b/src/tvheadend/entity/Recording.h index 50fb9a76..5bbb0312 100644 --- a/src/tvheadend/entity/Recording.h +++ b/src/tvheadend/entity/Recording.h @@ -62,7 +62,8 @@ class Recording : public Entity m_contentType(0), m_season(-1), m_episode(-1), - m_part(0) + m_part(0), + m_ageRating(0) { } @@ -80,7 +81,10 @@ class Recording : public Entity m_error == other.m_error && m_lifetime == other.m_lifetime && m_priority == other.m_priority && m_playCount == other.m_playCount && m_playPosition == other.m_playPosition && m_contentType == other.m_contentType && - m_season == other.m_season && m_episode == other.m_episode && m_part == other.m_part; + m_season == other.m_season && m_episode == other.m_episode && m_part == other.m_part && + m_ageRating == other.m_ageRating && m_ratingLabel == other.m_ratingLabel && + m_ratingIcon == other.m_ratingIcon; + m_ratingSource == other.m_ratingSource; } bool operator!=(const Recording& other) const { return !(*this == other); } @@ -210,6 +214,18 @@ class Recording : public Entity uint32_t GetPart() const { return m_part; } void SetPart(uint32_t part) { m_part = part; } + void SetAgeRating(uint32_t content) { m_ageRating = content; } + uint32_t GetAgeRating() const { return m_ageRating; } + + const std::string& GetRatingLabel() const { return m_ratingLabel; } + void SetRatingLabel(const std::string& ratingLabel) { m_ratingLabel = ratingLabel; } + + const std::string& GetRatingIcon() const { return m_ratingIcon; } + void SetRatingIcon(const std::string& ratingIcon) { m_ratingIcon = ratingIcon; } + + const std::string& GetRatingSource() const { return m_ratingSource; } + void SetRatingSource(const std::string& ratingSource) { m_ratingSource = ratingSource; } + private: uint32_t m_enabled; uint32_t m_channel; @@ -241,6 +257,10 @@ class Recording : public Entity int32_t m_season; int32_t m_episode; uint32_t m_part; + uint32_t m_ageRating; + std::string m_ratingLabel; + std::string m_ratingIcon; + std::string m_ratingSource; }; } // namespace entity