From 67a68d204af8058c9251b797fcdca728cf642ebb Mon Sep 17 00:00:00 2001 From: Kai Sommerfeld Date: Mon, 18 Feb 2019 23:48:06 +0100 Subject: [PVR] Fix PVR inter component dependencies: epg must not depend on channels. --- .../resource.language.en_gb/resources/strings.po | 186 +++++------ xbmc/FileItem.cpp | 36 +- xbmc/addons/PVRClient.cpp | 38 ++- xbmc/addons/PVRClient.h | 5 +- xbmc/cores/VideoPlayer/Edl.cpp | 2 +- xbmc/interfaces/json-rpc/PVROperations.cpp | 9 +- xbmc/pvr/PVRContextMenus.cpp | 5 +- xbmc/pvr/PVRGUIActions.cpp | 8 +- xbmc/pvr/PVRGUIInfo.cpp | 22 +- xbmc/pvr/PVRGUITimesInfo.cpp | 5 +- xbmc/pvr/PVRItem.cpp | 8 +- xbmc/pvr/PVRManager.cpp | 38 ++- xbmc/pvr/PVRManager.h | 21 +- xbmc/pvr/channels/PVRChannel.cpp | 57 +++- xbmc/pvr/channels/PVRChannel.h | 3 +- xbmc/pvr/channels/PVRChannelGroup.cpp | 11 +- xbmc/pvr/channels/PVRChannelGroups.cpp | 2 +- xbmc/pvr/channels/PVRChannelGroupsContainer.cpp | 10 + xbmc/pvr/channels/PVRChannelGroupsContainer.h | 7 + xbmc/pvr/dialogs/GUIDialogPVRGuideInfo.cpp | 10 +- xbmc/pvr/epg/CMakeLists.txt | 6 +- xbmc/pvr/epg/Epg.cpp | 197 +++++------ xbmc/pvr/epg/Epg.h | 39 +-- xbmc/pvr/epg/EpgChannelData.cpp | 135 ++++++++ xbmc/pvr/epg/EpgChannelData.h | 67 ++++ xbmc/pvr/epg/EpgContainer.cpp | 151 ++++----- xbmc/pvr/epg/EpgContainer.h | 40 ++- xbmc/pvr/epg/EpgDatabase.cpp | 16 +- xbmc/pvr/epg/EpgInfoTag.cpp | 362 +++++++++------------ xbmc/pvr/epg/EpgInfoTag.h | 90 +++-- xbmc/pvr/epg/EpgSearchFilter.cpp | 46 ++- xbmc/pvr/timers/PVRTimerInfoTag.cpp | 7 +- xbmc/pvr/timers/PVRTimers.cpp | 41 +-- xbmc/pvr/windows/GUIEPGGridContainer.cpp | 12 +- xbmc/pvr/windows/GUIEPGGridContainerModel.cpp | 47 ++- xbmc/pvr/windows/GUIEPGGridContainerModel.h | 1 + xbmc/pvr/windows/GUIWindowPVRGuide.cpp | 17 +- xbmc/pvr/windows/GUIWindowPVRSearch.cpp | 2 +- 38 files changed, 1042 insertions(+), 717 deletions(-) create mode 100644 xbmc/pvr/epg/EpgChannelData.cpp create mode 100644 xbmc/pvr/epg/EpgChannelData.h diff --git a/addons/resource.language.en_gb/resources/strings.po b/addons/resource.language.en_gb/resources/strings.po index 803f3b5b5f..ebaa166c03 100644 --- a/addons/resource.language.en_gb/resources/strings.po +++ b/addons/resource.language.en_gb/resources/strings.po @@ -9094,7 +9094,7 @@ msgid "Find similar" msgstr "" #. label for epg import progress control -#: xbmc/epg/EpgContainer.cpp +#: xbmc/pvr/epg/EpgContainer.cpp msgctxt "#19004" msgid "Importing guide from clients" msgstr "" @@ -9443,7 +9443,7 @@ msgstr "" #: addons/skin.estuary/xml/MyPics.xml #: addons/skin.estuary/xml/MyVideoNav.xml #: addons/skin.estuary/xml/View_50_List.xml -#: xbmc/epg/EpgInfoTag.cpp +#: xbmc/pvr/epg/EpgInfoTag.cpp #: xbmc/FileItem.cpp #: xbmc/GUIInfoManager.cpp #: xbmc/pvr/PVRManager.cpp @@ -10608,7 +10608,7 @@ msgid "Filter channels" msgstr "" #. label 'loading epg data from database' for progress dialog text -#: xbmc/epg/EpgContainer.cpp +#: xbmc/pvr/epg/EpgContainer.cpp msgctxt "#19250" msgid "Loading guide from database" msgstr "" @@ -10702,7 +10702,7 @@ msgid "The entered PIN was incorrect." msgstr "" #. label to use for epg tag title instead of actual event title if the respective channel is parental locked -#: xbmc/epg/EpgInfoTag.cpp +#: xbmc/pvr/PVRGUIActions.cpp msgctxt "#19266" msgid "Parental locked" msgstr "" @@ -10935,63 +10935,63 @@ msgstr "" #empty strings from id 19305 to 19498 #. label for epg genre value -#: xbmc/epg/Epg.cpp +#: xbmc/pvr/epg/Epg.cpp #: xbmc/pvr/dialogs/GUIDialogPVRGuideSearch.cpp msgctxt "#19499" msgid "Other / Unknown" msgstr "" #. label for epg "movie/drama" genre value -#: xbmc/epg/Epg.cpp +#: xbmc/pvr/epg/Epg.cpp #: xbmc/pvr/dialogs/GUIDialogPVRGuideSearch.cpp msgctxt "#19500" msgid "Movie / Drama" msgstr "" #. label for epg "movie/drama" subgenre value -#: xbmc/epg/Epg.cpp +#: xbmc/pvr/epg/Epg.cpp msgctxt "#19501" msgid "Detective / Thriller" msgstr "" #. label for epg "movie/drama" subgenre value -#: xbmc/epg/Epg.cpp +#: xbmc/pvr/epg/Epg.cpp msgctxt "#19502" msgid "Adventure / Western / War" msgstr "" #. label for epg "movie/drama" subgenre value -#: xbmc/epg/Epg.cpp +#: xbmc/pvr/epg/Epg.cpp msgctxt "#19503" msgid "Science fiction / Fantasy / Horror" msgstr "" #. label for epg "movie/drama" subgenre value -#: xbmc/epg/Epg.cpp +#: xbmc/pvr/epg/Epg.cpp msgctxt "#19504" msgid "Comedy" msgstr "" #. label for epg "movie/drama" subgenre value -#: xbmc/epg/Epg.cpp +#: xbmc/pvr/epg/Epg.cpp msgctxt "#19505" msgid "Soap / Melodrama / Folkloric" msgstr "" #. label for epg "movie/drama" subgenre value -#: xbmc/epg/Epg.cpp +#: xbmc/pvr/epg/Epg.cpp msgctxt "#19506" msgid "Romance" msgstr "" #. label for epg "movie/drama" subgenre value -#: xbmc/epg/Epg.cpp +#: xbmc/pvr/epg/Epg.cpp msgctxt "#19507" msgid "Serious / Classical / Religious / Historical movie / drama" msgstr "" #. label for epg "movie/drama" subgenre value -#: xbmc/epg/Epg.cpp +#: xbmc/pvr/epg/Epg.cpp msgctxt "#19508" msgid "Adult movie / drama" msgstr "" @@ -10999,32 +10999,32 @@ msgstr "" #empty strings from id 19509 to 19515 #. label for "news/current affairs" epg genre value -#: xbmc/epg/Epg.cpp +#: xbmc/pvr/epg/Epg.cpp #: xbmc/pvr/dialogs/GUIDialogPVRGuideSearch.cpp msgctxt "#19516" msgid "News / Current affairs" msgstr "" #. label for "news/current affairs" epg subgenre value -#: xbmc/epg/Epg.cpp +#: xbmc/pvr/epg/Epg.cpp msgctxt "#19517" msgid "News / Weather report" msgstr "" #. label for "news/current affairs" epg subgenre value -#: xbmc/epg/Epg.cpp +#: xbmc/pvr/epg/Epg.cpp msgctxt "#19518" msgid "News magazine" msgstr "" #. label for "news/current affairs" epg subgenre value -#: xbmc/epg/Epg.cpp +#: xbmc/pvr/epg/Epg.cpp msgctxt "#19519" msgid "Documentary" msgstr "" #. label for "news/current affairs" epg subgenre value -#: xbmc/epg/Epg.cpp +#: xbmc/pvr/epg/Epg.cpp msgctxt "#19520" msgid "Discussion / Interview / Debate" msgstr "" @@ -11032,26 +11032,26 @@ msgstr "" #empty strings from id 19521 to 19531 #. label for "show/game show" epg subgenre value -#: xbmc/epg/Epg.cpp +#: xbmc/pvr/epg/Epg.cpp #: xbmc/pvr/dialogs/GUIDialogPVRGuideSearch.cpp msgctxt "#19532" msgid "Show / Game show" msgstr "" #. label for "show/game show" epg subgenre value -#: xbmc/epg/Epg.cpp +#: xbmc/pvr/epg/Epg.cpp msgctxt "#19533" msgid "Game show / Quiz / Contest" msgstr "" #. label for "show/game show" epg subgenre value -#: xbmc/epg/Epg.cpp +#: xbmc/pvr/epg/Epg.cpp msgctxt "#19534" msgid "Variety show" msgstr "" #. label for "show/game show" epg subgenre value -#: xbmc/epg/Epg.cpp +#: xbmc/pvr/epg/Epg.cpp msgctxt "#19535" msgid "Talk show" msgstr "" @@ -11059,74 +11059,74 @@ msgstr "" #empty strings from id 19536 to 19547 #. label for "sports" epg genre value -#: xbmc/epg/Epg.cpp +#: xbmc/pvr/epg/Epg.cpp #: xbmc/pvr/dialogs/GUIDialogPVRGuideSearch.cpp msgctxt "#19548" msgid "Sports" msgstr "" #. label for "sports" epg subgenre value -#: xbmc/epg/Epg.cpp +#: xbmc/pvr/epg/Epg.cpp msgctxt "#19549" msgid "Special event" msgstr "" #. label for "sports" epg subgenre value -#: xbmc/epg/Epg.cpp +#: xbmc/pvr/epg/Epg.cpp msgctxt "#19550" msgid "Sport magazine" msgstr "" #. label for "sports" epg subgenre value -#: xbmc/epg/Epg.cpp +#: xbmc/pvr/epg/Epg.cpp msgctxt "#19551" msgid "Football" msgstr "" #. label for "sports" epg subgenre value -#: xbmc/epg/Epg.cpp +#: xbmc/pvr/epg/Epg.cpp msgctxt "#19552" msgid "Tennis / Squash" msgstr "" #. label for "sports" epg subgenre value -#: xbmc/epg/Epg.cpp +#: xbmc/pvr/epg/Epg.cpp msgctxt "#19553" msgid "Team sports" msgstr "" #. label for "sports" epg subgenre value -#: xbmc/epg/Epg.cpp +#: xbmc/pvr/epg/Epg.cpp msgctxt "#19554" msgid "Athletics" msgstr "" #. label for "sports" epg subgenre value -#: xbmc/epg/Epg.cpp +#: xbmc/pvr/epg/Epg.cpp msgctxt "#19555" msgid "Motor sport" msgstr "" #. label for "sports" epg subgenre value -#: xbmc/epg/Epg.cpp +#: xbmc/pvr/epg/Epg.cpp msgctxt "#19556" msgid "Water sport" msgstr "" #. label for "sports" epg subgenre value -#: xbmc/epg/Epg.cpp +#: xbmc/pvr/epg/Epg.cpp msgctxt "#19557" msgid "Winter sports" msgstr "" #. label for "sports" epg subgenre value -#: xbmc/epg/Epg.cpp +#: xbmc/pvr/epg/Epg.cpp msgctxt "#19558" msgid "Equestrian" msgstr "" #. label for "sports" epg subgenre value -#: xbmc/epg/Epg.cpp +#: xbmc/pvr/epg/Epg.cpp msgctxt "#19559" msgid "Martial sports" msgstr "" @@ -11134,38 +11134,38 @@ msgstr "" #empty strings from id 19560 to 19563 #. label for "children's/youth programmes" epg genre value -#: xbmc/epg/Epg.cpp +#: xbmc/pvr/epg/Epg.cpp #: xbmc/pvr/dialogs/GUIDialogPVRGuideSearch.cpp msgctxt "#19564" msgid "Children's / Youth programmes" msgstr "" #. label for "children's/youth programmes" epg subgenre value -#: xbmc/epg/Epg.cpp +#: xbmc/pvr/epg/Epg.cpp msgctxt "#19565" msgid "Pre-school children's programmes" msgstr "" #. label for "children's/youth programmes" epg subgenre value -#: xbmc/epg/Epg.cpp +#: xbmc/pvr/epg/Epg.cpp msgctxt "#19566" msgid "Entertainment programmes for 6 to 14" msgstr "" #. label for "children's/youth programmes" epg subgenre value -#: xbmc/epg/Epg.cpp +#: xbmc/pvr/epg/Epg.cpp msgctxt "#19567" msgid "Entertainment programmes for 10 to 16" msgstr "" #. label for "children's/youth programmes" epg subgenre value -#: xbmc/epg/Epg.cpp +#: xbmc/pvr/epg/Epg.cpp msgctxt "#19568" msgid "Informational / Educational / School programme" msgstr "" #. label for "children's/youth programmes" epg subgenre value -#: xbmc/epg/Epg.cpp +#: xbmc/pvr/epg/Epg.cpp msgctxt "#19569" msgid "Cartoons / Puppets" msgstr "" @@ -11173,38 +11173,38 @@ msgstr "" #empty strings from id 19570 to 19579 #. label for "music/ballet/dance" epg genre value -#: xbmc/epg/Epg.cpp +#: xbmc/pvr/epg/Epg.cpp #: xbmc/pvr/dialogs/GUIDialogPVRGuideSearch.cpp msgctxt "#19580" msgid "Music / Ballet / Dance" msgstr "" #. label for "music/ballet/dance" epg subgenre value -#: xbmc/epg/Epg.cpp +#: xbmc/pvr/epg/Epg.cpp msgctxt "#19581" msgid "Rock / Pop" msgstr "" #. label for "music/ballet/dance" epg subgenre value -#: xbmc/epg/Epg.cpp +#: xbmc/pvr/epg/Epg.cpp msgctxt "#19582" msgid "Serious / Classical music" msgstr "" #. label for "music/ballet/dance" epg subgenre value -#: xbmc/epg/Epg.cpp +#: xbmc/pvr/epg/Epg.cpp msgctxt "#19583" msgid "Folk / Traditional music" msgstr "" #. label for "music/ballet/dance" epg subgenre value -#: xbmc/epg/Epg.cpp +#: xbmc/pvr/epg/Epg.cpp msgctxt "#19584" msgid "Musical / Opera" msgstr "" #. label for "music/ballet/dance" epg subgenre value -#: xbmc/epg/Epg.cpp +#: xbmc/pvr/epg/Epg.cpp msgctxt "#19585" msgid "Ballet" msgstr "" @@ -11212,74 +11212,74 @@ msgstr "" #empty strings from id 19586 to 19595 #. label for "arts/culture" epg genre value -#: xbmc/epg/Epg.cpp +#: xbmc/pvr/epg/Epg.cpp #: xbmc/pvr/dialogs/GUIDialogPVRGuideSearch.cpp msgctxt "#19596" msgid "Arts / Culture" msgstr "" #. label for "arts/culture" epg subgenre value -#: xbmc/epg/Epg.cpp +#: xbmc/pvr/epg/Epg.cpp msgctxt "#19597" msgid "Performing arts" msgstr "" #. label for "arts/culture" epg subgenre value -#: xbmc/epg/Epg.cpp +#: xbmc/pvr/epg/Epg.cpp msgctxt "#19598" msgid "Fine arts" msgstr "" #. label for "arts/culture" epg subgenre value -#: xbmc/epg/Epg.cpp +#: xbmc/pvr/epg/Epg.cpp msgctxt "#19599" msgid "Religion" msgstr "" #. label for "arts/culture" epg subgenre value -#: xbmc/epg/Epg.cpp +#: xbmc/pvr/epg/Epg.cpp msgctxt "#19600" msgid "Popular culture / Traditional arts" msgstr "" #. label for "arts/culture" epg subgenre value -#: xbmc/epg/Epg.cpp +#: xbmc/pvr/epg/Epg.cpp msgctxt "#19601" msgid "Literature" msgstr "" #. label for "arts/culture" epg subgenre value -#: xbmc/epg/Epg.cpp +#: xbmc/pvr/epg/Epg.cpp msgctxt "#19602" msgid "Film / Cinema" msgstr "" #. label for "arts/culture" epg subgenre value -#: xbmc/epg/Epg.cpp +#: xbmc/pvr/epg/Epg.cpp msgctxt "#19603" msgid "Experimental film / video" msgstr "" #. label for "arts/culture" epg subgenre value -#: xbmc/epg/Epg.cpp +#: xbmc/pvr/epg/Epg.cpp msgctxt "#19604" msgid "Broadcasting / Press" msgstr "" #. label for "arts/culture" epg subgenre value -#: xbmc/epg/Epg.cpp +#: xbmc/pvr/epg/Epg.cpp msgctxt "#19605" msgid "New media" msgstr "" #. label for "arts/culture" epg subgenre value -#: xbmc/epg/Epg.cpp +#: xbmc/pvr/epg/Epg.cpp msgctxt "#19606" msgid "Arts / Culture magazines" msgstr "" #. label for "arts/culture" epg subgenre value -#: xbmc/epg/Epg.cpp +#: xbmc/pvr/epg/Epg.cpp msgctxt "#19607" msgid "Fashion" msgstr "" @@ -11287,26 +11287,26 @@ msgstr "" #empty strings from id 19608 to 19611 #. label for "social/political/economics" epg genre value -#: xbmc/epg/Epg.cpp +#: xbmc/pvr/epg/Epg.cpp #: xbmc/pvr/dialogs/GUIDialogPVRGuideSearch.cpp msgctxt "#19612" msgid "Social / Political / Economics" msgstr "" #. label for "social/political/economics" epg subgenre value -#: xbmc/epg/Epg.cpp +#: xbmc/pvr/epg/Epg.cpp msgctxt "#19613" msgid "Magazines / Reports / Documentary" msgstr "" #. label for "social/political/economics" epg subgenre value -#: xbmc/epg/Epg.cpp +#: xbmc/pvr/epg/Epg.cpp msgctxt "#19614" msgid "Economics / Social advisory" msgstr "" #. label for "social/political/economics" epg subgenre value -#: xbmc/epg/Epg.cpp +#: xbmc/pvr/epg/Epg.cpp msgctxt "#19615" msgid "Remarkable people" msgstr "" @@ -11314,50 +11314,50 @@ msgstr "" #empty strings from id 19616 to 19627 #. label for "education/science/factual" epg genre value -#: xbmc/epg/Epg.cpp +#: xbmc/pvr/epg/Epg.cpp #: xbmc/pvr/dialogs/GUIDialogPVRGuideSearch.cpp msgctxt "#19628" msgid "Education / Science / Factual" msgstr "" #. label for "education/science/factual" epg subgenre value -#: xbmc/epg/Epg.cpp +#: xbmc/pvr/epg/Epg.cpp msgctxt "#19629" msgid "Nature / Animals / Environment" msgstr "" #. label for "education/science/factual" epg subgenre value -#: xbmc/epg/Epg.cpp +#: xbmc/pvr/epg/Epg.cpp msgctxt "#19630" msgid "Technology / Natural sciences" msgstr "" #. label for "education/science/factual" epg subgenre value -#: xbmc/epg/Epg.cpp +#: xbmc/pvr/epg/Epg.cpp msgctxt "#19631" msgid "Medicine / Physiology / Psychology" msgstr "" #. label for "education/science/factual" epg subgenre value -#: xbmc/epg/Epg.cpp +#: xbmc/pvr/epg/Epg.cpp msgctxt "#19632" msgid "Foreign countries / Expeditions" msgstr "" #. label for "education/science/factual" epg subgenre value -#: xbmc/epg/Epg.cpp +#: xbmc/pvr/epg/Epg.cpp msgctxt "#19633" msgid "Social / Spiritual sciences" msgstr "" #. label for "education/science/factual" epg subgenre value -#: xbmc/epg/Epg.cpp +#: xbmc/pvr/epg/Epg.cpp msgctxt "#19634" msgid "Further education" msgstr "" #. label for "education/science/factual" epg subgenre value -#: xbmc/epg/Epg.cpp +#: xbmc/pvr/epg/Epg.cpp msgctxt "#19635" msgid "Languages" msgstr "" @@ -11365,50 +11365,50 @@ msgstr "" #empty strings from id 19636 to 19643 #. label for "leisure/hobbies" epg genre value -#: xbmc/epg/Epg.cpp +#: xbmc/pvr/epg/Epg.cpp #: xbmc/pvr/dialogs/GUIDialogPVRGuideSearch.cpp msgctxt "#19644" msgid "Leisure / Hobbies" msgstr "" #. label for "leisure/hobbies" epg subgenre value -#: xbmc/epg/Epg.cpp +#: xbmc/pvr/epg/Epg.cpp msgctxt "#19645" msgid "Tourism / Travel" msgstr "" #. label for "leisure/hobbies" epg subgenre value -#: xbmc/epg/Epg.cpp +#: xbmc/pvr/epg/Epg.cpp msgctxt "#19646" msgid "Handicraft" msgstr "" #. label for "leisure/hobbies" epg subgenre value -#: xbmc/epg/Epg.cpp +#: xbmc/pvr/epg/Epg.cpp msgctxt "#19647" msgid "Motoring" msgstr "" #. label for "leisure/hobbies" epg subgenre value -#: xbmc/epg/Epg.cpp +#: xbmc/pvr/epg/Epg.cpp msgctxt "#19648" msgid "Fitness & health" msgstr "" #. label for "leisure/hobbies" epg subgenre value -#: xbmc/epg/Epg.cpp +#: xbmc/pvr/epg/Epg.cpp msgctxt "#19649" msgid "Cooking" msgstr "" #. label for "leisure/hobbies" epg subgenre value -#: xbmc/epg/Epg.cpp +#: xbmc/pvr/epg/Epg.cpp msgctxt "#19650" msgid "Advertisement / Shopping" msgstr "" #. label for "leisure/hobbies" epg subgenre value -#: xbmc/epg/Epg.cpp +#: xbmc/pvr/epg/Epg.cpp msgctxt "#19651" msgid "Gardening" msgstr "" @@ -11416,32 +11416,32 @@ msgstr "" #empty strings from id 19652 to 19659 #. label for "special characteristics" epg genre value -#: xbmc/epg/Epg.cpp +#: xbmc/pvr/epg/Epg.cpp #: xbmc/pvr/dialogs/GUIDialogPVRGuideSearch.cpp msgctxt "#19660" msgid "Special characteristics" msgstr "" #. label for "special characteristics" epg subgenre value -#: xbmc/epg/Epg.cpp +#: xbmc/pvr/epg/Epg.cpp msgctxt "#19661" msgid "Original language" msgstr "" #. label for "special characteristics" epg subgenre value -#: xbmc/epg/Epg.cpp +#: xbmc/pvr/epg/Epg.cpp msgctxt "#19662" msgid "Black & white" msgstr "" #. label for "special characteristics" epg subgenre value -#: xbmc/epg/Epg.cpp +#: xbmc/pvr/epg/Epg.cpp msgctxt "#19663" msgid "Unpublished" msgstr "" #. label for "special characteristics" epg subgenre value -#: xbmc/epg/Epg.cpp +#: xbmc/pvr/epg/Epg.cpp msgctxt "#19664" msgid "Live broadcast" msgstr "" @@ -11449,55 +11449,55 @@ msgstr "" #empty strings from id 19665 to 19675 #. label for "user defined" epg subgenre value -#: xbmc/epg/Epg.cpp +#: xbmc/pvr/epg/Epg.cpp msgctxt "#19676" msgid "Drama" msgstr "" #. label for "user defined" epg subgenre value -#: xbmc/epg/Epg.cpp +#: xbmc/pvr/epg/Epg.cpp msgctxt "#19677" msgid "Detective / Thriller" msgstr "" #. label for "user defined" epg subgenre value -#: xbmc/epg/Epg.cpp +#: xbmc/pvr/epg/Epg.cpp msgctxt "#19678" msgid "Adventure / Western / War" msgstr "" #. label for "user defined" epg subgenre value -#: xbmc/epg/Epg.cpp +#: xbmc/pvr/epg/Epg.cpp msgctxt "#19679" msgid "Science fiction / Fantasy / Horror" msgstr "" #. label for "user defined" epg subgenre value -#: xbmc/epg/Epg.cpp +#: xbmc/pvr/epg/Epg.cpp msgctxt "#19680" msgid "Comedy" msgstr "" #. label for "user defined" epg subgenre value -#: xbmc/epg/Epg.cpp +#: xbmc/pvr/epg/Epg.cpp msgctxt "#19681" msgid "Soap / Melodrama / Folkloric" msgstr "" #. label for "user defined" epg subgenre value -#: xbmc/epg/Epg.cpp +#: xbmc/pvr/epg/Epg.cpp msgctxt "#19682" msgid "Romance" msgstr "" #. label for "user defined" epg subgenre value -#: xbmc/epg/Epg.cpp +#: xbmc/pvr/epg/Epg.cpp msgctxt "#19683" msgid "Serious / Classical / Religion / Historical" msgstr "" #. label for "user defined" epg subgenre value -#: xbmc/epg/Epg.cpp +#: xbmc/pvr/epg/Epg.cpp msgctxt "#19684" msgid "Adult" msgstr "" diff --git a/xbmc/FileItem.cpp b/xbmc/FileItem.cpp index f184899b37..791a1d7079 100644 --- a/xbmc/FileItem.cpp +++ b/xbmc/FileItem.cpp @@ -32,6 +32,8 @@ #include "CueDocument.h" #include "video/VideoDatabase.h" #include "music/MusicDatabase.h" +#include "pvr/PVRManager.h" +#include "pvr/channels/PVRChannelGroupsContainer.h" #include "pvr/channels/PVRChannel.h" #include "pvr/epg/Epg.h" #include "pvr/recordings/PVRRecording.h" @@ -112,6 +114,20 @@ CFileItem::CFileItem(const CVideoInfoTag& movie) SetFromVideoInfoTag(movie); } +namespace +{ + std::string GetEpgTagTitle(const std::shared_ptr& epgTag) + { + if (CServiceBroker::GetPVRManager().IsParentalLocked(epgTag)) + return g_localizeStrings.Get(19266); // Parental locked + else if (epgTag->Title().empty() && + !CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool(CSettings::SETTING_EPG_HIDENOINFOAVAILABLE)) + return g_localizeStrings.Get(19055); // no information available + else + return epgTag->Title(); + } +} // unnamed namespace + void CFileItem::FillMusicInfoTag(const CPVRChannelPtr& channel, const CPVREpgInfoTagPtr& tag) { if (channel && channel->IsRadio() && !HasMusicInfoTag()) @@ -120,7 +136,7 @@ void CFileItem::FillMusicInfoTag(const CPVRChannelPtr& channel, const CPVREpgInf if (tag) { - musictag->SetTitle(tag->Title()); + musictag->SetTitle(GetEpgTagTitle(tag)); musictag->SetGenre(tag->Genre()); musictag->SetDuration(tag->GetDuration()); } @@ -144,15 +160,23 @@ CFileItem::CFileItem(const CPVREpgInfoTagPtr& tag) m_bIsFolder = false; m_epgInfoTag = tag; m_strPath = tag->Path(); - SetLabel(tag->Title()); + SetLabel(GetEpgTagTitle(tag)); m_dateTime = tag->StartAsLocalTime(); if (!tag->Icon().empty()) SetIconImage(tag->Icon()); - else if (tag->HasChannel() && !tag->Channel()->IconPath().empty()) - SetIconImage(tag->Channel()->IconPath()); + else + { + const std::shared_ptr channel = CServiceBroker::GetPVRManager().ChannelGroups()->GetChannelForEpgTag(tag); + if (channel) + { + if (!channel->IconPath().empty()) + SetIconImage(channel->IconPath()); + + FillMusicInfoTag(channel, tag); + } + } - FillMusicInfoTag(tag->Channel(), tag); FillInMimeType(false); } @@ -3597,7 +3621,7 @@ CFileItem CFileItem::GetItemToPlay() const { if (HasEPGInfoTag()) { - const CPVRChannelPtr channel(GetEPGInfoTag()->Channel()); + const std::shared_ptr channel = CServiceBroker::GetPVRManager().ChannelGroups()->GetChannelForEpgTag(GetEPGInfoTag()); if (channel) return CFileItem(channel); } diff --git a/xbmc/addons/PVRClient.cpp b/xbmc/addons/PVRClient.cpp index c5b3fae92e..157440fe8b 100644 --- a/xbmc/addons/PVRClient.cpp +++ b/xbmc/addons/PVRClient.cpp @@ -35,6 +35,7 @@ extern "C" { #include "pvr/channels/PVRChannelGroupInternal.h" #include "pvr/channels/PVRChannelGroupsContainer.h" #include "pvr/epg/Epg.h" +#include "pvr/epg/EpgChannelData.h" #include "pvr/epg/EpgContainer.h" #include "pvr/epg/EpgInfoTag.h" #include "pvr/recordings/PVRRecordings.h" @@ -609,11 +610,25 @@ PVR_ERROR CPVRClient::RenameChannel(const CPVRChannelPtr &channel) }, m_clientCapabilities.SupportsChannelSettings()); } -PVR_ERROR CPVRClient::GetEPGForChannel(const CPVRChannelPtr &channel, CPVREpg *epg, time_t start /* = 0 */, time_t end /* = 0 */, bool bSaveInDb /* = false*/) +PVR_ERROR CPVRClient::GetEPGForChannel(const std::shared_ptr& channelData, + CPVREpg* epg, + time_t start /* = 0 */, + time_t end /* = 0 */, + bool bSaveInDb /* = false */) { - return DoAddonCall(__FUNCTION__, [this, channel, epg, start, end, bSaveInDb](const AddonInstance* addon) { - PVR_CHANNEL addonChannel; - WriteClientChannelInfo(channel, addonChannel); + return DoAddonCall(__FUNCTION__, [this, channelData, epg, start, end, bSaveInDb](const AddonInstance* addon) { + + //! @todo PVR Addon API Change: Change GetEPGForChannel param from 'PVR_CHANNEL channel' to 'int iUniqueId'. + PVR_CHANNEL addonChannel = {0}; + + // mandatory + addonChannel.iUniqueId = channelData->UniqueClientChannelId(); + addonChannel.bIsRadio = channelData->IsRadio(); + + // optional + strncpy(addonChannel.strChannelName, channelData->ChannelName().c_str(), sizeof(addonChannel.strChannelName) - 1); + strncpy(addonChannel.strIconPath, channelData->IconPath().c_str(), sizeof(addonChannel.strIconPath) - 1); + addonChannel.bIsHidden = channelData->IsHidden(); ADDON_HANDLE_STRUCT handle; handle.callerAddress = this; @@ -647,15 +662,15 @@ class CAddonEpgTag : public EPG_TAG public: CAddonEpgTag() = delete; explicit CAddonEpgTag(const CConstPVREpgInfoTagPtr kodiTag) : - m_strTitle(kodiTag->Title(true)), - m_strPlotOutline(kodiTag->PlotOutline(true)), - m_strPlot(kodiTag->Plot(true)), - m_strOriginalTitle(kodiTag->OriginalTitle(true)), + m_strTitle(kodiTag->Title()), + m_strPlotOutline(kodiTag->PlotOutline()), + m_strPlot(kodiTag->Plot()), + m_strOriginalTitle(kodiTag->OriginalTitle()), m_strCast(kodiTag->DeTokenize(kodiTag->Cast())), m_strDirector(kodiTag->DeTokenize(kodiTag->Directors())), m_strWriter(kodiTag->DeTokenize(kodiTag->Writers())), m_strIMDBNumber(kodiTag->IMDBNumber()), - m_strEpisodeName(kodiTag->EpisodeName(true)), + m_strEpisodeName(kodiTag->EpisodeName()), m_strIconPath(kodiTag->Icon()), m_strSeriesLink(kodiTag->SeriesLink()), m_strGenreDescription(kodiTag->GetGenresLabel()) @@ -1664,7 +1679,6 @@ void CPVRClient::cb_trigger_channel_groups_update(void *kodiInstance) void CPVRClient::cb_trigger_epg_update(void *kodiInstance, unsigned int iChannelUid) { - // get the client CPVRClient *client = static_cast(kodiInstance); if (!client) { @@ -1718,7 +1732,9 @@ void CPVRClient::cb_epg_event_state_change(void* kodiInstance, EPG_TAG* tag, EPG return; } - CServiceBroker::GetPVRManager().EpgContainer().UpdateFromClient(std::make_shared(*tag, client->GetID()), newState); + // Note: channel data and epg id may not yet be available. Tag will be fully initialized later. + const std::shared_ptr epgTag = std::make_shared(*tag, client->GetID(), nullptr, -1); + CServiceBroker::GetPVRManager().EpgContainer().UpdateFromClient(epgTag, newState); } class CCodecIds diff --git a/xbmc/addons/PVRClient.h b/xbmc/addons/PVRClient.h index e88362618e..604ad2b166 100644 --- a/xbmc/addons/PVRClient.h +++ b/xbmc/addons/PVRClient.h @@ -22,6 +22,7 @@ namespace PVR { class CPVRChannelGroups; + class CPVREpgChannelData; class CPVRTimersContainer; class CPVRClientMenuHook; class CPVRClientMenuHooks; @@ -400,14 +401,14 @@ namespace PVR /*! * @brief Request an EPG table for a channel from the client. - * @param channel The channel to get the EPG table for. + * @param channelData The data for the channel to get the EPG table for. * @param epg The table to write the data to. * @param start The start time to use. * @param end The end time to use. * @param bSaveInDb If true, tell the callback method to save any new entry in the database or not. see CAddonCallbacksPVR::PVRTransferEpgEntry() * @return PVR_ERROR_NO_ERROR if the table has been fetched successfully. */ - PVR_ERROR GetEPGForChannel(const CPVRChannelPtr &channel, CPVREpg *epg, time_t start = 0, time_t end = 0, bool bSaveInDb = false); + PVR_ERROR GetEPGForChannel(const std::shared_ptr& channelData, CPVREpg* epg, time_t start = 0, time_t end = 0, bool bSaveInDb = false); /*! * Tell the client the time frame to use when notifying epg events back to Kodi. The client might push epg events asynchronously diff --git a/xbmc/cores/VideoPlayer/Edl.cpp b/xbmc/cores/VideoPlayer/Edl.cpp index 09023321c9..039614edc7 100644 --- a/xbmc/cores/VideoPlayer/Edl.cpp +++ b/xbmc/cores/VideoPlayer/Edl.cpp @@ -575,7 +575,7 @@ bool CEdl::ReadPvr(const CFileItem &fileItem) } else if (fileItem.HasEPGInfoTag()) { - CLog::Log(LOGDEBUG, "%s - Reading Edl for EPG: %s", __FUNCTION__, fileItem.GetEPGInfoTag()->Title(true).c_str()); + CLog::Log(LOGDEBUG, "%s - Reading Edl for EPG: %s", __FUNCTION__, fileItem.GetEPGInfoTag()->Title().c_str()); edl = fileItem.GetEPGInfoTag()->GetEdl(); } else diff --git a/xbmc/interfaces/json-rpc/PVROperations.cpp b/xbmc/interfaces/json-rpc/PVROperations.cpp index afd05aeb62..5262f98cfa 100644 --- a/xbmc/interfaces/json-rpc/PVROperations.cpp +++ b/xbmc/interfaces/json-rpc/PVROperations.cpp @@ -169,7 +169,8 @@ JSONRPC_STATUS CPVROperations::GetBroadcastDetails(const std::string &method, IT if (!CServiceBroker::GetPVRManager().IsStarted()) return FailedToExecute; - const CPVREpgInfoTagPtr epgTag = CServiceBroker::GetPVRManager().EpgContainer().GetTagById(CPVRChannelPtr(), parameterObject["broadcastid"].asUnsignedInteger()); + const std::shared_ptr epgTag = CServiceBroker::GetPVRManager().EpgContainer().GetTagById(std::shared_ptr(), + parameterObject["broadcastid"].asUnsignedInteger()); if (!epgTag) return InvalidParams; @@ -321,7 +322,8 @@ JSONRPC_STATUS CPVROperations::AddTimer(const std::string &method, ITransportLay if (!CServiceBroker::GetPVRManager().IsStarted()) return FailedToExecute; - const CPVREpgInfoTagPtr epgTag = CServiceBroker::GetPVRManager().EpgContainer().GetTagById(CPVRChannelPtr(), parameterObject["broadcastid"].asUnsignedInteger()); + const std::shared_ptr epgTag = CServiceBroker::GetPVRManager().EpgContainer().GetTagById(std::shared_ptr(), + parameterObject["broadcastid"].asUnsignedInteger()); if (!epgTag) return InvalidParams; @@ -363,7 +365,8 @@ JSONRPC_STATUS CPVROperations::ToggleTimer(const std::string &method, ITransport if (!CServiceBroker::GetPVRManager().IsStarted()) return FailedToExecute; - const CPVREpgInfoTagPtr epgTag = CServiceBroker::GetPVRManager().EpgContainer().GetTagById(CPVRChannelPtr(), parameterObject["broadcastid"].asUnsignedInteger()); + const std::shared_ptr epgTag = CServiceBroker::GetPVRManager().EpgContainer().GetTagById(std::shared_ptr(), + parameterObject["broadcastid"].asUnsignedInteger()); if (!epgTag) return InvalidParams; diff --git a/xbmc/pvr/PVRContextMenus.cpp b/xbmc/pvr/PVRContextMenus.cpp index f819dc8d3e..2126b26a6e 100644 --- a/xbmc/pvr/PVRContextMenus.cpp +++ b/xbmc/pvr/PVRContextMenus.cpp @@ -221,7 +221,6 @@ namespace PVR const CPVREpgInfoTagPtr epg = item.GetEPGInfoTag(); if (epg && !CServiceBroker::GetPVRManager().Timers()->GetTimerForEpgTag(epg) && - epg->Channel() && epg->IsRecordable()) return client && client->GetClientCapabilities().SupportsTimers(); @@ -380,9 +379,7 @@ namespace PVR bool AddTimerRule::IsVisible(const CFileItem &item) const { const CPVREpgInfoTagPtr epg = item.GetEPGInfoTag(); - if (epg && - epg->Channel() && - !CServiceBroker::GetPVRManager().Timers()->GetTimerForEpgTag(epg)) + if (epg && !CServiceBroker::GetPVRManager().Timers()->GetTimerForEpgTag(epg)) { const CPVRClientPtr client = CServiceBroker::GetPVRManager().GetClient(item); return client && client->GetClientCapabilities().SupportsTimers(); diff --git a/xbmc/pvr/PVRGUIActions.cpp b/xbmc/pvr/PVRGUIActions.cpp index acb06a5e77..8882f06e8b 100644 --- a/xbmc/pvr/PVRGUIActions.cpp +++ b/xbmc/pvr/PVRGUIActions.cpp @@ -537,15 +537,19 @@ namespace PVR epgTag = channel->GetEPGNow(); if (epgTag) { + bool bLocked = CServiceBroker::GetPVRManager().IsParentalLocked(epgTag); + // "now" - selector.AddAction(RECORD_CURRENT_SHOW, epgTag->Title()); + const std::string currentTitle = bLocked ? g_localizeStrings.Get(19266) /* Parental locked */ : epgTag->Title(); + selector.AddAction(RECORD_CURRENT_SHOW, currentTitle); ePreselect = RECORD_CURRENT_SHOW; // "next" epgTagNext = channel->GetEPGNext(); if (epgTagNext) { - selector.AddAction(RECORD_NEXT_SHOW, epgTagNext->Title()); + const std::string nextTitle = bLocked ? g_localizeStrings.Get(19266) /* Parental locked */ : epgTagNext->Title(); + selector.AddAction(RECORD_NEXT_SHOW, nextTitle); // be smart. if current show is almost over, preselect next show. if (epgTag->ProgressPercentage() > 90.0f) diff --git a/xbmc/pvr/PVRGUIInfo.cpp b/xbmc/pvr/PVRGUIInfo.cpp index bd0863c122..17c3dc86e1 100644 --- a/xbmc/pvr/PVRGUIInfo.cpp +++ b/xbmc/pvr/PVRGUIInfo.cpp @@ -468,7 +468,10 @@ bool CPVRGUIInfo::GetListItemAndPlayerLabel(const CFileItem *item, const CGUIInf // Note: in difference to LISTITEM_TITLE, LISTITEM_EPG_EVENT_TITLE returns the title // associated with the epg event of a timer, if any, and not the title of the timer. if (epgTag) - strValue = epgTag->Title(); + { + bool bLocked = CServiceBroker::GetPVRManager().IsParentalLocked(epgTag); + strValue = bLocked ? g_localizeStrings.Get(19266) /* Parental locked */ : epgTag->Title(); + } if (strValue.empty() && !CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool(CSettings::SETTING_EPG_HIDENOINFOAVAILABLE)) strValue = g_localizeStrings.Get(19055); // no information available return true; @@ -489,13 +492,15 @@ bool CPVRGUIInfo::GetListItemAndPlayerLabel(const CFileItem *item, const CGUIInf case LISTITEM_PLOT: case VIDEOPLAYER_NEXT_PLOT: case LISTITEM_NEXT_PLOT: - strValue = epgTag->Plot(); + if (!CServiceBroker::GetPVRManager().IsParentalLocked(epgTag)) + strValue = epgTag->Plot(); return true; case VIDEOPLAYER_PLOT_OUTLINE: case LISTITEM_PLOT_OUTLINE: case VIDEOPLAYER_NEXT_PLOT_OUTLINE: case LISTITEM_NEXT_PLOT_OUTLINE: - strValue = epgTag->PlotOutline(); + if (!CServiceBroker::GetPVRManager().IsParentalLocked(epgTag)) + strValue = epgTag->PlotOutline(); return true; case LISTITEM_DATE: strValue = GetAsLocalizedDateTimeString(epgTag->StartAsLocalTime()); @@ -536,7 +541,8 @@ bool CPVRGUIInfo::GetListItemAndPlayerLabel(const CFileItem *item, const CGUIInf return true; case VIDEOPLAYER_ORIGINALTITLE: case LISTITEM_ORIGINALTITLE: - strValue = epgTag->OriginalTitle(); + if (!CServiceBroker::GetPVRManager().IsParentalLocked(epgTag)) + strValue = epgTag->OriginalTitle(); return true; case VIDEOPLAYER_YEAR: case LISTITEM_YEAR: @@ -567,7 +573,8 @@ bool CPVRGUIInfo::GetListItemAndPlayerLabel(const CFileItem *item, const CGUIInf return false; case VIDEOPLAYER_EPISODENAME: case LISTITEM_EPISODENAME: - strValue = epgTag->EpisodeName(); + if (!CServiceBroker::GetPVRManager().IsParentalLocked(epgTag)) + strValue = epgTag->EpisodeName(); return true; case VIDEOPLAYER_CAST: case LISTITEM_CAST: @@ -1225,8 +1232,9 @@ bool CPVRGUIInfo::GetListItemAndPlayerBool(const CFileItem *item, const CGUIInfo if (item->IsPVRRecording()) { const CPVRRecordingPtr recording = item->GetPVRRecordingInfoTag(); - const CPVREpgInfoTagPtr epgTag = CServiceBroker::GetPVRManager().EpgContainer().GetTagById(recording->Channel(), recording->BroadcastUid()); - bValue = (epgTag && epgTag->IsActive() && epgTag->Channel()); + const std::shared_ptr epg = recording->Channel() ? recording->Channel()->GetEPG() : nullptr; + const std::shared_ptr epgTag = CServiceBroker::GetPVRManager().EpgContainer().GetTagById(epg, recording->BroadcastUid()); + bValue = (epgTag && epgTag->IsActive()); return true; } break; diff --git a/xbmc/pvr/PVRGUITimesInfo.cpp b/xbmc/pvr/PVRGUITimesInfo.cpp index 365458164c..41f73971eb 100644 --- a/xbmc/pvr/PVRGUITimesInfo.cpp +++ b/xbmc/pvr/PVRGUITimesInfo.cpp @@ -19,6 +19,7 @@ #include "utils/StringUtils.h" #include "pvr/PVRManager.h" +#include "pvr/channels/PVRChannelGroupsContainer.h" using namespace PVR; @@ -56,9 +57,11 @@ void CPVRGUITimesInfo::UpdatePlayingTag() if (currentChannel && !currentTag) currentTag = currentChannel->GetEPGNow(); + const std::shared_ptr groups = CServiceBroker::GetPVRManager().ChannelGroups(); + CSingleLock lock(m_critSection); - const CPVRChannelPtr playingChannel = m_playingEpgTag ? m_playingEpgTag->Channel() : nullptr; + const std::shared_ptr playingChannel = m_playingEpgTag ? groups->GetChannelForEpgTag(m_playingEpgTag) : nullptr; if (!m_playingEpgTag || !m_playingEpgTag->IsActive() || !playingChannel || !currentChannel || *playingChannel != *currentChannel) { diff --git a/xbmc/pvr/PVRItem.cpp b/xbmc/pvr/PVRItem.cpp index 2dcd48208b..1f51ed6693 100644 --- a/xbmc/pvr/PVRItem.cpp +++ b/xbmc/pvr/PVRItem.cpp @@ -14,6 +14,7 @@ #include "pvr/PVRManager.h" #include "pvr/channels/PVRChannel.h" +#include "pvr/channels/PVRChannelGroupsContainer.h" #include "pvr/epg/EpgInfoTag.h" #include "pvr/recordings/PVRRecording.h" #include "pvr/recordings/PVRRecordings.h" @@ -47,7 +48,7 @@ namespace PVR { if (m_item->IsEPG()) { - const CPVRChannelPtr channel = m_item->GetEPGInfoTag()->Channel(); + const std::shared_ptr channel = CServiceBroker::GetPVRManager().ChannelGroups()->GetChannelForEpgTag(m_item->GetEPGInfoTag()); if (channel) return channel->GetEPGNext(); } @@ -76,7 +77,7 @@ namespace PVR } else if (m_item->IsEPG()) { - return m_item->GetEPGInfoTag()->Channel(); + return CServiceBroker::GetPVRManager().ChannelGroups()->GetChannelForEpgTag(m_item->GetEPGInfoTag()); } else if (m_item->IsPVRTimer()) { @@ -135,8 +136,7 @@ namespace PVR } else if (m_item->IsEPG()) { - const CPVRChannelPtr channel(m_item->GetEPGInfoTag()->Channel()); - return (channel && channel->IsRadio()); + return m_item->GetEPGInfoTag()->IsRadio(); } else if (m_item->IsPVRRecording()) { diff --git a/xbmc/pvr/PVRManager.cpp b/xbmc/pvr/PVRManager.cpp index 42a394d41b..a21fbf5da9 100644 --- a/xbmc/pvr/PVRManager.cpp +++ b/xbmc/pvr/PVRManager.cpp @@ -650,6 +650,14 @@ bool CPVRManager::IsPlayingEpgTag(const CPVREpgInfoTagPtr &epgTag) const return bReturn; } +bool CPVRManager::MatchPlayingChannel(int iClientID, int iUniqueChannelID) const +{ + if (m_playingChannel) + return m_playingChannel->ClientID() == iClientID && m_playingChannel->UniqueID() == iUniqueChannelID; + + return false; +} + CPVRChannelPtr CPVRManager::GetPlayingChannel(void) const { return m_playingChannel; @@ -693,19 +701,33 @@ void CPVRManager::RestartParentalTimer() m_parentalTimer->StartZero(); } -bool CPVRManager::IsParentalLocked(const CPVRChannelPtr &channel) +bool CPVRManager::IsParentalLocked(const std::shared_ptr& epgTag) const { - bool bReturn(false); - if (!IsStarted()) + return m_channelGroups && + epgTag && + IsCurrentlyParentalLocked(m_channelGroups->GetByUniqueID(epgTag->UniqueChannelID(), epgTag->ClientID()), + epgTag->IsParentalLocked()); +} + +bool CPVRManager::IsParentalLocked(const std::shared_ptr& channel) const +{ + return channel && + IsCurrentlyParentalLocked(channel, channel->IsLocked()); +} + +bool CPVRManager::IsCurrentlyParentalLocked(const std::shared_ptr& channel, bool bGenerallyLocked) const +{ + bool bReturn = false; + + if (!channel || !bGenerallyLocked) return bReturn; - CPVRChannelPtr currentChannel(GetPlayingChannel()); - if (// different channel + const std::shared_ptr currentChannel = GetPlayingChannel(); + + if (// if channel in question is currently playing it must be currently unlocked. (!currentChannel || channel != currentChannel) && // parental control enabled - m_settings.GetBoolValue(CSettings::SETTING_PVRPARENTAL_ENABLED) && - // channel is locked - channel && channel->IsLocked()) + m_settings.GetBoolValue(CSettings::SETTING_PVRPARENTAL_ENABLED)) { float parentalDurationMs = m_settings.GetIntValue(CSettings::SETTING_PVRPARENTAL_DURATION) * 1000.0f; bReturn = m_parentalTimer && diff --git a/xbmc/pvr/PVRManager.h b/xbmc/pvr/PVRManager.h index bbb9673b1f..76a2290b1e 100644 --- a/xbmc/pvr/PVRManager.h +++ b/xbmc/pvr/PVRManager.h @@ -239,6 +239,14 @@ namespace PVR return GetState() == ManagerStateStopped; } + /*! + * @brief Check whether playing channel matches given uids. + * @param iClientID The client id. + * @param iUniqueChannelID The channel uid. + * @return True on match, false if there is no match or no channel is playing. + */ + bool MatchPlayingChannel(int iClientID, int iUniqueChannelID) const; + /*! * @brief Return the channel that is currently playing. * @return The channel or NULL if none is playing. @@ -403,10 +411,17 @@ namespace PVR /*! * @brief Check if parental lock is overridden at the given moment. - * @param channel The channel to open. + * @param channel The channel to check. + * @return True if parental lock is overridden, false otherwise. + */ + bool IsParentalLocked(const std::shared_ptr& channel) const; + + /*! + * @brief Check if parental lock is overridden at the given moment. + * @param epgTag The epg tag to check. * @return True if parental lock is overridden, false otherwise. */ - bool IsParentalLocked(const CPVRChannelPtr &channel); + bool IsParentalLocked(const std::shared_ptr& epgTag) const; /*! * @brief Restart the parental timer. @@ -509,6 +524,8 @@ namespace PVR */ void SetState(ManagerState state); + bool IsCurrentlyParentalLocked(const std::shared_ptr& channel, bool bGenerallyLocked) const; + /** @name containers */ //@{ CPVRChannelGroupsContainerPtr m_channelGroups; /*!< pointer to the channel groups container */ diff --git a/xbmc/pvr/channels/PVRChannel.cpp b/xbmc/pvr/channels/PVRChannel.cpp index a9bafe39b8..620f8cfcb3 100644 --- a/xbmc/pvr/channels/PVRChannel.cpp +++ b/xbmc/pvr/channels/PVRChannel.cpp @@ -20,6 +20,7 @@ #include "pvr/PVRDatabase.h" #include "pvr/PVRManager.h" #include "pvr/channels/PVRChannelGroupInternal.h" +#include "pvr/epg/EpgChannelData.h" #include "pvr/epg/EpgContainer.h" #include "pvr/timers/PVRTimers.h" @@ -130,7 +131,6 @@ bool CPVRChannel::Delete(void) const CPVREpgPtr epg = GetEPG(); if (epg) { - epg->SetChannel(CPVRChannelPtr()); CServiceBroker::GetPVRManager().EpgContainer().DeleteEpg(epg, true); CSingleLock lock(m_critSection); @@ -158,7 +158,9 @@ bool CPVRChannel::CreateEPG(bool bForce) CSingleLock lock(m_critSection); if (!m_bEPGCreated || bForce) { - const CPVREpgPtr epg = CServiceBroker::GetPVRManager().EpgContainer().CreateChannelEpg(shared_from_this()); + const CPVREpgPtr epg = CServiceBroker::GetPVRManager().EpgContainer().CreateChannelEpg(m_iEpgId, + m_strEPGScraper, + std::make_shared(*this)); if (epg) { m_bEPGCreated = true; @@ -167,6 +169,7 @@ bool CPVRChannel::CreateEPG(bool bForce) m_iEpgId = epg->EpgID(); m_bChanged = true; } + return true; } } @@ -230,6 +233,11 @@ bool CPVRChannel::SetChannelID(int iChannelId) if (m_iChannelId != iChannelId) { m_iChannelId = iChannelId; + + const std::shared_ptr epg = GetEPG(); + if (epg) + epg->GetChannelData()->SetChannelId(m_iChannelId); + SetChanged(); m_bChanged = true; return true; @@ -252,6 +260,14 @@ bool CPVRChannel::SetHidden(bool bIsHidden) { m_bIsHidden = bIsHidden; m_bEPGEnabled = !bIsHidden; + + const std::shared_ptr epg = GetEPG(); + if (epg) + { + epg->GetChannelData()->SetHidden(m_bIsHidden); + epg->GetChannelData()->SetEPGEnabled(m_bEPGEnabled); + } + SetChanged(); m_bChanged = true; return true; @@ -267,6 +283,11 @@ bool CPVRChannel::SetLocked(bool bIsLocked) if (m_bIsLocked != bIsLocked) { m_bIsLocked = bIsLocked; + + const std::shared_ptr epg = GetEPG(); + if (epg) + epg->GetChannelData()->SetLocked(m_bIsLocked); + SetChanged(); m_bChanged = true; return true; @@ -299,6 +320,11 @@ bool CPVRChannel::SetIconPath(const std::string &strIconPath, bool bIsUserSetIco if (m_strIconPath != strIconPath) { m_strIconPath = StringUtils::Format("%s", strIconPath.c_str()); + + const std::shared_ptr epg = GetEPG(); + if (epg) + epg->GetChannelData()->SetIconPath(m_strIconPath); + SetChanged(); m_bChanged = true; m_bIsUserSetIcon = bIsUserSetIcon && !m_strIconPath.empty(); @@ -329,8 +355,13 @@ bool CPVRChannel::SetChannelName(const std::string &strChannelName, bool bIsUser m_strChannelName = ClientChannelName(); } + const std::shared_ptr epg = GetEPG(); + if (epg) + epg->GetChannelData()->SetChannelName(m_strChannelName); + SetChanged(); m_bChanged = true; + return true; } @@ -341,7 +372,13 @@ bool CPVRChannel::SetLastWatched(time_t iLastWatched) { { CSingleLock lock(m_critSection); - m_iLastWatched = iLastWatched; + if (m_iLastWatched != iLastWatched) + { + m_iLastWatched = iLastWatched; + const std::shared_ptr epg = GetEPG(); + if (epg) + epg->GetChannelData()->SetLastWatched(iLastWatched); + } } const CPVRDatabasePtr database = CServiceBroker::GetPVRManager().GetTVDatabase(); @@ -565,6 +602,11 @@ bool CPVRChannel::SetEPGEnabled(bool bEPGEnabled) if (m_bEPGEnabled != bEPGEnabled) { m_bEPGEnabled = bEPGEnabled; + + const std::shared_ptr epg = GetEPG(); + if (epg) + epg->GetChannelData()->SetEPGEnabled(m_bEPGEnabled); + SetChanged(); m_bChanged = true; @@ -603,7 +645,14 @@ bool CPVRChannel::SetEPGScraper(const std::string &strScraper) void CPVRChannel::SetChannelNumber(const CPVRChannelNumber& channelNumber) { CSingleLock lock(m_critSection); - m_channelNumber = channelNumber; + if (m_channelNumber != channelNumber) + { + m_channelNumber = channelNumber; + + const std::shared_ptr epg = GetEPG(); + if (epg) + epg->GetChannelData()->SetSortableChannelNumber(m_channelNumber.SortableChannelNumber()); + } } void CPVRChannel::ToSortable(SortItem& sortable, Field field) const diff --git a/xbmc/pvr/channels/PVRChannel.h b/xbmc/pvr/channels/PVRChannel.h index 42101087ad..b79521cb31 100644 --- a/xbmc/pvr/channels/PVRChannel.h +++ b/xbmc/pvr/channels/PVRChannel.h @@ -32,8 +32,7 @@ namespace PVR /** PVR Channel class */ class CPVRChannel : public Observable, public ISerializable, - public ISortable, - public std::enable_shared_from_this + public ISortable { friend class CPVRDatabase; diff --git a/xbmc/pvr/channels/PVRChannelGroup.cpp b/xbmc/pvr/channels/PVRChannelGroup.cpp index 4293a18cf5..5e4074c852 100644 --- a/xbmc/pvr/channels/PVRChannelGroup.cpp +++ b/xbmc/pvr/channels/PVRChannelGroup.cpp @@ -30,6 +30,7 @@ #include "pvr/PVRManager.h" #include "pvr/addons/PVRClients.h" #include "pvr/channels/PVRChannelGroupsContainer.h" +#include "pvr/epg/EpgChannelData.h" #include "pvr/epg/EpgContainer.h" using namespace PVR; @@ -941,16 +942,16 @@ int CPVRChannelGroup::GetEPGAll(CFileItemList &results, bool bIncludeChannelsWit CPVREpgPtr epg = channel->GetEPG(); if (epg) - { - // XXX channel pointers aren't set in some occasions. this works around the issue, but is not very nice - epg->SetChannel(channel); iAdded = epg->Get(results); - } if (bIncludeChannelsWithoutEPG && iAdded == 0) { // Add dummy EPG tag associated with this channel - epgTag = std::make_shared(channel); + if (epg) + epgTag = std::make_shared(epg->GetChannelData(), epg->EpgID()); + else + epgTag = std::make_shared(std::make_shared(*channel), -1); + results.Add(std::make_shared(epgTag)); } } diff --git a/xbmc/pvr/channels/PVRChannelGroups.cpp b/xbmc/pvr/channels/PVRChannelGroups.cpp index bf4b1d9286..3a4bf8f08f 100644 --- a/xbmc/pvr/channels/PVRChannelGroups.cpp +++ b/xbmc/pvr/channels/PVRChannelGroups.cpp @@ -546,7 +546,7 @@ bool CPVRChannelGroups::CreateChannelEpgs(void) CSingleLock lock(m_critSection); for (std::vector::iterator it = m_groups.begin(); it != m_groups.end(); ++it) { - /* Only create EPGs for the internatl groups */ + /* Only create EPGs for the internal groups */ if ((*it)->IsInternalGroup()) bReturn = (*it)->CreateChannelEpgs(); } diff --git a/xbmc/pvr/channels/PVRChannelGroupsContainer.cpp b/xbmc/pvr/channels/PVRChannelGroupsContainer.cpp index 2f879d28c8..2e9043c03b 100644 --- a/xbmc/pvr/channels/PVRChannelGroupsContainer.cpp +++ b/xbmc/pvr/channels/PVRChannelGroupsContainer.cpp @@ -15,6 +15,7 @@ #include "utils/log.h" #include "pvr/PVRManager.h" +#include "pvr/epg/EpgInfoTag.h" using namespace PVR; @@ -105,6 +106,15 @@ CPVRChannelPtr CPVRChannelGroupsContainer::GetChannelByEpgId(int iEpgId) const return channel; } +std::shared_ptr CPVRChannelGroupsContainer::GetChannelForEpgTag(const std::shared_ptr& epgTag) const +{ + if (!epgTag) + return std::shared_ptr(); + + const CPVRChannelGroups* groups = epgTag->IsRadio() ? m_groupsRadio : m_groupsTV; + return groups->GetGroupAll()->GetByUniqueID(epgTag->UniqueChannelID(), epgTag->ClientID()); +} + bool CPVRChannelGroupsContainer::GetGroupsDirectory(CFileItemList *results, bool bRadio) const { const CPVRChannelGroups *channelGroups = Get(bRadio); diff --git a/xbmc/pvr/channels/PVRChannelGroupsContainer.h b/xbmc/pvr/channels/PVRChannelGroupsContainer.h index baa02ac145..5417e45611 100644 --- a/xbmc/pvr/channels/PVRChannelGroupsContainer.h +++ b/xbmc/pvr/channels/PVRChannelGroupsContainer.h @@ -112,6 +112,13 @@ namespace PVR */ CPVRChannelPtr GetChannelByEpgId(int iEpgId) const; + /*! + * @brief Get the channel for the given epg tag. + * @param epgTag The epg tag. + * @return The channel. + */ + std::shared_ptr GetChannelForEpgTag(const std::shared_ptr& epgTag) const; + /*! * @brief Get the groups list for a directory. * @param strBase The directory path. diff --git a/xbmc/pvr/dialogs/GUIDialogPVRGuideInfo.cpp b/xbmc/pvr/dialogs/GUIDialogPVRGuideInfo.cpp index 4db83d06ad..e2ae28ed9d 100644 --- a/xbmc/pvr/dialogs/GUIDialogPVRGuideInfo.cpp +++ b/xbmc/pvr/dialogs/GUIDialogPVRGuideInfo.cpp @@ -69,14 +69,6 @@ bool CGUIDialogPVRGuideInfo::OnClickButtonRecord(CGUIMessage &message) { bReturn = true; - if (!m_progItem || !m_progItem->HasChannel()) - { - /* invalid channel */ - HELPERS::ShowOKDialogText(CVariant{19033}, CVariant{19067}); - Close(); - return bReturn; - } - const std::shared_ptr timerTag = CServiceBroker::GetPVRManager().Timers()->GetTimerForEpgTag(m_progItem); if (timerTag) { @@ -216,7 +208,7 @@ void CGUIDialogPVRGuideInfo::OnInitWindow() bHideRecord = false; } } - else if (m_progItem->Channel() && m_progItem->IsRecordable()) + else if (m_progItem->IsRecordable()) { const CPVRClientPtr client = CServiceBroker::GetPVRManager().GetClient(m_progItem->ClientID()); if (client && client->GetClientCapabilities().SupportsTimers()) diff --git a/xbmc/pvr/epg/CMakeLists.txt b/xbmc/pvr/epg/CMakeLists.txt index bef9dc29f3..9b350ab18b 100644 --- a/xbmc/pvr/epg/CMakeLists.txt +++ b/xbmc/pvr/epg/CMakeLists.txt @@ -2,12 +2,14 @@ set(SOURCES EpgContainer.cpp Epg.cpp EpgDatabase.cpp EpgInfoTag.cpp - EpgSearchFilter.cpp) + EpgSearchFilter.cpp + EpgChannelData.cpp) set(HEADERS Epg.h EpgContainer.h EpgDatabase.h EpgInfoTag.h - EpgSearchFilter.h) + EpgSearchFilter.h + EpgChannelData.h) core_add_library(pvr_epg) diff --git a/xbmc/pvr/epg/Epg.cpp b/xbmc/pvr/epg/Epg.cpp index d40bc524d6..60ae02943c 100644 --- a/xbmc/pvr/epg/Epg.cpp +++ b/xbmc/pvr/epg/Epg.cpp @@ -12,8 +12,6 @@ #include "addons/PVRClient.h" #include "addons/kodi-addon-dev-kit/include/kodi/xbmc_epg_types.h" -#include "EpgContainer.h" -#include "EpgDatabase.h" #include "ServiceBroker.h" #include "guilib/LocalizeStrings.h" #include "settings/AdvancedSettings.h" @@ -22,23 +20,27 @@ #include "utils/log.h" #include "pvr/PVRManager.h" +#include "pvr/epg/EpgChannelData.h" +#include "pvr/epg/EpgContainer.h" +#include "pvr/epg/EpgDatabase.h" using namespace PVR; -CPVREpg::CPVREpg(int iEpgID, const std::string &strName, const std::string &strScraperName, bool bLoadedFromDb) -: m_bChanged(!bLoadedFromDb), +CPVREpg::CPVREpg(int iEpgID, const std::string& strName, const std::string& strScraperName) +: m_bChanged(false), m_iEpgID(iEpgID), m_strName(strName), - m_strScraperName(strScraperName) + m_strScraperName(strScraperName), + m_channelData(new CPVREpgChannelData) { } -CPVREpg::CPVREpg(const CPVRChannelPtr &channel) +CPVREpg::CPVREpg(int iEpgID, const std::string& strName, const std::string& strScraperName, const std::shared_ptr& channelData) : m_bChanged(true), - m_iEpgID(channel->EpgID()), - m_strName(channel->ChannelName()), - m_strScraperName(channel->EPGScraper()), - m_pvrChannel(channel) + m_iEpgID(iEpgID), + m_strName(strName), + m_strScraperName(strScraperName), + m_channelData(channelData) { } @@ -232,11 +234,7 @@ CPVREpgInfoTagPtr CPVREpg::GetTagBetween(const CDateTime &beginTime, const CDate time_t e; endTime.GetAsTime(e); - const CPVRChannelPtr channel = Channel(); - const CPVREpgPtr tmpEpg = channel - ? std::make_shared(channel) - : std::make_shared(m_iEpgID, m_strName, m_strScraperName, false); - + const std::shared_ptr tmpEpg = std::make_shared(m_iEpgID, m_strName, m_strScraperName, m_channelData); if (tmpEpg->UpdateFromScraper(b, e, true)) tag = tmpEpg->GetTagBetween(beginTime, endTime, false); @@ -253,27 +251,19 @@ CPVREpgInfoTagPtr CPVREpg::GetTagBetween(const CDateTime &beginTime, const CDate void CPVREpg::AddEntry(const CPVREpgInfoTag &tag) { CPVREpgInfoTagPtr newTag; - CPVRChannelPtr channel; - { - CSingleLock lock(m_critSection); - const auto it = m_tags.find(tag.StartAsUTC()); - if (it != m_tags.end()) - newTag = it->second; - else - { - newTag = std::make_shared(m_pvrChannel, this, m_strName); - m_tags.insert(std::make_pair(tag.StartAsUTC(), newTag)); - } - - channel = m_pvrChannel; - } - if (newTag) + CSingleLock lock(m_critSection); + const auto it = m_tags.find(tag.StartAsUTC()); + if (it != m_tags.end()) + newTag = it->second; + else { - newTag->Update(tag); - newTag->SetChannel(channel); - newTag->SetEpg(this); + newTag = std::make_shared(m_channelData, m_iEpgID); + m_tags.insert(std::make_pair(tag.StartAsUTC(), newTag)); } + + newTag->Update(tag); + newTag->SetEpgID(m_iEpgID); } bool CPVREpg::Load(void) @@ -357,7 +347,7 @@ bool CPVREpg::UpdateEntry(const EPG_TAG *data, int iClientId, bool bUpdateDataba if (!data) return false; - const CPVREpgInfoTagPtr tag = std::make_shared(*data, iClientId); + const std::shared_ptr tag = std::make_shared(*data, iClientId, m_channelData, m_iEpgID); return UpdateEntry(tag, bUpdateDatabase); } @@ -365,29 +355,26 @@ bool CPVREpg::UpdateEntry(const CPVREpgInfoTagPtr &tag, bool bUpdateDatabase) { CPVREpgInfoTagPtr infoTag; + CSingleLock lock(m_critSection); + const auto it = m_tags.find(tag->StartAsUTC()); + bool bNewTag = false; + if (it != m_tags.end()) { - CSingleLock lock(m_critSection); - const auto it = m_tags.find(tag->StartAsUTC()); - bool bNewTag = false; - if (it != m_tags.end()) - { - infoTag = it->second; - } - else - { - infoTag = std::make_shared(m_pvrChannel, this, m_strName); - infoTag->SetUniqueBroadcastID(tag->UniqueBroadcastID()); - m_tags.insert(std::make_pair(tag->StartAsUTC(), infoTag)); - bNewTag = true; - } + infoTag = it->second; + } + else + { + infoTag = std::make_shared(m_channelData, m_iEpgID); + infoTag->SetUniqueBroadcastID(tag->UniqueBroadcastID()); + m_tags.insert(std::make_pair(tag->StartAsUTC(), infoTag)); + bNewTag = true; + } - infoTag->Update(*tag, bNewTag); - infoTag->SetEpg(this); - infoTag->SetChannel(m_pvrChannel); + infoTag->Update(*tag, bNewTag); + infoTag->SetEpgID(m_iEpgID); - if (bUpdateDatabase) - m_changedTags.insert(std::make_pair(infoTag->UniqueBroadcastID(), infoTag)); - } + if (bUpdateDatabase) + m_changedTags.insert(std::make_pair(infoTag->UniqueBroadcastID(), infoTag)); return true; } @@ -464,8 +451,8 @@ bool CPVREpg::Update(const time_t start, const time_t end, int iUpdateTime, bool /* get the last update time from the database */ const CDateTime lastScanTime = GetLastScanTime(); - /* enforce advanced settings update interval override for TV Channels with no EPG data */ - if (m_tags.empty() && !bUpdate && ChannelID() > 0 && !Channel()->IsRadio()) + /* enforce advanced settings update interval override for channels with no EPG data */ + if (m_tags.empty() && !bUpdate && ChannelID() > 0) iUpdateTime = CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_iEpgUpdateEmptyTagsInterval; if (!bForceUpdate) @@ -538,11 +525,15 @@ bool CPVREpg::Persist(void) { CSingleLock lock(m_critSection); + bool bEpgIdChanged = false; if (m_iEpgID <= 0 || m_bChanged) { int iId = database->Persist(*this, m_iEpgID > 0); - if (iId > 0) + if (iId > 0 && m_iEpgID != iId) + { m_iEpgID = iId; + bEpgIdChanged = true; + } } for (const auto& tag : m_deletedTags) @@ -554,6 +545,12 @@ bool CPVREpg::Persist(void) if (m_bUpdateLastScanTime) database->PersistLastEpgScanTime(m_iEpgID, true); + if (bEpgIdChanged) + { + for (const auto& tag : m_tags) + tag.second->SetEpgID(m_iEpgID); + } + m_deletedTags.clear(); m_changedTags.clear(); m_bChanged = false; @@ -639,43 +636,38 @@ bool CPVREpg::UpdateFromScraper(time_t start, time_t end, bool bForceUpdate) } else if (m_strScraperName == "client") { - const CPVRChannelPtr channel = Channel(); - if (channel) + if (!CServiceBroker::GetPVRManager().EpgsCreated()) + return false; + + if (!m_channelData->IsEPGEnabled() || m_channelData->IsHidden()) { - if (!channel->EPGEnabled() || channel->IsHidden()) + // ignore. not interested in any updates. + return true; + } + + const std::shared_ptr client = CServiceBroker::GetPVRManager().GetClient(m_channelData->ClientId()); + if (client) + { + if (!client->GetClientCapabilities().SupportsEPG()) { - // ignore. not interested in any updates. - return true; + CLog::LogF(LOGERROR, "The backend for channel '%s' on client '%i' does not support EPGs", + m_channelData->ChannelName().c_str(), m_channelData->ClientId()); } - - const CPVRClientPtr client = CServiceBroker::GetPVRManager().GetClient(channel->ClientID()); - if (client) + else if (!bForceUpdate && client->GetClientCapabilities().SupportsAsyncEPGTransfer()) { - if (!client->GetClientCapabilities().SupportsEPG()) - { - CLog::LogF(LOGERROR, "The backend for channel '%s' on client '%i' does not support EPGs", - channel->ChannelName().c_str(), channel->ClientID()); - } - else if (!bForceUpdate && client->GetClientCapabilities().SupportsAsyncEPGTransfer()) - { - // nothing to do. client will provide epg updates asynchronously - return true; - } - else - { - CLog::LogFC(LOGDEBUG, LOGEPG, "Updating EPG for channel '%s' from client '%i'", - channel->ChannelName().c_str(), channel->ClientID()); - return (client->GetEPGForChannel(channel, this, start, end) == PVR_ERROR_NO_ERROR); - } + // nothing to do. client will provide epg updates asynchronously + return true; } else { - CLog::LogF(LOGERROR, "Client '%i' not found, can't update", channel->ClientID()); + CLog::LogFC(LOGDEBUG, LOGEPG, "Updating EPG for channel '%s' from client '%i'", + m_channelData->ChannelName().c_str(), m_channelData->ClientId()); + return (client->GetEPGForChannel(m_channelData, this, start, end) == PVR_ERROR_NO_ERROR); } } else { - CLog::LogF(LOGERROR, "Channel not found, can't update"); + CLog::LogF(LOGERROR, "Client '%i' not found, can't update", m_channelData->ClientId()); } } else // other non-empty scraper name... @@ -739,49 +731,32 @@ bool CPVREpg::LoadFromClients(time_t start, time_t end, bool bForceUpdate) { bool bReturn = false; - const CPVRChannelPtr channel = Channel(); - const CPVREpgPtr tmpEpg = channel - ? std::make_shared(channel) - : std::make_shared(m_iEpgID, m_strName, m_strScraperName, false); - + const std::shared_ptr tmpEpg = std::make_shared(m_iEpgID, m_strName, m_strScraperName, m_channelData); if (tmpEpg->UpdateFromScraper(start, end, bForceUpdate)) bReturn = UpdateEntries(*tmpEpg, !CServiceBroker::GetPVRManager().EpgContainer().IgnoreDB()); return bReturn; } -CPVRChannelPtr CPVREpg::Channel(void) const +std::shared_ptr CPVREpg::GetChannelData() const { CSingleLock lock(m_critSection); - return m_pvrChannel; + return m_channelData; } -int CPVREpg::ChannelID(void) const +void CPVREpg::SetChannelData(const std::shared_ptr& data) { CSingleLock lock(m_critSection); - return m_pvrChannel ? m_pvrChannel->ChannelID() : -1; + m_channelData = data; + + for (const auto& tag : m_tags) + tag.second->SetChannelData(data); } -void CPVREpg::SetChannel(const CPVRChannelPtr &channel) +int CPVREpg::ChannelID(void) const { CSingleLock lock(m_critSection); - if (m_pvrChannel != channel) - { - if (channel) - { - if (m_strName != channel->ChannelName()) - { - m_bChanged = true; - m_strName = channel->ChannelName(); - } - - channel->SetEpgID(m_iEpgID); - } - - m_pvrChannel = channel; - for (const auto& tag : m_tags) - tag.second->SetChannel(m_pvrChannel); - } + return m_channelData->ChannelId(); } const std::string& CPVREpg::ScraperName(void) const @@ -818,7 +793,7 @@ bool CPVREpg::IsValid(void) const { CSingleLock lock(m_critSection); if (ScraperName() == "client") - return m_pvrChannel != nullptr; + return m_channelData->ClientId() != -1 && m_channelData->UniqueClientChannelId() != PVR_CHANNEL_INVALID_UID; return true; } diff --git a/xbmc/pvr/epg/Epg.h b/xbmc/pvr/epg/Epg.h index 9fb9150085..9d6f07365d 100644 --- a/xbmc/pvr/epg/Epg.h +++ b/xbmc/pvr/epg/Epg.h @@ -17,13 +17,14 @@ #include "utils/Observer.h" #include "pvr/PVRTypes.h" -#include "pvr/channels/PVRChannel.h" #include "pvr/epg/EpgInfoTag.h" #include "pvr/epg/EpgSearchFilter.h" /** EPG container for CPVREpgInfoTag instances */ namespace PVR { + class CPVREpgChannelData; + class CPVREpg : public Observable { friend class CPVREpgDatabase; @@ -34,15 +35,17 @@ namespace PVR * @param iEpgID The ID of this table or <= 0 to create a new ID. * @param strName The name of this table. * @param strScraperName The name of the scraper to use. - * @param bLoadedFromDb True if this table was loaded from the database, false otherwise. */ - CPVREpg(int iEpgID, const std::string &strName, const std::string &strScraperName, bool bLoadedFromDb); + CPVREpg(int iEpgID, const std::string& strName, const std::string& strScraperName); /*! - * @brief Create a new EPG instance for a channel. - * @param channel The channel to create the EPG for. + * @brief Create a new EPG instance. + * @param iEpgID The ID of this table or <= 0 to create a new ID. + * @param strName The name of this table. + * @param strScraperName The name of the scraper to use. + * @param channelData The channel data. */ - CPVREpg(const CPVRChannelPtr &channel); + CPVREpg(int iEpgID, const std::string& strName, const std::string& strScraperName, const std::shared_ptr& channelData); /*! * @brief Destroy this EPG instance. @@ -56,22 +59,22 @@ namespace PVR bool Load(void); /*! - * @brief The channel this EPG belongs to. - * @return The channel this EPG belongs to + * @brief Get data for the channel associated with this EPG. + * @return The data. */ - CPVRChannelPtr Channel(void) const; + std::shared_ptr GetChannelData() const; /*! - * @brief The id of the channel this EPG belongs to. - * @return The channel id or -1 if no channel + * @brief Set data for the channel associated with this EPG. + * @param data The data. */ - int ChannelID(void) const; + void SetChannelData(const std::shared_ptr& data); /*! - * @brief Channel the channel tag linked to this EPG table. - * @param channel The new channel tag. + * @brief The id of the channel associated with this EPG. + * @return The channel id or -1 if no channel is associated */ - void SetChannel(const CPVRChannelPtr &channel); + int ChannelID(void) const; /*! * @brief Get the name of the scraper to use for this table. @@ -317,12 +320,10 @@ namespace PVR std::string m_strName; /*!< the name of this table */ std::string m_strScraperName; /*!< the name of the scraper to use */ mutable CDateTime m_nowActiveStart; /*!< the start time of the tag that is currently active */ - CDateTime m_lastScanTime; /*!< the last time the EPG has been updated */ - - CPVRChannelPtr m_pvrChannel; /*!< the channel this EPG belongs to */ - mutable CCriticalSection m_critSection; /*!< critical section for changes in this table */ bool m_bUpdateLastScanTime = false; + + std::shared_ptr m_channelData; }; } diff --git a/xbmc/pvr/epg/EpgChannelData.cpp b/xbmc/pvr/epg/EpgChannelData.cpp new file mode 100644 index 0000000000..7f6ca36edd --- /dev/null +++ b/xbmc/pvr/epg/EpgChannelData.cpp @@ -0,0 +1,135 @@ +/* + * Copyright (C) 2012-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "EpgChannelData.h" + +#include "XBDateTime.h" + +#include "pvr/channels/PVRChannel.h" + +using namespace PVR; + +CPVREpgChannelData::CPVREpgChannelData(int iClientId, int iUniqueClientChannelId) +: m_iClientId(iClientId), + m_iUniqueClientChannelId(iUniqueClientChannelId) +{ +} + +CPVREpgChannelData::CPVREpgChannelData(const CPVRChannel& channel) +: m_bIsRadio(channel.IsRadio()), + m_iClientId(channel.ClientID()), + m_iUniqueClientChannelId(channel.UniqueID()), + m_bIsHidden(channel.IsHidden()), + m_bIsLocked(channel.IsLocked()), + m_bIsEPGEnabled(channel.EPGEnabled()), + m_iChannelId(channel.ChannelID()), + m_strIconPath(channel.IconPath()), + m_strChannelName(channel.ChannelName()), + m_strSortableChannelNumber(channel.ChannelNumber().SortableChannelNumber()) +{ + SetLastWatched(channel.LastWatched()); +} + +bool CPVREpgChannelData::IsRadio() const +{ + return m_bIsRadio; +} + +int CPVREpgChannelData::ClientId() const +{ + return m_iClientId; +} + +int CPVREpgChannelData::UniqueClientChannelId() const +{ + return m_iUniqueClientChannelId; +} + +bool CPVREpgChannelData::IsHidden() const +{ + return m_bIsHidden; +} + +void CPVREpgChannelData::SetHidden(bool bIsHidden) +{ + m_bIsHidden = bIsHidden; +} + +bool CPVREpgChannelData::IsLocked() const +{ + return m_bIsLocked; +} + +void CPVREpgChannelData::SetLocked(bool bIsLocked) +{ + m_bIsLocked = bIsLocked; +} + +bool CPVREpgChannelData::IsEPGEnabled() const +{ + return m_bIsEPGEnabled; +} + +void CPVREpgChannelData::SetEPGEnabled(bool bIsEPGEnabled) +{ + m_bIsEPGEnabled = bIsEPGEnabled; +} + +int CPVREpgChannelData::ChannelId() const +{ + return m_iChannelId; +} + +void CPVREpgChannelData::SetChannelId(int iChannelId) +{ + m_iChannelId = iChannelId; +} + +const std::string& CPVREpgChannelData::IconPath() const +{ + return m_strIconPath; +} + +void CPVREpgChannelData::SetIconPath(const std::string& strIconPath) +{ + m_strIconPath = strIconPath; +} + +const std::string& CPVREpgChannelData::ChannelName() const +{ + return m_strChannelName; +} + +void CPVREpgChannelData::SetChannelName(const std::string& strChannelName) +{ + m_strChannelName = strChannelName; +} + +const std::string& CPVREpgChannelData::SortableChannelNumber() const +{ + return m_strSortableChannelNumber; +} + +void CPVREpgChannelData::SetSortableChannelNumber(const std::string& strSortableChannelNumber) +{ + m_strSortableChannelNumber = strSortableChannelNumber; +} + +const std::string& CPVREpgChannelData::LastWatched() const +{ + return m_strLastWatched; +} + +void CPVREpgChannelData::SetLastWatched(time_t iLastWatched) +{ + const CDateTime lastWatched(iLastWatched); + if (lastWatched.IsValid()) + m_strLastWatched = lastWatched.GetAsDBDateTime(); + else + m_strLastWatched.clear(); +} diff --git a/xbmc/pvr/epg/EpgChannelData.h b/xbmc/pvr/epg/EpgChannelData.h new file mode 100644 index 0000000000..45bd1dafb8 --- /dev/null +++ b/xbmc/pvr/epg/EpgChannelData.h @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2012-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include +#include + +namespace PVR +{ + class CPVRChannel; + + class CPVREpgChannelData + { + public: + CPVREpgChannelData() = default; + CPVREpgChannelData(int iClientId, int iUniqueClientChannelId); + explicit CPVREpgChannelData(const CPVRChannel& channel); + + int ClientId() const; + int UniqueClientChannelId() const; + bool IsRadio() const; + + bool IsHidden() const; + void SetHidden(bool bIsHidden); + + bool IsLocked() const; + void SetLocked(bool bIsLocked); + + bool IsEPGEnabled() const; + void SetEPGEnabled(bool bIsEPGEnabled); + + int ChannelId() const; + void SetChannelId(int iChannelId); + + const std::string& IconPath() const; + void SetIconPath(const std::string& strIconPath); + + const std::string& ChannelName() const; + void SetChannelName(const std::string& strChannelName); + + const std::string& SortableChannelNumber() const; + void SetSortableChannelNumber(const std::string& strSortableChannelNumber); + + const std::string& LastWatched() const; + void SetLastWatched(time_t iLastWatched); + + private: + const bool m_bIsRadio = false; + const int m_iClientId = -1; + const int m_iUniqueClientChannelId = -1; + + bool m_bIsHidden = false; + bool m_bIsLocked = false; + bool m_bIsEPGEnabled = true; + int m_iChannelId = -1; + std::string m_strIconPath; + std::string m_strChannelName; + std::string m_strSortableChannelNumber; + std::string m_strLastWatched; + }; +} diff --git a/xbmc/pvr/epg/EpgContainer.cpp b/xbmc/pvr/epg/EpgContainer.cpp index a486becb22..6e1028b15e 100644 --- a/xbmc/pvr/epg/EpgContainer.cpp +++ b/xbmc/pvr/epg/EpgContainer.cpp @@ -8,8 +8,6 @@ #include "EpgContainer.h" -#include - #include "ServiceBroker.h" #include "guilib/LocalizeStrings.h" #include "settings/AdvancedSettings.h" @@ -22,8 +20,8 @@ #include "pvr/PVRManager.h" #include "pvr/PVRGUIProgressHandler.h" -#include "pvr/channels/PVRChannelGroupsContainer.h" #include "pvr/epg/Epg.h" +#include "pvr/epg/EpgChannelData.h" #include "pvr/epg/EpgSearchFilter.h" namespace PVR @@ -33,29 +31,22 @@ class CEpgUpdateRequest { public: CEpgUpdateRequest() : CEpgUpdateRequest(-1, PVR_CHANNEL_INVALID_UID) {} - CEpgUpdateRequest(int iClientID, unsigned int iUniqueChannelID) : m_iClientID(iClientID), m_iUniqueChannelID(iUniqueChannelID) {} + CEpgUpdateRequest(int iClientID, int iUniqueChannelID) : m_iClientID(iClientID), m_iUniqueChannelID(iUniqueChannelID) {} void Deliver(); private: int m_iClientID; - unsigned int m_iUniqueChannelID; + int m_iUniqueChannelID; }; void CEpgUpdateRequest::Deliver() { - const CPVRChannelPtr channel = CServiceBroker::GetPVRManager().ChannelGroups()->GetByUniqueID(m_iUniqueChannelID, m_iClientID); - if (!channel) - { - CLog::LogF(LOGERROR, "Invalid channel (%d)! Unable to deliver the epg update!", m_iUniqueChannelID); - return; - } - - const CPVREpgPtr epg = channel->GetEPG(); + const std::shared_ptr epg = CServiceBroker::GetPVRManager().EpgContainer().GetByChannelUid(m_iClientID, m_iUniqueChannelID); if (!epg) { - CLog::LogF(LOGERROR, "Channel '%s' does not have an EPG! Unable to deliver the epg update!", - channel->ChannelName().c_str()); + CLog::LogF(LOGERROR, "Unable to obtain EPG for client %d and channel %d! Unable to deliver the epg update request!", + m_iClientID, m_iUniqueChannelID); return; } @@ -77,25 +68,27 @@ private: void CEpgTagStateChange::Deliver() { - const CPVRChannelPtr channel = CServiceBroker::GetPVRManager().ChannelGroups()->GetByUniqueID(m_epgtag->UniqueChannelID(), m_epgtag->ClientID()); - if (!channel) + const std::shared_ptr epg = CServiceBroker::GetPVRManager().EpgContainer().GetByChannelUid(m_epgtag->ClientID(), m_epgtag->UniqueChannelID()); + if (!epg) { - CLog::LogF(LOGERROR, "Invalid channel (%d)! Unable to deliver state change for tag '%d'!", - m_epgtag->UniqueChannelID(), m_epgtag->UniqueBroadcastID()); + CLog::LogF(LOGERROR, "Unable to obtain EPG for client %d and channel %d! Unable to deliver state change for tag '%d'!", + m_epgtag->ClientID(), m_epgtag->UniqueChannelID(), m_epgtag->UniqueBroadcastID()); return; } - const CPVREpgPtr epg = channel->GetEPG(); - if (!epg) + if (m_epgtag->EpgID() < 0) { - CLog::LogF(LOGERROR, "Channel '%s' does not have an EPG! Unable to deliver state change for tag '%d'!", - channel->ChannelName().c_str(), m_epgtag->UniqueBroadcastID()); - return; + // now that we have the epg instance, fully initialize the tag + m_epgtag->SetEpgID(epg->EpgID()); + m_epgtag->SetChannelData(epg->GetChannelData()); } // update if (!epg->UpdateEntry(m_epgtag, m_state, false)) - CLog::LogF(LOGERROR, "Update failed for epgtag change for channel '%s'", channel->ChannelName().c_str()); + CLog::LogF(LOGWARNING, "State update failed for epgtag (%s | %s | %s | %s | %s)", + m_state == EPG_EVENT_DELETED ? "DELETED" : m_state == EPG_EVENT_UPDATED ? "UPDTAED" : m_state == EPG_EVENT_CREATED ? "CREATED" : "UNKNOWN", + epg->GetChannelData()->ChannelName().c_str(), m_epgtag->StartAsLocalTime().GetAsDBDateTime(), m_epgtag->EndAsLocalTime().GetAsDBDateTime(), + m_epgtag->Title().c_str()); } CPVREpgContainer::CPVREpgContainer(void) : @@ -134,7 +127,7 @@ bool CPVREpgContainer::IsStarted(void) const return m_bStarted; } -unsigned int CPVREpgContainer::NextEpgId(void) +int CPVREpgContainer::NextEpgId(void) { CSingleLock lock(m_critSection); return ++m_iNextEpgId; @@ -150,10 +143,11 @@ void CPVREpgContainer::Clear() { CSingleLock lock(m_critSection); /* clear all epg tables and remove pointers to epg tables on channels */ - for (const auto &epgEntry : m_epgs) + for (const auto &epgEntry : m_epgIdToEpgMap) epgEntry.second->UnregisterObserver(this); - m_epgs.clear(); + m_epgIdToEpgMap.clear(); + m_channelUidToEpgMap.clear(); m_iNextEpgUpdate = 0; m_bStarted = false; m_bIsInitialising = true; @@ -280,12 +274,12 @@ void CPVREpgContainer::LoadFromDB(void) for (const auto& entry : result) InsertFromDB(entry); - for (const auto &epgEntry : m_epgs) + for (const auto &epgEntry : m_epgIdToEpgMap) { if (m_bStop) break; - progressHandler->UpdateProgress(epgEntry.second->Name(), ++iCounter, m_epgs.size()); + progressHandler->UpdateProgress(epgEntry.second->Name(), ++iCounter, m_epgIdToEpgMap.size()); lock.Leave(); epgEntry.second->Load(); @@ -302,7 +296,7 @@ bool CPVREpgContainer::PersistAll(void) bool bReturn = true; m_critSection.lock(); - const auto epgs = m_epgs; + const auto epgs = m_epgIdToEpgMap; m_critSection.unlock(); for (const auto& epg : epgs) @@ -438,29 +432,42 @@ CPVREpgPtr CPVREpgContainer::GetById(int iEpgId) const return retval; CSingleLock lock(m_critSection); - const auto &epgEntry = m_epgs.find(static_cast(iEpgId)); - if (epgEntry != m_epgs.end()) + const auto &epgEntry = m_epgIdToEpgMap.find(iEpgId); + if (epgEntry != m_epgIdToEpgMap.end()) retval = epgEntry->second; return retval; } -CPVREpgInfoTagPtr CPVREpgContainer::GetTagById(const CPVRChannelPtr &channel, unsigned int iBroadcastId) const +std::shared_ptr CPVREpgContainer::GetByChannelUid(int iClientId, int iChannelUid) const +{ + std::shared_ptr epg; + + if (iClientId < 0 || iChannelUid < 0) + return epg; + + CSingleLock lock(m_critSection); + const auto &epgEntry = m_channelUidToEpgMap.find(std::pair(iClientId, iChannelUid)); + if (epgEntry != m_channelUidToEpgMap.end()) + epg = epgEntry->second; + + return epg; +} + +std::shared_ptr CPVREpgContainer::GetTagById(const std::shared_ptr& epg, unsigned int iBroadcastId) const { CPVREpgInfoTagPtr retval; if (iBroadcastId == EPG_TAG_INVALID_UID) return retval; - if (channel) + if (epg) { - const CPVREpgPtr epg = channel->GetEPG(); - if (epg) - retval = epg->GetTagByBroadcastId(iBroadcastId); + retval = epg->GetTagByBroadcastId(iBroadcastId); } else { - for (const auto &epgEntry : m_epgs) + for (const auto &epgEntry : m_epgIdToEpgMap) { retval = epgEntry.second->GetTagByBroadcastId(iBroadcastId); if (retval) @@ -488,38 +495,41 @@ void CPVREpgContainer::InsertFromDB(const CPVREpgPtr &newEpg) { // create a new epg table epg = newEpg; - m_epgs.insert(std::make_pair(epg->EpgID(), epg)); + m_epgIdToEpgMap.insert(std::make_pair(epg->EpgID(), epg)); SetChanged(); epg->RegisterObserver(this); } } -CPVREpgPtr CPVREpgContainer::CreateChannelEpg(const CPVRChannelPtr &channel) +CPVREpgPtr CPVREpgContainer::CreateChannelEpg(int iEpgId, const std::string& strScraperName, const std::shared_ptr& channelData) { CPVREpgPtr epg; - if (!channel) - return epg; WaitForUpdateFinish(); LoadFromDB(); - if (channel->EpgID() > 0) - epg = GetById(channel->EpgID()); + if (iEpgId > 0) + epg = GetById(iEpgId); if (!epg) { - if (channel->EpgID() <= 0) - channel->SetEpgID(NextEpgId()); + if (iEpgId <= 0) + iEpgId = NextEpgId(); - epg.reset(new CPVREpg(channel)); + epg.reset(new CPVREpg(iEpgId, channelData->ChannelName(), strScraperName, channelData)); CSingleLock lock(m_critSection); - m_epgs.insert(std::make_pair(static_cast(epg->EpgID()), epg)); + m_epgIdToEpgMap.insert(std::make_pair(iEpgId, epg)); + m_channelUidToEpgMap.insert(std::make_pair(std::make_pair(channelData->ClientId(), channelData->UniqueClientChannelId()), epg)); SetChanged(); epg->RegisterObserver(this); } - - epg->SetChannel(channel); + else if (epg->ChannelID() == -1) + { + CSingleLock lock(m_critSection); + m_channelUidToEpgMap.insert(std::make_pair(std::make_pair(channelData->ClientId(), channelData->UniqueClientChannelId()), epg)); + epg->SetChannelData(channelData); + } { CSingleLock lock(m_critSection); @@ -538,7 +548,7 @@ bool CPVREpgContainer::RemoveOldEntries(void) const CDateTime cleanupTime(CDateTime::GetUTCDateTime() - CDateTimeSpan(GetPastDaysToDisplay(), 0, 0, 0)); /* call Cleanup() on all known EPG tables */ - for (const auto &epgEntry : m_epgs) + for (const auto &epgEntry : m_epgIdToEpgMap) epgEntry.second->Cleanup(cleanupTime); /* remove the old entries from the database */ @@ -558,16 +568,21 @@ bool CPVREpgContainer::DeleteEpg(const CPVREpgPtr &epg, bool bDeleteFromDatabase CSingleLock lock(m_critSection); - const auto &epgEntry = m_epgs.find(static_cast(epg->EpgID())); - if (epgEntry == m_epgs.end()) + const auto &epgEntry = m_epgIdToEpgMap.find(epg->EpgID()); + if (epgEntry == m_epgIdToEpgMap.end()) return false; + const auto& epgEntry1 = m_channelUidToEpgMap.find(std::make_pair(epg->GetChannelData()->ClientId(), + epg->GetChannelData()->UniqueClientChannelId())); + if (epgEntry1 != m_channelUidToEpgMap.end()) + m_channelUidToEpgMap.erase(epgEntry1); + CLog::LogFC(LOGDEBUG, LOGEPG, "Deleting EPG table %s (%d)", epg->Name().c_str(), epg->EpgID()); if (bDeleteFromDatabase && !IgnoreDB()) m_database->Delete(*epgEntry->second); epgEntry->second->UnregisterObserver(this); - m_epgs.erase(epgEntry); + m_epgIdToEpgMap.erase(epgEntry); return true; } @@ -634,7 +649,7 @@ bool CPVREpgContainer::UpdateEPG(bool bOnlyPending /* = false */) /* load or update all EPG tables */ unsigned int iCounter = 0; - for (const auto &epgEntry : m_epgs) + for (const auto &epgEntry : m_epgIdToEpgMap) { if (InterruptUpdate()) { @@ -647,19 +662,7 @@ bool CPVREpgContainer::UpdateEPG(bool bOnlyPending /* = false */) continue; if (bShowProgress && !bOnlyPending) - progressHandler->UpdateProgress(epg->Name(), ++iCounter, m_epgs.size()); - - // we currently only support update via pvr add-ons. skip update when the pvr manager isn't started - if (!CServiceBroker::GetPVRManager().IsStarted()) - continue; - - // check the pvr manager when the channel pointer isn't set - if (!epg->Channel()) - { - const CPVRChannelPtr channel = CServiceBroker::GetPVRManager().ChannelGroups()->GetChannelByEpgId(epg->EpgID()); - if (channel) - epg->SetChannel(channel); - } + progressHandler->UpdateProgress(epg->Name(), ++iCounter, m_epgIdToEpgMap.size()); if ((!bOnlyPending || epg->UpdatePending()) && epg->Update(start, end, m_settings.GetIntValue(CSettings::SETTING_EPG_EPGUPDATE) * 60, bOnlyPending)) @@ -714,7 +717,7 @@ const CDateTime CPVREpgContainer::GetFirstEPGDate(void) CDateTime returnValue; m_critSection.lock(); - const auto epgs = m_epgs; + const auto epgs = m_epgIdToEpgMap; m_critSection.unlock(); for (const auto &epgEntry : epgs) @@ -732,7 +735,7 @@ const CDateTime CPVREpgContainer::GetLastEPGDate(void) CDateTime returnValue; m_critSection.lock(); - const auto epgs = m_epgs; + const auto epgs = m_epgIdToEpgMap; m_critSection.unlock(); for (const auto &epgEntry : epgs) @@ -752,7 +755,7 @@ int CPVREpgContainer::GetEPGSearch(CFileItemList &results, const CPVREpgSearchFi /* get filtered results from all tables */ { CSingleLock lock(m_critSection); - for (const auto &epgEntry : m_epgs) + for (const auto &epgEntry : m_epgIdToEpgMap) epgEntry.second->Get(results, filter); } @@ -778,7 +781,7 @@ bool CPVREpgContainer::CheckPlayingEvents(void) CDateTime::GetCurrentDateTime().GetAsUTCDateTime().GetAsTime(iNow); if (iNow >= iNextEpgActiveTagCheck) { - for (const auto &epgEntry : m_epgs) + for (const auto &epgEntry : m_epgIdToEpgMap) bFoundChanges = epgEntry.second->CheckPlayingEvent() || bFoundChanges; CDateTime::GetCurrentDateTime().GetAsUTCDateTime().GetAsTime(iNextEpgActiveTagCheck); @@ -815,7 +818,7 @@ void CPVREpgContainer::SetHasPendingUpdates(bool bHasPendingUpdates /* = true */ m_pendingUpdates = 0; } -void CPVREpgContainer::UpdateRequest(int iClientID, unsigned int iUniqueChannelID) +void CPVREpgContainer::UpdateRequest(int iClientID, int iUniqueChannelID) { CSingleLock lock(m_updateRequestsLock); m_updateRequests.emplace_back(CEpgUpdateRequest(iClientID, iUniqueChannelID)); diff --git a/xbmc/pvr/epg/EpgContainer.h b/xbmc/pvr/epg/EpgContainer.h index 0fbfb46d2d..af303da15d 100644 --- a/xbmc/pvr/epg/EpgContainer.h +++ b/xbmc/pvr/epg/EpgContainer.h @@ -8,6 +8,10 @@ #pragma once +#include +#include +#include + #include "XBDateTime.h" #include "threads/CriticalSection.h" #include "threads/Thread.h" @@ -22,6 +26,7 @@ class CFileItemList; namespace PVR { + class CPVREpgChannelData; class CEpgUpdateRequest; class CEpgTagStateChange; @@ -85,10 +90,12 @@ namespace PVR /*! * @brief Create the EPg for a given channel. - * @param channel The channel. + * @param iEpgId The EPG id. + * @param strScraperName The scraper name. + * @param channelData The channel data. * @return the created EPG */ - CPVREpgPtr CreateChannelEpg(const CPVRChannelPtr &channel); + std::shared_ptr CreateChannelEpg(int iEpgId, const std::string& strScraperName, const std::shared_ptr& channelData); /*! * @brief Get all EPG tables and apply a filter. @@ -111,19 +118,27 @@ namespace PVR const CDateTime GetLastEPGDate(void); /*! - * @brief Get an EPG table given it's ID. + * @brief Get an EPG given its ID. * @param iEpgId The database ID of the table. - * @return The table or NULL if it wasn't found. + * @return The EPG or nullptr if it wasn't found. */ CPVREpgPtr GetById(int iEpgId) const; + /*! + * @brief Get an EPG given its client id and channel uid. + * @param iClientId the id of the pvr client providing the EPG + * @param iChannelUid the uid of the channel for the EPG + * @return The EPG or nullptr if it wasn't found. + */ + std::shared_ptr GetByChannelUid(int iClientId, int iChannelUid) const; + /*! * @brief Get the EPG event with the given event id - * @param channel The channel to get the event for. - * @param iBroadcastId The event id to get + * @param epg The epg to lookup the event. + * @param iBroadcastId The event id to lookup. * @return The requested event, or an empty tag when not found */ - CPVREpgInfoTagPtr GetTagById(const CPVRChannelPtr &channel, unsigned int iBroadcastId) const; + std::shared_ptr GetTagById(const std::shared_ptr& epg, unsigned int iBroadcastId) const; /*! * @brief Check whether data should be persisted to the EPG database. @@ -142,7 +157,7 @@ namespace PVR * @param iClientID The id of the client which triggered the update request * @param iUniqueChannelID The uid of the channel for which the epg shall be updated */ - void UpdateRequest(int iClientID, unsigned int iUniqueChannelID); + void UpdateRequest(int iClientID, int iUniqueChannelID); /*! * @brief A client announced an updated epg tag for a channel @@ -175,7 +190,6 @@ namespace PVR */ void OnPlaybackStopped(const CFileItemPtr &item); - private: /*! * @brief Notify EPG table observers when the currently active tag changed. @@ -187,7 +201,7 @@ namespace PVR * @brief The next EPG ID to be given to a table when the db isn't being used. * @return The next ID. */ - unsigned int NextEpgId(void); + int NextEpgId(void); /*! * @brief Wait for an EPG update to finish. @@ -247,8 +261,10 @@ namespace PVR time_t m_iLastEpgCleanup = 0; /*!< the time the EPG was cleaned up */ time_t m_iNextEpgUpdate = 0; /*!< the time the EPG will be updated */ time_t m_iNextEpgActiveTagCheck = 0; /*!< the time the EPG will be checked for active tag updates */ - unsigned int m_iNextEpgId = 0; /*!< the next epg ID that will be given to a new table when the db isn't being used */ - std::map m_epgs; /*!< the EPGs in this container */ + int m_iNextEpgId = 0; /*!< the next epg ID that will be given to a new table when the db isn't being used */ + + std::map> m_epgIdToEpgMap; /*!< the EPGs in this container. maps epg ids to epgs */ + std::map, std::shared_ptr> m_channelUidToEpgMap; /*!< the EPGs in this container. maps channel uids to epgs */ mutable CCriticalSection m_critSection; /*!< a critical section for changes to this container */ CEvent m_updateEvent; /*!< trigger when an update finishes */ diff --git a/xbmc/pvr/epg/EpgDatabase.cpp b/xbmc/pvr/epg/EpgDatabase.cpp index 5cae646895..078c1ba95a 100644 --- a/xbmc/pvr/epg/EpgDatabase.cpp +++ b/xbmc/pvr/epg/EpgDatabase.cpp @@ -213,7 +213,7 @@ std::vector CPVREpgDatabase::Get(const CPVREpgContainer &container) std::string strName = m_pDS->fv("sName").get_asString().c_str(); std::string strScraperName = m_pDS->fv("sScraperName").get_asString().c_str(); - result.emplace_back(new CPVREpg(iEpgID, strName, strScraperName, true)); + result.emplace_back(new CPVREpg(iEpgID, strName, strScraperName)); m_pDS->next(); } m_pDS->close(); @@ -359,7 +359,7 @@ int CPVREpgDatabase::Persist(const CPVREpgInfoTag &tag, bool bSingleUpdate /* = if (tag.EpgID() <= 0) { - CLog::LogF(LOGERROR, "Tag '%s' does not have a valid table", tag.Title(true).c_str()); + CLog::LogF(LOGERROR, "Tag '%s' does not have a valid table", tag.Title().c_str()); return iReturn; } @@ -384,12 +384,12 @@ int CPVREpgDatabase::Persist(const CPVREpgInfoTag &tag, bool bSingleUpdate /* = "iEpisodeId, iEpisodePart, sEpisodeName, iFlags, sSeriesLink, iBroadcastUid) " "VALUES (%u, %u, %u, '%s', '%s', '%s', '%s', '%s', '%s', '%s', %i, '%s', '%s', %i, %i, '%s', %u, %i, %i, %i, %i, %i, %i, '%s', %i, '%s', %i);", tag.EpgID(), static_cast(iStartTime), static_cast(iEndTime), - tag.Title(true).c_str(), tag.PlotOutline(true).c_str(), tag.Plot(true).c_str(), - tag.OriginalTitle(true).c_str(), tag.DeTokenize(tag.Cast()).c_str(), tag.DeTokenize(tag.Directors()).c_str(), + tag.Title().c_str(), tag.PlotOutline().c_str(), tag.Plot().c_str(), + tag.OriginalTitle().c_str(), tag.DeTokenize(tag.Cast()).c_str(), tag.DeTokenize(tag.Directors()).c_str(), tag.DeTokenize(tag.Writers()).c_str(), tag.Year(), tag.IMDBNumber().c_str(), tag.Icon().c_str(), tag.GenreType(), tag.GenreSubType(), strGenre.c_str(), static_cast(iFirstAired), tag.ParentalRating(), tag.StarRating(), tag.Notify(), - tag.SeriesNumber(), tag.EpisodeNumber(), tag.EpisodePart(), tag.EpisodeName(true).c_str(), tag.Flags(), tag.SeriesLink().c_str(), + tag.SeriesNumber(), tag.EpisodeNumber(), tag.EpisodePart(), tag.EpisodeName().c_str(), tag.Flags(), tag.SeriesLink().c_str(), tag.UniqueBroadcastID()); } else @@ -400,12 +400,12 @@ int CPVREpgDatabase::Persist(const CPVREpgInfoTag &tag, bool bSingleUpdate /* = "iEpisodeId, iEpisodePart, sEpisodeName, iFlags, sSeriesLink, iBroadcastUid, idBroadcast) " "VALUES (%u, %u, %u, '%s', '%s', '%s', '%s', '%s', '%s', '%s', %i, '%s', '%s', %i, %i, '%s', %u, %i, %i, %i, %i, %i, %i, '%s', %i, '%s', %i, %i);", tag.EpgID(), static_cast(iStartTime), static_cast(iEndTime), - tag.Title(true).c_str(), tag.PlotOutline(true).c_str(), tag.Plot(true).c_str(), - tag.OriginalTitle(true).c_str(), tag.DeTokenize(tag.Cast()).c_str(), tag.DeTokenize(tag.Directors()).c_str(), + tag.Title().c_str(), tag.PlotOutline().c_str(), tag.Plot().c_str(), + tag.OriginalTitle().c_str(), tag.DeTokenize(tag.Cast()).c_str(), tag.DeTokenize(tag.Directors()).c_str(), tag.DeTokenize(tag.Writers()).c_str(), tag.Year(), tag.IMDBNumber().c_str(), tag.Icon().c_str(), tag.GenreType(), tag.GenreSubType(), strGenre.c_str(), static_cast(iFirstAired), tag.ParentalRating(), tag.StarRating(), tag.Notify(), - tag.SeriesNumber(), tag.EpisodeNumber(), tag.EpisodePart(), tag.EpisodeName(true).c_str(), tag.Flags(), tag.SeriesLink().c_str(), + tag.SeriesNumber(), tag.EpisodeNumber(), tag.EpisodePart(), tag.EpisodeName().c_str(), tag.Flags(), tag.SeriesLink().c_str(), tag.UniqueBroadcastID(), iBroadcastId); } diff --git a/xbmc/pvr/epg/EpgInfoTag.cpp b/xbmc/pvr/epg/EpgInfoTag.cpp index 1d63d9ab46..2287f8f122 100644 --- a/xbmc/pvr/epg/EpgInfoTag.cpp +++ b/xbmc/pvr/epg/EpgInfoTag.cpp @@ -12,9 +12,7 @@ #include "addons/PVRClient.h" #include "addons/kodi-addon-dev-kit/include/kodi/xbmc_pvr_types.h" #include "cores/DataCacheCore.h" -#include "guilib/LocalizeStrings.h" #include "settings/AdvancedSettings.h" -#include "settings/Settings.h" #include "settings/SettingsComponent.h" #include "utils/StringUtils.h" #include "utils/Variant.h" @@ -22,37 +20,60 @@ #include "pvr/PVRManager.h" #include "pvr/epg/Epg.h" +#include "pvr/epg/EpgChannelData.h" #include "pvr/epg/EpgContainer.h" #include "pvr/epg/EpgDatabase.h" using namespace PVR; -CPVREpgInfoTag::CPVREpgInfoTag(const CPVRChannelPtr &channel, CPVREpg *epg /* = nullptr */, const std::string &strTableName /* = "" */) -: m_iClientId(channel ? channel->ClientID() : -1), - m_iUniqueChannelID(channel ? channel->UniqueID() : PVR_CHANNEL_INVALID_UID), - m_strIconPath(channel ? channel->IconPath() : ""), - m_epg(epg), - m_channel(channel) +CPVREpgInfoTag::CPVREpgInfoTag() +: m_channelData(new CPVREpgChannelData) { +} + +CPVREpgInfoTag::CPVREpgInfoTag(const std::shared_ptr& channelData, int iEpgID) +: m_iEpgID(iEpgID) +{ + if (channelData) + m_channelData = channelData; + else + m_channelData = std::make_shared(); + UpdatePath(); } -CPVREpgInfoTag::CPVREpgInfoTag(const EPG_TAG &data, int iClientId) +CPVREpgInfoTag::CPVREpgInfoTag(const EPG_TAG& data, int iClientId, const std::shared_ptr& channelData, int iEpgID) : m_bNotify(data.bNotify), - m_iClientId(iClientId), m_iParentalRating(data.iParentalRating), m_iStarRating(data.iStarRating), m_iSeriesNumber(data.iSeriesNumber), m_iEpisodeNumber(data.iEpisodeNumber), m_iEpisodePart(data.iEpisodePartNumber), m_iUniqueBroadcastID(data.iUniqueBroadcastId), - m_iUniqueChannelID(data.iUniqueChannelId), m_iYear(data.iYear), m_startTime(data.startTime + CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_iPVRTimeCorrection), m_endTime(data.endTime + CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_iPVRTimeCorrection), m_firstAired(data.firstAired + CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_iPVRTimeCorrection), - m_iFlags(data.iFlags) + m_iFlags(data.iFlags), + m_iEpgID(iEpgID) { + if (channelData) + { + m_channelData = channelData; + + if (m_channelData->ClientId() != iClientId) + CLog::LogF(LOGERROR, "Client id mismatch (channel: %d, epg: %d)!", + m_channelData->ClientId(), iClientId); + if (m_channelData->UniqueClientChannelId() != static_cast(data.iUniqueChannelId)) + CLog::LogF(LOGERROR, "Channel uid mismatch (channel: %d, epg: %d)!", + m_channelData->UniqueClientChannelId(), data.iUniqueChannelId); + } + else + { + // provide minimalistic channel data until we get fully initialized later + m_channelData = std::make_shared(iClientId, data.iUniqueChannelId); + } + SetGenre(data.iGenreType, data.iGenreSubType, data.strGenreDescription); // explicit NULL check, because there is no implicit NULL constructor for std::string @@ -82,19 +103,21 @@ CPVREpgInfoTag::CPVREpgInfoTag(const EPG_TAG &data, int iClientId) UpdatePath(); } +void CPVREpgInfoTag::SetChannelData(const std::shared_ptr& data) +{ + CSingleLock lock(m_critSection); + if (data) + m_channelData = data; + else + m_channelData.reset(new CPVREpgChannelData); +} + bool CPVREpgInfoTag::operator ==(const CPVREpgInfoTag& right) const { if (this == &right) return true; - bool bChannelMatch = false; - { - CSingleLock lock(m_critSection); - bChannelMatch = (m_channel == right.m_channel); - } - return (bChannelMatch && - m_bNotify == right.m_bNotify && - m_iClientId == right.m_iClientId && + return (m_bNotify == right.m_bNotify && m_iDatabaseID == right.m_iDatabaseID && m_iGenreType == right.m_iGenreType && m_iGenreSubType == right.m_iGenreSubType && @@ -105,7 +128,6 @@ bool CPVREpgInfoTag::operator ==(const CPVREpgInfoTag& right) const m_iEpisodeNumber == right.m_iEpisodeNumber && m_iEpisodePart == right.m_iEpisodePart && m_iUniqueBroadcastID == right.m_iUniqueBroadcastID && - m_iUniqueChannelID == right.m_iUniqueChannelID && m_strTitle == right.m_strTitle && m_strPlotOutline == right.m_strPlotOutline && m_strPlot == right.m_strPlot && @@ -117,12 +139,14 @@ bool CPVREpgInfoTag::operator ==(const CPVREpgInfoTag& right) const m_strIMDBNumber == right.m_strIMDBNumber && m_genre == right.m_genre && m_strEpisodeName == right.m_strEpisodeName && + m_iEpgID == right.m_iEpgID && m_strIconPath == right.m_strIconPath && m_strFileNameAndPath == right.m_strFileNameAndPath && m_startTime == right.m_startTime && m_endTime == right.m_endTime && m_iFlags == right.m_iFlags && - m_strSeriesLink == right.m_strSeriesLink); + m_strSeriesLink == right.m_strSeriesLink && + m_channelData == right.m_channelData); } bool CPVREpgInfoTag::operator !=(const CPVREpgInfoTag& right) const @@ -136,7 +160,7 @@ bool CPVREpgInfoTag::operator !=(const CPVREpgInfoTag& right) const void CPVREpgInfoTag::Serialize(CVariant &value) const { value["broadcastid"] = m_iUniqueBroadcastID; - value["channeluid"] = m_iUniqueChannelID; + value["channeluid"] = m_channelData->UniqueClientChannelId(); value["parentalrating"] = m_iParentalRating; value["rating"] = m_iStarRating; value["title"] = m_strTitle; @@ -169,27 +193,26 @@ void CPVREpgInfoTag::Serialize(CVariant &value) const value["serieslink"] = m_strSeriesLink; } +int CPVREpgInfoTag::ClientID() const +{ + return m_channelData->ClientId(); +} + void CPVREpgInfoTag::ToSortable(SortItem& sortable, Field field) const { CSingleLock lock(m_critSection); - if (!m_channel) - return; - switch (field) { case FieldChannelName: - sortable[FieldChannelName] = m_channel->ChannelName(); + sortable[FieldChannelName] = m_channelData->ChannelName(); break; case FieldChannelNumber: - sortable[FieldChannelNumber] = m_channel->ChannelNumber().SortableChannelNumber(); + sortable[FieldChannelNumber] = m_channelData->SortableChannelNumber(); break; case FieldLastPlayed: - { - const CDateTime lastWatched(m_channel->LastWatched()); - sortable[FieldLastPlayed] = lastWatched.IsValid() ? lastWatched.GetAsDBDateTime() : StringUtils::Empty; + sortable[FieldLastPlayed] = m_channelData->LastWatched(); break; - } default: break; } @@ -197,7 +220,7 @@ void CPVREpgInfoTag::ToSortable(SortItem& sortable, Field field) const CDateTime CPVREpgInfoTag::GetCurrentPlayingTime() const { - if (CServiceBroker::GetPVRManager().GetPlayingChannel() == Channel()) + if (CServiceBroker::GetPVRManager().MatchPlayingChannel(ClientID(), UniqueChannelID())) { // start time valid? time_t startTime = CServiceBroker::GetDataCacheCore().GetStartTime(); @@ -274,9 +297,9 @@ int CPVREpgInfoTag::DatabaseID(void) const return m_iDatabaseID; } -unsigned int CPVREpgInfoTag::UniqueChannelID(void) const +int CPVREpgInfoTag::UniqueChannelID(void) const { - return m_iUniqueChannelID; + return m_channelData->UniqueClientChannelId(); } CDateTime CPVREpgInfoTag::StartAsUTC(void) const @@ -316,59 +339,24 @@ int CPVREpgInfoTag::GetDuration(void) const return end - start > 0 ? end - start : 3600; } -bool CPVREpgInfoTag::IsParentalLocked() const +std::string CPVREpgInfoTag::Title() const { - CPVRChannelPtr channel; - { - CSingleLock lock(m_critSection); - channel = m_channel; - } - - return channel && CServiceBroker::GetPVRManager().IsParentalLocked(channel); + return m_strTitle; } -std::string CPVREpgInfoTag::Title(bool bOverrideParental /* = false */) const +std::string CPVREpgInfoTag::PlotOutline() const { - std::string strTitle; - - if (!bOverrideParental && IsParentalLocked()) - strTitle = g_localizeStrings.Get(19266); // parental locked - else if (m_strTitle.empty() && !CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool(CSettings::SETTING_EPG_HIDENOINFOAVAILABLE)) - strTitle = g_localizeStrings.Get(19055); // no information available - else - strTitle = m_strTitle; - - return strTitle; + return m_strPlotOutline; } -std::string CPVREpgInfoTag::PlotOutline(bool bOverrideParental /* = false */) const +std::string CPVREpgInfoTag::Plot() const { - std::string retVal; - - if (bOverrideParental || !IsParentalLocked()) - retVal = m_strPlotOutline; - - return retVal; + return m_strPlot; } -std::string CPVREpgInfoTag::Plot(bool bOverrideParental /* = false */) const +std::string CPVREpgInfoTag::OriginalTitle() const { - std::string retVal; - - if (bOverrideParental || !IsParentalLocked()) - retVal = m_strPlot; - - return retVal; -} - -std::string CPVREpgInfoTag::OriginalTitle(bool bOverrideParental /* = false */) const -{ - std::string retVal; - - if (bOverrideParental || !IsParentalLocked()) - retVal = m_strOriginalTitle; - - return retVal; + return m_strOriginalTitle; } const std::vector CPVREpgInfoTag::Cast(void) const @@ -503,14 +491,9 @@ int CPVREpgInfoTag::EpisodePart(void) const return m_iEpisodePart; } -std::string CPVREpgInfoTag::EpisodeName(bool bOverrideParental /* = false */) const +std::string CPVREpgInfoTag::EpisodeName() const { - std::string retVal; - - if (bOverrideParental || !IsParentalLocked()) - retVal = m_strEpisodeName; - - return retVal; + return m_strEpisodeName; } std::string CPVREpgInfoTag::Icon(void) const @@ -523,120 +506,87 @@ std::string CPVREpgInfoTag::Path(void) const return m_strFileNameAndPath; } -void CPVREpgInfoTag::SetChannel(const CPVRChannelPtr &channel) -{ - CSingleLock lock(m_critSection); - m_channel = channel; - m_iClientId = m_channel ? m_channel->ClientID() : -1; - m_iUniqueChannelID = m_channel ? m_channel->UniqueID() : PVR_CHANNEL_INVALID_UID; -} - -bool CPVREpgInfoTag::HasChannel(void) const -{ - CSingleLock lock(m_critSection); - return m_channel != nullptr; -} - -const CPVRChannelPtr CPVREpgInfoTag::Channel() const -{ - CSingleLock lock(m_critSection); - return m_channel; -} - bool CPVREpgInfoTag::Update(const CPVREpgInfoTag &tag, bool bUpdateBroadcastId /* = true */) { - bool bChanged = false; - { - CSingleLock lock(m_critSection); - bChanged = (m_channel != tag.m_channel); - } + bool bChanged = ( + m_strTitle != tag.m_strTitle || + m_strPlotOutline != tag.m_strPlotOutline || + m_strPlot != tag.m_strPlot || + m_strOriginalTitle != tag.m_strOriginalTitle || + m_cast != tag.m_cast || + m_directors != tag.m_directors || + m_writers != tag.m_writers || + m_iYear != tag.m_iYear || + m_strIMDBNumber != tag.m_strIMDBNumber || + m_startTime != tag.m_startTime || + m_endTime != tag.m_endTime || + m_iGenreType != tag.m_iGenreType || + m_iGenreSubType != tag.m_iGenreSubType || + m_firstAired != tag.m_firstAired || + m_iParentalRating != tag.m_iParentalRating || + m_iStarRating != tag.m_iStarRating || + m_bNotify != tag.m_bNotify || + m_iEpisodeNumber != tag.m_iEpisodeNumber || + m_iEpisodePart != tag.m_iEpisodePart || + m_iSeriesNumber != tag.m_iSeriesNumber || + m_strEpisodeName != tag.m_strEpisodeName || + m_iUniqueBroadcastID != tag.m_iUniqueBroadcastID || + m_iEpgID != tag.m_iEpgID || + m_genre != tag.m_genre || + m_strIconPath != tag.m_strIconPath || + m_iFlags != tag.m_iFlags || + m_strSeriesLink != tag.m_strSeriesLink || + m_channelData != tag.m_channelData + ); + + if (bUpdateBroadcastId) + bChanged |= (m_iDatabaseID != tag.m_iDatabaseID); + if (bChanged) { - bChanged |= ( - m_iClientId != tag.m_iClientId || - m_strTitle != tag.m_strTitle || - m_strPlotOutline != tag.m_strPlotOutline || - m_strPlot != tag.m_strPlot || - m_strOriginalTitle != tag.m_strOriginalTitle || - m_cast != tag.m_cast || - m_directors != tag.m_directors || - m_writers != tag.m_writers || - m_iYear != tag.m_iYear || - m_strIMDBNumber != tag.m_strIMDBNumber || - m_startTime != tag.m_startTime || - m_endTime != tag.m_endTime || - m_iGenreType != tag.m_iGenreType || - m_iGenreSubType != tag.m_iGenreSubType || - m_firstAired != tag.m_firstAired || - m_iParentalRating != tag.m_iParentalRating || - m_iStarRating != tag.m_iStarRating || - m_bNotify != tag.m_bNotify || - m_iEpisodeNumber != tag.m_iEpisodeNumber || - m_iEpisodePart != tag.m_iEpisodePart || - m_iSeriesNumber != tag.m_iSeriesNumber || - m_strEpisodeName != tag.m_strEpisodeName || - m_iUniqueBroadcastID != tag.m_iUniqueBroadcastID || - m_iUniqueChannelID != tag.m_iUniqueChannelID || - EpgID() != tag.EpgID() || - m_genre != tag.m_genre || - m_strIconPath != tag.m_strIconPath || - m_iFlags != tag.m_iFlags || - m_strSeriesLink != tag.m_strSeriesLink - ); if (bUpdateBroadcastId) - bChanged |= (m_iDatabaseID != tag.m_iDatabaseID); - - if (bChanged) + m_iDatabaseID = tag.m_iDatabaseID; + + m_strTitle = tag.m_strTitle; + m_strPlotOutline = tag.m_strPlotOutline; + m_strPlot = tag.m_strPlot; + m_strOriginalTitle = tag.m_strOriginalTitle; + m_cast = tag.m_cast; + m_directors = tag.m_directors; + m_writers = tag.m_writers; + m_iYear = tag.m_iYear; + m_strIMDBNumber = tag.m_strIMDBNumber; + m_startTime = tag.m_startTime; + m_endTime = tag.m_endTime; + m_iGenreType = tag.m_iGenreType; + m_iGenreSubType = tag.m_iGenreSubType; + m_iEpgID = tag.m_iEpgID; + m_iFlags = tag.m_iFlags; + m_strSeriesLink = tag.m_strSeriesLink; + + if (m_iGenreType == EPG_GENRE_USE_STRING) { - if (bUpdateBroadcastId) - m_iDatabaseID = tag.m_iDatabaseID; - - m_iClientId = tag.m_iClientId; - m_strTitle = tag.m_strTitle; - m_strPlotOutline = tag.m_strPlotOutline; - m_strPlot = tag.m_strPlot; - m_strOriginalTitle = tag.m_strOriginalTitle; - m_cast = tag.m_cast; - m_directors = tag.m_directors; - m_writers = tag.m_writers; - m_iYear = tag.m_iYear; - m_strIMDBNumber = tag.m_strIMDBNumber; - m_startTime = tag.m_startTime; - m_endTime = tag.m_endTime; - m_iGenreType = tag.m_iGenreType; - m_iGenreSubType = tag.m_iGenreSubType; - m_epg = tag.m_epg; - m_iFlags = tag.m_iFlags; - m_strSeriesLink = tag.m_strSeriesLink; - - { - CSingleLock lock(m_critSection); - m_channel = tag.m_channel; - } - - if (m_iGenreType == EPG_GENRE_USE_STRING) - { - /* No type/subtype. Use the provided description */ - m_genre = tag.m_genre; - } - else - { - /* Determine genre description by type/subtype */ - m_genre = StringUtils::Split(CPVREpg::ConvertGenreIdToString(tag.m_iGenreType, tag.m_iGenreSubType), CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_videoItemSeparator); - } - m_firstAired = tag.m_firstAired; - m_iParentalRating = tag.m_iParentalRating; - m_iStarRating = tag.m_iStarRating; - m_bNotify = tag.m_bNotify; - m_iEpisodeNumber = tag.m_iEpisodeNumber; - m_iEpisodePart = tag.m_iEpisodePart; - m_iSeriesNumber = tag.m_iSeriesNumber; - m_strEpisodeName = tag.m_strEpisodeName; - m_iUniqueBroadcastID = tag.m_iUniqueBroadcastID; - m_iUniqueChannelID = tag.m_iUniqueChannelID; - m_strIconPath = tag.m_strIconPath; + /* No type/subtype. Use the provided description */ + m_genre = tag.m_genre; } + else + { + /* Determine genre description by type/subtype */ + m_genre = StringUtils::Split(CPVREpg::ConvertGenreIdToString(tag.m_iGenreType, tag.m_iGenreSubType), CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_videoItemSeparator); + } + m_firstAired = tag.m_firstAired; + m_iParentalRating = tag.m_iParentalRating; + m_iStarRating = tag.m_iStarRating; + m_bNotify = tag.m_bNotify; + m_iEpisodeNumber = tag.m_iEpisodeNumber; + m_iEpisodePart = tag.m_iEpisodePart; + m_iSeriesNumber = tag.m_iSeriesNumber; + m_strEpisodeName = tag.m_strEpisodeName; + m_iUniqueBroadcastID = tag.m_iUniqueBroadcastID; + m_strIconPath = tag.m_strIconPath; + m_channelData = tag.m_channelData; } + if (bChanged) UpdatePath(); @@ -669,7 +619,7 @@ bool CPVREpgInfoTag::Persist(bool bSingleUpdate /* = true */) std::vector CPVREpgInfoTag::GetEdl() const { std::vector edls; - const CPVRClientPtr client = CServiceBroker::GetPVRManager().GetClient(m_iClientId); + const std::shared_ptr client = CServiceBroker::GetPVRManager().GetClient(m_channelData->ClientId()); if (client && client->GetClientCapabilities().SupportsEpgTagEdl()) client->GetEpgTagEdl(shared_from_this(), edls); @@ -684,13 +634,19 @@ void CPVREpgInfoTag::UpdatePath(void) int CPVREpgInfoTag::EpgID(void) const { - return m_epg ? m_epg->EpgID() : -1; + return m_iEpgID; +} + +void CPVREpgInfoTag::SetEpgID(int iEpgID) +{ + m_iEpgID = iEpgID; + UpdatePath(); // Note: path contains epg id. } bool CPVREpgInfoTag::IsRecordable(void) const { bool bIsRecordable = false; - const CPVRClientPtr client = CServiceBroker::GetPVRManager().GetClient(m_iClientId); + const std::shared_ptr client = CServiceBroker::GetPVRManager().GetClient(m_channelData->ClientId()); if (!client || (client->IsRecordable(shared_from_this(), bIsRecordable) != PVR_ERROR_NO_ERROR)) { // event end time based fallback @@ -702,7 +658,7 @@ bool CPVREpgInfoTag::IsRecordable(void) const bool CPVREpgInfoTag::IsPlayable(void) const { bool bIsPlayable = false; - const CPVRClientPtr client = CServiceBroker::GetPVRManager().GetClient(m_iClientId); + const std::shared_ptr client = CServiceBroker::GetPVRManager().GetClient(m_channelData->ClientId()); if (!client || (client->IsPlayable(shared_from_this(), bIsPlayable) != PVR_ERROR_NO_ERROR)) { // fallback @@ -711,12 +667,6 @@ bool CPVREpgInfoTag::IsPlayable(void) const return bIsPlayable; } -void CPVREpgInfoTag::SetEpg(CPVREpg *epg) -{ - m_epg = epg; - UpdatePath(); // Note: path contains epg id. -} - bool CPVREpgInfoTag::IsSeries(void) const { if ((m_iFlags & EPG_TAG_FLAG_IS_SERIES) > 0 || SeriesNumber() > 0 || EpisodeNumber() > 0 || EpisodePart() > 0) @@ -725,6 +675,16 @@ bool CPVREpgInfoTag::IsSeries(void) const return false; } +bool CPVREpgInfoTag::IsRadio() const +{ + return m_channelData->IsRadio(); +} + +bool CPVREpgInfoTag::IsParentalLocked() const +{ + return m_channelData->IsLocked(); +} + const std::vector CPVREpgInfoTag::Tokenize(const std::string &str) { return StringUtils::Split(str.c_str(), EPG_STRING_TOKEN_SEPARATOR); diff --git a/xbmc/pvr/epg/EpgInfoTag.h b/xbmc/pvr/epg/EpgInfoTag.h index 9cb376e9a5..cf2088db7e 100644 --- a/xbmc/pvr/epg/EpgInfoTag.h +++ b/xbmc/pvr/epg/EpgInfoTag.h @@ -14,17 +14,17 @@ #include "XBDateTime.h" #include "addons/kodi-addon-dev-kit/include/kodi/xbmc_pvr_types.h" +#include "threads/CriticalSection.h" #include "utils/ISerializable.h" #include "utils/ISortable.h" #include "pvr/PVRTypes.h" -#include "pvr/channels/PVRChannel.h" class CVariant; namespace PVR { - class CPVREpg; + class CPVREpgChannelData; class CPVREpgInfoTag final : public ISerializable, public ISortable, public std::enable_shared_from_this { @@ -36,16 +36,23 @@ namespace PVR * @brief Create a new EPG infotag. * @param data The tag's data. * @param iClientId The client id. + * @param channelData The channel data. + * @param iEpgId The id of the EPG this tag belongs to. */ - CPVREpgInfoTag(const EPG_TAG &data, int iClientId); + CPVREpgInfoTag(const EPG_TAG& data, int iClientId, const std::shared_ptr& channelData, int iEpgID); /*! * @brief Create a new EPG infotag. - * @param channel The channel. - * @param epg The epg data. - * @param strTabelName The name of the epg database table. + * @param channelData The channel data. + * @param iEpgId The id of the EPG this tag belongs to. */ - CPVREpgInfoTag(const CPVRChannelPtr &channel, CPVREpg *epg = nullptr, const std::string &strTableName = ""); + CPVREpgInfoTag(const std::shared_ptr& channelData, int iEpgID); + + /*! + * @brief Set data for the channel linked to this EPG infotag. + * @param data The channel data. + */ + void SetChannelData(const std::shared_ptr& data); bool operator ==(const CPVREpgInfoTag& right) const; bool operator !=(const CPVREpgInfoTag& right) const; @@ -60,7 +67,7 @@ namespace PVR * @brief Get the identifier of the client that serves this event. * @return The identifier. */ - int ClientID(void) const { return m_iClientId; } + int ClientID() const; /*! * @brief Check if this event is currently active. @@ -99,10 +106,10 @@ namespace PVR int EpgID(void) const; /*! - * @brief Sets the EPG for this event. - * @param epg The epg. + * @brief Sets the EPG id for this event. + * @param iEpgID The EPG id. */ - void SetEpg(CPVREpg *epg); + void SetEpgID(int iEpgID); /*! * @brief Change the unique broadcast ID of this event. @@ -126,7 +133,7 @@ namespace PVR * @brief Get the unique ID of the channel associated with this event. * @return The unique channel ID. */ - unsigned int UniqueChannelID(void) const; + int UniqueChannelID(void) const; /*! * @brief Get the event's start time. @@ -166,31 +173,27 @@ namespace PVR /*! * @brief Get the title of this event. - * @param bOverrideParental True to override parental control, false to check it. * @return The title. */ - std::string Title(bool bOverrideParental = false) const; + std::string Title() const; /*! * @brief Get the plot outline of this event. - * @param bOverrideParental True to override parental control, false to check it. * @return The plot outline. */ - std::string PlotOutline(bool bOverrideParental = false) const; + std::string PlotOutline() const; /*! * @brief Get the plot of this event. - * @param bOverrideParental True to override parental control, false to check it. * @return The plot. */ - std::string Plot(bool bOverrideParental = false) const; + std::string Plot() const; /*! * @brief Get the original title of this event. - * @param bOverrideParental True to override parental control, false check it. * @return The original title. */ - std::string OriginalTitle(bool bOverrideParental = false) const; + std::string OriginalTitle() const; /*! * @brief Get the cast of this event. @@ -320,10 +323,9 @@ namespace PVR /*! * @brief The episode name of this event. - * @param bOverrideParental True to override parental control, false to check it. * @return The episode name. */ - std::string EpisodeName(bool bOverrideParental = false) const; + std::string EpisodeName() const; /*! * @brief Get the path to the icon for this event. @@ -349,24 +351,6 @@ namespace PVR */ bool IsPlayable(void) const; - /*! - * @brief Set the channel of this epg tag - * @param channel The channel - */ - void SetChannel(const CPVRChannelPtr &channel); - - /*! - * @brief Check whether this event has a channel. - * @return True if it has a channel, false if not. - */ - bool HasChannel(void) const; - - /*! - * @brief Get the channel for this event. - * @return The channel. - */ - const CPVRChannelPtr Channel(void) const; - /*! * @brief Persist this tag in the database. * @param bSingleUpdate True if this is a single update, false if more updates will follow. @@ -394,6 +378,18 @@ namespace PVR */ bool IsSeries() const; + /*! + * @brief Check whether this tag is associated with a radion or TV channel. + * @return True if this tag is associated with a radio channel, false otherwise. + */ + bool IsRadio() const; + + /*! + * @brief Check whether this event is parental locked. + * @return True if whether this event is parental locked, false otherwise. + */ + bool IsParentalLocked() const; + /*! * @brief Return the flags (EPG_TAG_FLAG_*) of this event as a bitfield. * @return the flags. @@ -415,17 +411,11 @@ namespace PVR static const std::string DeTokenize(const std::vector &tokens); private: - CPVREpgInfoTag() = default; + CPVREpgInfoTag(); CPVREpgInfoTag(const CPVREpgInfoTag &tag) = delete; CPVREpgInfoTag &operator =(const CPVREpgInfoTag &other) = delete; - /*! - * @brief Check whether this event is parental locked. - * @return True if whether this event is parental locked, false otherwise. - */ - bool IsParentalLocked() const; - /*! * @brief Change the genre of this event. * @param iGenreType The genre type ID. @@ -445,7 +435,6 @@ namespace PVR CDateTime GetCurrentPlayingTime(void) const; bool m_bNotify = false; /*!< notify on start */ - int m_iClientId = -1; /*!< client id */ int m_iDatabaseID = -1; /*!< database ID */ int m_iGenreType = 0; /*!< genre type */ int m_iGenreSubType = 0; /*!< genre subtype */ @@ -455,7 +444,6 @@ namespace PVR int m_iEpisodeNumber = 0; /*!< episode number */ int m_iEpisodePart = 0; /*!< episode part number */ unsigned int m_iUniqueBroadcastID = EPG_TAG_INVALID_UID; /*!< unique broadcast ID */ - unsigned int m_iUniqueChannelID = PVR_CHANNEL_INVALID_UID; /*!< unique channel ID */ std::string m_strTitle; /*!< title */ std::string m_strPlotOutline; /*!< plot outline */ std::string m_strPlot; /*!< plot */ @@ -476,7 +464,7 @@ namespace PVR std::string m_strSeriesLink; /*!< series link */ mutable CCriticalSection m_critSection; - CPVREpg *m_epg = nullptr; - CPVRChannelPtr m_channel; + std::shared_ptr m_channelData; + int m_iEpgID = -1; }; } diff --git a/xbmc/pvr/epg/EpgSearchFilter.cpp b/xbmc/pvr/epg/EpgSearchFilter.cpp index 7660fd43ab..fb88b9709a 100644 --- a/xbmc/pvr/epg/EpgSearchFilter.cpp +++ b/xbmc/pvr/epg/EpgSearchFilter.cpp @@ -111,9 +111,11 @@ bool CPVREpgSearchFilter::MatchSearchTerm(const CPVREpgInfoTagPtr &tag) const if (!m_strSearchTerm.empty()) { CTextSearch search(m_strSearchTerm, m_bIsCaseSensitive, SEARCH_DEFAULT_OR); - bReturn = search.Search(tag->Title()) || - search.Search(tag->PlotOutline()) || - (m_bSearchInDescription && search.Search(tag->Plot())); + bReturn = !CServiceBroker::GetPVRManager().IsParentalLocked(tag); + if (bReturn) + bReturn = search.Search(tag->Title()) || + search.Search(tag->PlotOutline()) || + (m_bSearchInDescription && search.Search(tag->Plot())); } return bReturn; @@ -136,11 +138,10 @@ bool CPVREpgSearchFilter::FilterEntry(const CPVREpgInfoTagPtr &tag) const MatchSearchTerm(tag) && MatchTimers(tag) && MatchRecordings(tag)) && - (!tag->HasChannel() || - (MatchChannelType(tag) && - MatchChannelNumber(tag) && - MatchChannelGroup(tag) && - MatchFreeToAir(tag))); + MatchChannelType(tag) && + MatchChannelNumber(tag) && + MatchChannelGroup(tag) && + MatchFreeToAir(tag); } int CPVREpgSearchFilter::RemoveDuplicates(CFileItemList &results) @@ -179,20 +180,17 @@ int CPVREpgSearchFilter::RemoveDuplicates(CFileItemList &results) bool CPVREpgSearchFilter::MatchChannelType(const CPVREpgInfoTagPtr &tag) const { - return (CServiceBroker::GetPVRManager().IsStarted() && tag->Channel()->IsRadio() == m_bIsRadio); + return tag && (tag->IsRadio() == m_bIsRadio); } bool CPVREpgSearchFilter::MatchChannelNumber(const CPVREpgInfoTagPtr &tag) const { bool bReturn(true); - if (m_channelNumber.IsValid() && CServiceBroker::GetPVRManager().IsStarted()) + if (m_channelNumber.IsValid()) { - CPVRChannelGroupPtr group = (m_iChannelGroup != EPG_SEARCH_UNSET) ? CServiceBroker::GetPVRManager().ChannelGroups()->GetByIdFromAll(m_iChannelGroup) : CServiceBroker::GetPVRManager().ChannelGroups()->GetGroupAllTV(); - if (!group) - group = CServiceBroker::GetPVRManager().ChannelGroups()->GetGroupAllTV(); - - bReturn = (m_channelNumber == group->GetChannelNumber(tag->Channel())); + const std::shared_ptr channel = CServiceBroker::GetPVRManager().ChannelGroups()->GetChannelForEpgTag(tag); + bReturn = channel && (m_channelNumber == channel->ChannelNumber()); } return bReturn; @@ -202,10 +200,14 @@ bool CPVREpgSearchFilter::MatchChannelGroup(const CPVREpgInfoTagPtr &tag) const { bool bReturn(true); - if (m_iChannelGroup != EPG_SEARCH_UNSET && CServiceBroker::GetPVRManager().IsStarted()) + if (m_iChannelGroup != EPG_SEARCH_UNSET) { CPVRChannelGroupPtr group = CServiceBroker::GetPVRManager().ChannelGroups()->GetByIdFromAll(m_iChannelGroup); - bReturn = (group && group->IsGroupMember(tag->Channel())); + if (group) + { + const std::shared_ptr channel = CServiceBroker::GetPVRManager().ChannelGroups()->GetChannelForEpgTag(tag); + bReturn = (channel && group->IsGroupMember(channel)); + } } return bReturn; @@ -213,7 +215,15 @@ bool CPVREpgSearchFilter::MatchChannelGroup(const CPVREpgInfoTagPtr &tag) const bool CPVREpgSearchFilter::MatchFreeToAir(const CPVREpgInfoTagPtr &tag) const { - return (!m_bFreeToAirOnly || !tag->Channel()->IsEncrypted()); + bool bReturn(true); + + if (m_bFreeToAirOnly) + { + const std::shared_ptr channel = CServiceBroker::GetPVRManager().ChannelGroups()->GetChannelForEpgTag(tag); + bReturn = (channel && !channel->IsEncrypted()); + } + + return bReturn; } bool CPVREpgSearchFilter::MatchTimers(const CPVREpgInfoTagPtr &tag) const diff --git a/xbmc/pvr/timers/PVRTimerInfoTag.cpp b/xbmc/pvr/timers/PVRTimerInfoTag.cpp index 4caa60aa93..df99d6ed5e 100644 --- a/xbmc/pvr/timers/PVRTimerInfoTag.cpp +++ b/xbmc/pvr/timers/PVRTimerInfoTag.cpp @@ -742,7 +742,7 @@ CPVRTimerInfoTagPtr CPVRTimerInfoTag::CreateFromEpg(const CPVREpgInfoTagPtr &tag CPVRTimerInfoTagPtr newTag(new CPVRTimerInfoTag()); /* check if a valid channel is set */ - CPVRChannelPtr channel = tag->Channel(); + const std::shared_ptr channel = CServiceBroker::GetPVRManager().ChannelGroups()->GetChannelForEpgTag(tag); if (!channel) { CLog::LogF(LOGERROR, "EPG tag has no channel"); @@ -754,7 +754,10 @@ CPVRTimerInfoTagPtr CPVRTimerInfoTag::CreateFromEpg(const CPVREpgInfoTagPtr &tag CDateTime newEnd = tag->EndAsUTC(); newTag->m_iClientIndex = PVR_TIMER_NO_CLIENT_INDEX; newTag->m_iParentClientIndex = PVR_TIMER_NO_PARENT; - newTag->m_strTitle = tag->Title().empty() ? channel->ChannelName() : tag->Title(); + if (!CServiceBroker::GetPVRManager().IsParentalLocked(tag)) + newTag->m_strTitle = tag->Title(); + if (newTag->m_strTitle.empty()) + newTag->m_strTitle = channel->ChannelName(); newTag->m_iClientChannelUid = channel->UniqueID(); newTag->m_iClientId = channel->ClientID(); newTag->m_bIsRadio = channel->IsRadio(); diff --git a/xbmc/pvr/timers/PVRTimers.cpp b/xbmc/pvr/timers/PVRTimers.cpp index 084fe231a4..3030ea6b87 100644 --- a/xbmc/pvr/timers/PVRTimers.cpp +++ b/xbmc/pvr/timers/PVRTimers.cpp @@ -695,34 +695,29 @@ CPVRTimerInfoTagPtr CPVRTimers::GetTimerForEpgTag(const CPVREpgInfoTagPtr &epgTa { if (epgTag) { - // try to find a matching timer for the tag. - const CPVRChannelPtr channel(epgTag->Channel()); - if (channel) - { - CSingleLock lock(m_critSection); + CSingleLock lock(m_critSection); - for (const auto &tagsEntry : m_tags) + for (const auto &tagsEntry : m_tags) + { + for (const auto &timersEntry : tagsEntry.second) { - for (const auto &timersEntry : tagsEntry.second) - { - if (timersEntry->IsTimerRule()) - continue; + if (timersEntry->IsTimerRule()) + continue; + + if (timersEntry->GetEpgInfoTag(false) == epgTag) + return timersEntry; - if (timersEntry->GetEpgInfoTag(false) == epgTag) + if (timersEntry->m_iClientChannelUid != PVR_CHANNEL_INVALID_UID && + timersEntry->m_iClientChannelUid == epgTag->UniqueChannelID()) + { + if (timersEntry->UniqueBroadcastID() != EPG_TAG_INVALID_UID && + timersEntry->UniqueBroadcastID() == epgTag->UniqueBroadcastID()) return timersEntry; - if (timersEntry->m_iClientChannelUid != PVR_CHANNEL_INVALID_UID && - timersEntry->m_iClientChannelUid == channel->UniqueID()) - { - if (timersEntry->UniqueBroadcastID() != EPG_TAG_INVALID_UID && - timersEntry->UniqueBroadcastID() == epgTag->UniqueBroadcastID()) - return timersEntry; - - if (timersEntry->m_bIsRadio == channel->IsRadio() && - timersEntry->StartAsUTC() <= epgTag->StartAsUTC() && - timersEntry->EndAsUTC() >= epgTag->EndAsUTC()) - return timersEntry; - } + if (timersEntry->m_bIsRadio == epgTag->IsRadio() && + timersEntry->StartAsUTC() <= epgTag->StartAsUTC() && + timersEntry->EndAsUTC() >= epgTag->EndAsUTC()) + return timersEntry; } } } diff --git a/xbmc/pvr/windows/GUIEPGGridContainer.cpp b/xbmc/pvr/windows/GUIEPGGridContainer.cpp index 9788afae44..432a695eeb 100644 --- a/xbmc/pvr/windows/GUIEPGGridContainer.cpp +++ b/xbmc/pvr/windows/GUIEPGGridContainer.cpp @@ -23,7 +23,7 @@ #include "utils/Variant.h" #include "pvr/channels/PVRChannel.h" -#include "pvr/epg/Epg.h" +#include "pvr/epg/EpgInfoTag.h" #include "pvr/windows/GUIEPGGridContainerModel.h" using namespace PVR; @@ -692,17 +692,14 @@ void CGUIEPGGridContainer::UpdateItems() newBlockIndex = m_gridModel->GetFirstEventBlock(prevSelectedEpgTag) + eventOffset; } - const CPVRChannelPtr channel(prevSelectedEpgTag->Channel()); - if (channel) - channelUid = channel->UniqueID(); - + channelUid = prevSelectedEpgTag->UniqueChannelID(); broadcastUid = prevSelectedEpgTag->UniqueBroadcastID(); } else // "gap" tag selected { const GridItem *currItem(GetItem(m_channelCursor)); if (currItem) - channelUid = currItem->item->GetEPGInfoTag()->Channel()->UniqueID(); + channelUid = currItem->item->GetEPGInfoTag()->UniqueChannelID(); const GridItem *prevItem(GetPrevItem(m_channelCursor)); if (prevItem) @@ -768,7 +765,8 @@ void CGUIEPGGridContainer::UpdateItems() newChannelIndex = iChannelIndex; } else if (newChannelIndex >= m_gridModel->ChannelItemsSize() || - m_gridModel->GetGridItem(newChannelIndex, newBlockIndex)->GetEPGInfoTag()->Channel() != prevSelectedEpgTag->Channel()) + (m_gridModel->GetGridItem(newChannelIndex, newBlockIndex)->GetEPGInfoTag()->UniqueChannelID() != prevSelectedEpgTag->UniqueChannelID() && + m_gridModel->GetGridItem(newChannelIndex, newBlockIndex)->GetEPGInfoTag()->ClientID() != prevSelectedEpgTag->ClientID())) { // default to first channel newChannelIndex = 0; diff --git a/xbmc/pvr/windows/GUIEPGGridContainerModel.cpp b/xbmc/pvr/windows/GUIEPGGridContainerModel.cpp index a085b2d05f..023fb7001d 100644 --- a/xbmc/pvr/windows/GUIEPGGridContainerModel.cpp +++ b/xbmc/pvr/windows/GUIEPGGridContainerModel.cpp @@ -16,7 +16,8 @@ #include "utils/log.h" #include "pvr/PVRManager.h" -#include "pvr/channels/PVRChannel.h" +#include "pvr/channels/PVRChannelGroupsContainer.h" +#include "pvr/epg/EpgChannelData.h" #include "pvr/epg/EpgInfoTag.h" class CGUIListItem; @@ -36,6 +37,20 @@ void CGUIEPGGridContainerModel::SetInvalid() ruler->SetInvalid(); } +std::shared_ptr CGUIEPGGridContainerModel::CreateGapItem(int iChannel) const +{ + const std::shared_ptr channel = m_channelItems[iChannel]->GetPVRChannelInfoTag(); + + std::shared_ptr gapTag; + const std::shared_ptr epg = channel->GetEPG(); + if (epg) + gapTag = std::make_shared(epg->GetChannelData(), epg->EpgID()); + else + gapTag = std::make_shared(std::make_shared(*channel), -1); + + return std::make_shared(gapTag); +} + void CGUIEPGGridContainerModel::Initialize(const std::unique_ptr &items, const CDateTime &gridStart, const CDateTime &gridEnd, int iRulerUnit, int iBlocksPerPage, float fBlockSize) { if (!m_channelItems.empty()) @@ -48,33 +63,36 @@ void CGUIEPGGridContainerModel::Initialize(const std::unique_ptr // Create programme & channel items m_programmeItems.reserve(items->Size()); CFileItemPtr fileItem; - int iLastChannelID = -1; + int iLastChannelUID = -1; + int iLastClientUID = -1; ItemsPtr itemsPointer; itemsPointer.start = 0; - CPVRChannelPtr channel; int j = 0; for (int i = 0; i < items->Size(); ++i) { fileItem = items->Get(i); - if (!fileItem->HasEPGInfoTag() || !fileItem->GetEPGInfoTag()->HasChannel()) + if (!fileItem->HasEPGInfoTag()) continue; m_programmeItems.emplace_back(fileItem); - channel = fileItem->GetEPGInfoTag()->Channel(); - if (!channel) - continue; - - int iCurrentChannelID = channel->ChannelID(); - if (iCurrentChannelID != iLastChannelID) + int iCurrentChannelUID = fileItem->GetEPGInfoTag()->UniqueChannelID(); + int iCurrentClientUID = fileItem->GetEPGInfoTag()->ClientID(); + if (iCurrentChannelUID != iLastChannelUID || iCurrentClientUID != iLastClientUID) { + iLastChannelUID = iCurrentChannelUID; + iLastClientUID = iCurrentClientUID; + + const std::shared_ptr channel = CServiceBroker::GetPVRManager().ChannelGroups()->GetChannelForEpgTag(fileItem->GetEPGInfoTag()); + if (!channel) + continue; + if (j > 0) { itemsPointer.stop = j - 1; m_epgItemsPtr.emplace_back(itemsPointer); itemsPointer.start = j; } - iLastChannelID = iCurrentChannelID; m_channelItems.emplace_back(CFileItemPtr(new CFileItem(channel))); } ++j; @@ -203,8 +221,7 @@ void CGUIEPGGridContainerModel::Initialize(const std::unique_ptr } else { - const CPVREpgInfoTagPtr gapTag(new CPVREpgInfoTag(m_channelItems[channel]->GetPVRChannelInfoTag())); - const CFileItemPtr gapItem(new CFileItem(gapTag)); + const std::shared_ptr gapItem = CreateGapItem(channel); for (int i = block + blockDelta; i >= block - itemSize + sizeDelta; --i) { m_gridIndex[channel][i].item = gapItem; @@ -227,9 +244,7 @@ void CGUIEPGGridContainerModel::Initialize(const std::unique_ptr } else { - const CPVREpgInfoTagPtr gapTag(new CPVREpgInfoTag(m_channelItems[channel]->GetPVRChannelInfoTag())); - const CFileItemPtr gapItem(new CFileItem(gapTag)); - m_gridIndex[channel][block].item = gapItem; + m_gridIndex[channel][block].item = CreateGapItem(channel); } m_gridIndex[channel][savedBlock].originWidth = fBlockSize; // size always 1 block here diff --git a/xbmc/pvr/windows/GUIEPGGridContainerModel.h b/xbmc/pvr/windows/GUIEPGGridContainerModel.h index 146ecbe2fe..e0ca295613 100644 --- a/xbmc/pvr/windows/GUIEPGGridContainerModel.h +++ b/xbmc/pvr/windows/GUIEPGGridContainerModel.h @@ -84,6 +84,7 @@ namespace PVR private: void FreeItemsMemory(); + std::shared_ptr CreateGapItem(int iChannel) const; struct ItemsPtr { diff --git a/xbmc/pvr/windows/GUIWindowPVRGuide.cpp b/xbmc/pvr/windows/GUIWindowPVRGuide.cpp index f22ca1db40..73ab97dd1d 100644 --- a/xbmc/pvr/windows/GUIWindowPVRGuide.cpp +++ b/xbmc/pvr/windows/GUIWindowPVRGuide.cpp @@ -26,6 +26,7 @@ #include "pvr/PVRGUIActions.h" #include "pvr/PVRManager.h" #include "pvr/channels/PVRChannelGroupsContainer.h" +#include "pvr/epg/EpgChannelData.h" #include "pvr/epg/EpgContainer.h" #include "pvr/recordings/PVRRecordings.h" #include "pvr/timers/PVRTimers.h" @@ -628,7 +629,9 @@ bool CGUIWindowPVRGuideBase::RefreshTimelineItems() for (const auto& groupMember : groupMembers) { // fake a channel without epg - const std::shared_ptr gapTag = std::make_shared(groupMember.channel); + + const std::shared_ptr gapTag + = std::make_shared(std::make_shared(*(groupMember.channel)), -1); timeline->Add(std::make_shared(gapTag)); } @@ -724,15 +727,15 @@ void CGUIWindowPVRGuideBase::OnInputDone() const CPVRChannelNumber channelNumber = GetChannelNumber(); if (channelNumber.IsValid()) { - for (const CFileItemPtr event : *m_vecItems) + CGUIEPGGridContainer* epgGridContainer = GetGridControl(); + if (epgGridContainer) { - const CPVREpgInfoTagPtr tag(event->GetEPGInfoTag()); - if (tag->HasChannel() && tag->Channel()->ChannelNumber() == channelNumber) + for (const std::shared_ptr& event : *m_vecItems) { - CGUIEPGGridContainer* epgGridContainer = GetGridControl(); - if (epgGridContainer) + const std::shared_ptr channel = CServiceBroker::GetPVRManager().ChannelGroups()->GetChannelForEpgTag(event->GetEPGInfoTag()); + if (channel && channel->ChannelNumber() == channelNumber) { - epgGridContainer->SetChannel(tag->Channel()); + epgGridContainer->SetChannel(channel); return; } } diff --git a/xbmc/pvr/windows/GUIWindowPVRSearch.cpp b/xbmc/pvr/windows/GUIWindowPVRSearch.cpp index 05a88a0fae..03b0e33c64 100644 --- a/xbmc/pvr/windows/GUIWindowPVRSearch.cpp +++ b/xbmc/pvr/windows/GUIWindowPVRSearch.cpp @@ -96,7 +96,7 @@ void CGUIWindowPVRSearchBase::SetItemToSearch(const CFileItemPtr &item) else { const CPVREpgInfoTagPtr epgTag(CPVRItem(item).GetEpgInfoTag()); - if (epgTag) + if (epgTag && !CServiceBroker::GetPVRManager().IsParentalLocked(epgTag)) m_searchfilter->SetSearchPhrase(epgTag->Title()); } -- cgit v1.2.3