aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--addons/resource.language.en_gb/resources/strings.po186
-rw-r--r--xbmc/FileItem.cpp36
-rw-r--r--xbmc/addons/PVRClient.cpp38
-rw-r--r--xbmc/addons/PVRClient.h5
-rw-r--r--xbmc/cores/VideoPlayer/Edl.cpp2
-rw-r--r--xbmc/interfaces/json-rpc/PVROperations.cpp9
-rw-r--r--xbmc/pvr/PVRContextMenus.cpp5
-rw-r--r--xbmc/pvr/PVRGUIActions.cpp8
-rw-r--r--xbmc/pvr/PVRGUIInfo.cpp22
-rw-r--r--xbmc/pvr/PVRGUITimesInfo.cpp5
-rw-r--r--xbmc/pvr/PVRItem.cpp8
-rw-r--r--xbmc/pvr/PVRManager.cpp38
-rw-r--r--xbmc/pvr/PVRManager.h21
-rw-r--r--xbmc/pvr/channels/PVRChannel.cpp57
-rw-r--r--xbmc/pvr/channels/PVRChannel.h3
-rw-r--r--xbmc/pvr/channels/PVRChannelGroup.cpp11
-rw-r--r--xbmc/pvr/channels/PVRChannelGroups.cpp2
-rw-r--r--xbmc/pvr/channels/PVRChannelGroupsContainer.cpp10
-rw-r--r--xbmc/pvr/channels/PVRChannelGroupsContainer.h7
-rw-r--r--xbmc/pvr/dialogs/GUIDialogPVRGuideInfo.cpp10
-rw-r--r--xbmc/pvr/epg/CMakeLists.txt6
-rw-r--r--xbmc/pvr/epg/Epg.cpp197
-rw-r--r--xbmc/pvr/epg/Epg.h39
-rw-r--r--xbmc/pvr/epg/EpgChannelData.cpp135
-rw-r--r--xbmc/pvr/epg/EpgChannelData.h67
-rw-r--r--xbmc/pvr/epg/EpgContainer.cpp151
-rw-r--r--xbmc/pvr/epg/EpgContainer.h40
-rw-r--r--xbmc/pvr/epg/EpgDatabase.cpp16
-rw-r--r--xbmc/pvr/epg/EpgInfoTag.cpp362
-rw-r--r--xbmc/pvr/epg/EpgInfoTag.h90
-rw-r--r--xbmc/pvr/epg/EpgSearchFilter.cpp46
-rw-r--r--xbmc/pvr/timers/PVRTimerInfoTag.cpp7
-rw-r--r--xbmc/pvr/timers/PVRTimers.cpp41
-rw-r--r--xbmc/pvr/windows/GUIEPGGridContainer.cpp12
-rw-r--r--xbmc/pvr/windows/GUIEPGGridContainerModel.cpp47
-rw-r--r--xbmc/pvr/windows/GUIEPGGridContainerModel.h1
-rw-r--r--xbmc/pvr/windows/GUIWindowPVRGuide.cpp17
-rw-r--r--xbmc/pvr/windows/GUIWindowPVRSearch.cpp2
38 files changed, 1042 insertions, 717 deletions
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<CPVREpgInfoTag>& 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<CPVRChannel> 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<CPVRChannel> 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<CPVREpgChannelData>& 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<CPVRClient*>(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<CPVREpgInfoTag>(*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<CPVREpgInfoTag> epgTag = std::make_shared<CPVREpgInfoTag>(*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<CPVREpgChannelData>& 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<CPVREpgInfoTag> epgTag = CServiceBroker::GetPVRManager().EpgContainer().GetTagById(std::shared_ptr<CPVREpg>(),
+ 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<CPVREpgInfoTag> epgTag = CServiceBroker::GetPVRManager().EpgContainer().GetTagById(std::shared_ptr<CPVREpg>(),
+ 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<CPVREpgInfoTag> epgTag = CServiceBroker::GetPVRManager().EpgContainer().GetTagById(std::shared_ptr<CPVREpg>(),
+ 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<CPVREpg> epg = recording->Channel() ? recording->Channel()->GetEPG() : nullptr;
+ const std::shared_ptr<CPVREpgInfoTag> 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<CPVRChannelGroupsContainer> groups = CServiceBroker::GetPVRManager().ChannelGroups();
+
CSingleLock lock(m_critSection);
- const CPVRChannelPtr playingChannel = m_playingEpgTag ? m_playingEpgTag->Channel() : nullptr;
+ const std::shared_ptr<CPVRChannel> 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<CPVRChannel> 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<CPVREpgInfoTag>& 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<CPVRChannel>& channel) const
+{
+ return channel &&
+ IsCurrentlyParentalLocked(channel, channel->IsLocked());
+}
+
+bool CPVRManager::IsCurrentlyParentalLocked(const std::shared_ptr<CPVRChannel>& channel, bool bGenerallyLocked) const
+{
+ bool bReturn = false;
+
+ if (!channel || !bGenerallyLocked)
return bReturn;
- CPVRChannelPtr currentChannel(GetPlayingChannel());
- if (// different channel
+ const std::shared_ptr<CPVRChannel> 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
@@ -240,6 +240,14 @@ namespace PVR
}
/*!
+ * @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<CPVRChannel>& 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<CPVREpgInfoTag>& epgTag) const;
/*!
* @brief Restart the parental timer.
@@ -509,6 +524,8 @@ namespace PVR
*/
void SetState(ManagerState state);
+ bool IsCurrentlyParentalLocked(const std::shared_ptr<CPVRChannel>& 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<CPVREpgChannelData>(*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<CPVREpg> 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<CPVREpg> 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<CPVREpg> 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<CPVREpg> 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<CPVREpg> 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<CPVREpg> 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<CPVREpg> 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<CPVREpg> 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<CPVRChannel>
+ 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<CPVREpgInfoTag>(channel);
+ if (epg)
+ epgTag = std::make_shared<CPVREpgInfoTag>(epg->GetChannelData(), epg->EpgID());
+ else
+ epgTag = std::make_shared<CPVREpgInfoTag>(std::make_shared<CPVREpgChannelData>(*channel), -1);
+
results.Add(std::make_shared<CFileItem>(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<CPVRChannelGroupPtr>::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<CPVRChannel> CPVRChannelGroupsContainer::GetChannelForEpgTag(const std::shared_ptr<CPVREpgInfoTag>& epgTag) const
+{
+ if (!epgTag)
+ return std::shared_ptr<CPVRChannel>();
+
+ 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
@@ -113,6 +113,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<CPVRChannel> GetChannelForEpgTag(const std::shared_ptr<CPVREpgInfoTag>& epgTag) const;
+
+ /*!
* @brief Get the groups list for a directory.
* @param strBase The directory path.
* @param results The file list to store the results in.
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<CPVRTimerInfoTag> 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<CPVREpgChannelData>& 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<CPVREpg>(channel)
- : std::make_shared<CPVREpg>(m_iEpgID, m_strName, m_strScraperName, false);
-
+ const std::shared_ptr<CPVREpg> tmpEpg = std::make_shared<CPVREpg>(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<CPVREpgInfoTag>(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<CPVREpgInfoTag>(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<CPVREpgInfoTag>(*data, iClientId);
+ const std::shared_ptr<CPVREpgInfoTag> tag = std::make_shared<CPVREpgInfoTag>(*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<CPVREpgInfoTag>(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<CPVREpgInfoTag>(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<CPVRClient> 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<CPVREpg>(channel)
- : std::make_shared<CPVREpg>(m_iEpgID, m_strName, m_strScraperName, false);
-
+ const std::shared_ptr<CPVREpg> tmpEpg = std::make_shared<CPVREpg>(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<CPVREpgChannelData> 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<CPVREpgChannelData>& 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<CPVREpgChannelData>& 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<CPVREpgChannelData> 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<CPVREpgChannelData>& 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<CPVREpgChannelData> 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 <ctime>
+#include <string>
+
+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 <utility>
-
#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<CPVREpg> 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<CPVREpg> 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<unsigned int>(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<CPVREpg> CPVREpgContainer::GetByChannelUid(int iClientId, int iChannelUid) const
+{
+ std::shared_ptr<CPVREpg> epg;
+
+ if (iClientId < 0 || iChannelUid < 0)
+ return epg;
+
+ CSingleLock lock(m_critSection);
+ const auto &epgEntry = m_channelUidToEpgMap.find(std::pair<int, int>(iClientId, iChannelUid));
+ if (epgEntry != m_channelUidToEpgMap.end())
+ epg = epgEntry->second;
+
+ return epg;
+}
+
+std::shared_ptr<CPVREpgInfoTag> CPVREpgContainer::GetTagById(const std::shared_ptr<CPVREpg>& 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<CPVREpgChannelData>& 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<unsigned int>(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<unsigned int>(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 <list>
+#include <map>
+#include <utility>
+
#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<CPVREpg> CreateChannelEpg(int iEpgId, const std::string& strScraperName, const std::shared_ptr<CPVREpgChannelData>& 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<CPVREpg> 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<CPVREpgInfoTag> GetTagById(const std::shared_ptr<CPVREpg>& 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<unsigned int, CPVREpgPtr> 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<int, std::shared_ptr<CPVREpg>> m_epgIdToEpgMap; /*!< the EPGs in this container. maps epg ids to epgs */
+ std::map<std::pair<int, int>, std::shared_ptr<CPVREpg>> 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<CPVREpgPtr> 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<unsigned int>(iStartTime), static_cast<unsigned int>(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<unsigned int>(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<unsigned int>(iStartTime), static_cast<unsigned int>(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<unsigned int>(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<CPVREpgChannelData>& channelData, int iEpgID)
+: m_iEpgID(iEpgID)
+{
+ if (channelData)
+ m_channelData = channelData;
+ else
+ m_channelData = std::make_shared<CPVREpgChannelData>();
+
UpdatePath();
}
-CPVREpgInfoTag::CPVREpgInfoTag(const EPG_TAG &data, int iClientId)
+CPVREpgInfoTag::CPVREpgInfoTag(const EPG_TAG& data, int iClientId, const std::shared_ptr<CPVREpgChannelData>& 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<int>(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<CPVREpgChannelData>(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<CPVREpgChannelData>& 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<std::string> 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<PVR_EDL_ENTRY> CPVREpgInfoTag::GetEdl() const
{
std::vector<PVR_EDL_ENTRY> edls;
- const CPVRClientPtr client = CServiceBroker::GetPVRManager().GetClient(m_iClientId);
+ const std::shared_ptr<CPVRClient> 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<CPVRClient> 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<CPVRClient> 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<std::string> 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<CPVREpgInfoTag>
{
@@ -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<CPVREpgChannelData>& 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<CPVREpgChannelData>& 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<CPVREpgChannelData>& 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.
@@ -350,24 +352,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.
* @return True if the tag was persisted correctly, false otherwise.
@@ -395,6 +379,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,18 +411,12 @@ namespace PVR
static const std::string DeTokenize(const std::vector<std::string> &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.
* @param iGenreSubType The genre subtype 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<CPVREpgChannelData> 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<CPVRChannel> 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<CPVRChannel> 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<CPVRChannel> 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<CPVRChannel> 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<CFileItem> CGUIEPGGridContainerModel::CreateGapItem(int iChannel) const
+{
+ const std::shared_ptr<CPVRChannel> channel = m_channelItems[iChannel]->GetPVRChannelInfoTag();
+
+ std::shared_ptr<CPVREpgInfoTag> gapTag;
+ const std::shared_ptr<CPVREpg> epg = channel->GetEPG();
+ if (epg)
+ gapTag = std::make_shared<CPVREpgInfoTag>(epg->GetChannelData(), epg->EpgID());
+ else
+ gapTag = std::make_shared<CPVREpgInfoTag>(std::make_shared<CPVREpgChannelData>(*channel), -1);
+
+ return std::make_shared<CFileItem>(gapTag);
+}
+
void CGUIEPGGridContainerModel::Initialize(const std::unique_ptr<CFileItemList> &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<CFileItemList>
// 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<CPVRChannel> 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<CFileItemList>
}
else
{
- const CPVREpgInfoTagPtr gapTag(new CPVREpgInfoTag(m_channelItems[channel]->GetPVRChannelInfoTag()));
- const CFileItemPtr gapItem(new CFileItem(gapTag));
+ const std::shared_ptr<CFileItem> 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<CFileItemList>
}
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<CFileItem> 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<CPVREpgInfoTag> gapTag = std::make_shared<CPVREpgInfoTag>(groupMember.channel);
+
+ const std::shared_ptr<CPVREpgInfoTag> gapTag
+ = std::make_shared<CPVREpgInfoTag>(std::make_shared<CPVREpgChannelData>(*(groupMember.channel)), -1);
timeline->Add(std::make_shared<CFileItem>(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<CFileItem>& event : *m_vecItems)
{
- CGUIEPGGridContainer* epgGridContainer = GetGridControl();
- if (epgGridContainer)
+ const std::shared_ptr<CPVRChannel> 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());
}