aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.codedocs2
-rw-r--r--.github/triage.yml2
-rw-r--r--addons/resource.language.en_gb/resources/strings.po186
-rw-r--r--addons/skin.estouchy/xml/MyWeather.xml12
-rw-r--r--addons/skin.estuary/xml/Variables.xml4
-rw-r--r--docs/CODE_GUIDELINES.md4
-rw-r--r--docs/doxygen/CODING_GUIDELINES.dox414
-rw-r--r--docs/doxygen/Doxyfile.doxy2
-rw-r--r--tools/depends/target/ffmpeg/FFMPEG-VERSION2
-rw-r--r--xbmc/FileItem.cpp36
-rw-r--r--xbmc/addons/PVRClient.cpp40
-rw-r--r--xbmc/addons/PVRClient.h5
-rw-r--r--xbmc/addons/kodi-addon-dev-kit/doxygen/Doxyfile1
-rw-r--r--xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecAndroidMediaCodec.cpp8
-rw-r--r--xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.cpp29
-rw-r--r--xbmc/cores/VideoPlayer/Edl.cpp2
-rw-r--r--xbmc/cores/VideoPlayer/VideoPlayerVideo.cpp2
-rw-r--r--xbmc/filesystem/CurlFile.cpp2
-rw-r--r--xbmc/games/controllers/windows/GUIControllerWindow.cpp4
-rw-r--r--xbmc/interfaces/json-rpc/PVROperations.cpp25
-rw-r--r--xbmc/music/MusicDatabase.cpp13
-rw-r--r--xbmc/peripherals/devices/PeripheralCecAdapter.cpp2
-rw-r--r--xbmc/platform/android/activity/XBMCApp.cpp44
-rw-r--r--xbmc/pvr/PVRContextMenus.cpp22
-rw-r--r--xbmc/pvr/PVRDatabase.cpp2
-rw-r--r--xbmc/pvr/PVRGUIActions.cpp57
-rw-r--r--xbmc/pvr/PVRGUIInfo.cpp82
-rw-r--r--xbmc/pvr/PVRGUITimerInfo.cpp23
-rw-r--r--xbmc/pvr/PVRGUITimerInfo.h21
-rw-r--r--xbmc/pvr/PVRGUITimesInfo.cpp5
-rw-r--r--xbmc/pvr/PVRItem.cpp23
-rw-r--r--xbmc/pvr/PVRManager.cpp40
-rw-r--r--xbmc/pvr/PVRManager.h21
-rw-r--r--xbmc/pvr/addons/PVRClients.cpp3
-rw-r--r--xbmc/pvr/channels/PVRChannel.cpp124
-rw-r--r--xbmc/pvr/channels/PVRChannel.h40
-rw-r--r--xbmc/pvr/channels/PVRChannelGroup.cpp88
-rw-r--r--xbmc/pvr/channels/PVRChannelGroup.h36
-rw-r--r--xbmc/pvr/channels/PVRChannelGroupInternal.cpp27
-rw-r--r--xbmc/pvr/channels/PVRChannelGroupInternal.h11
-rw-r--r--xbmc/pvr/channels/PVRChannelGroups.cpp31
-rw-r--r--xbmc/pvr/channels/PVRChannelGroups.h18
-rw-r--r--xbmc/pvr/channels/PVRChannelGroupsContainer.cpp10
-rw-r--r--xbmc/pvr/channels/PVRChannelGroupsContainer.h7
-rw-r--r--xbmc/pvr/dialogs/GUIDialogPVRChannelGuide.cpp7
-rw-r--r--xbmc/pvr/dialogs/GUIDialogPVRChannelsOSD.cpp6
-rw-r--r--xbmc/pvr/dialogs/GUIDialogPVRGuideInfo.cpp25
-rw-r--r--xbmc/pvr/epg/CMakeLists.txt6
-rw-r--r--xbmc/pvr/epg/Epg.cpp336
-rw-r--r--xbmc/pvr/epg/Epg.h99
-rw-r--r--xbmc/pvr/epg/EpgChannelData.cpp135
-rw-r--r--xbmc/pvr/epg/EpgChannelData.h67
-rw-r--r--xbmc/pvr/epg/EpgContainer.cpp223
-rw-r--r--xbmc/pvr/epg/EpgContainer.h62
-rw-r--r--xbmc/pvr/epg/EpgDatabase.cpp34
-rw-r--r--xbmc/pvr/epg/EpgDatabase.h15
-rw-r--r--xbmc/pvr/epg/EpgInfoTag.cpp445
-rw-r--r--xbmc/pvr/epg/EpgInfoTag.h151
-rw-r--r--xbmc/pvr/epg/EpgSearchFilter.cpp85
-rw-r--r--xbmc/pvr/epg/EpgSearchFilter.h11
-rw-r--r--xbmc/pvr/recordings/PVRRecording.cpp50
-rw-r--r--xbmc/pvr/recordings/PVRRecording.h11
-rw-r--r--xbmc/pvr/recordings/PVRRecordings.cpp31
-rw-r--r--xbmc/pvr/timers/CMakeLists.txt2
-rw-r--r--xbmc/pvr/timers/PVRTimerInfoTag.cpp142
-rw-r--r--xbmc/pvr/timers/PVRTimerInfoTag.h31
-rw-r--r--xbmc/pvr/timers/PVRTimers.cpp246
-rw-r--r--xbmc/pvr/timers/PVRTimers.h77
-rw-r--r--xbmc/pvr/timers/PVRTimersPath.cpp83
-rw-r--r--xbmc/pvr/timers/PVRTimersPath.h46
-rw-r--r--xbmc/pvr/windows/GUIEPGGridContainer.cpp16
-rw-r--r--xbmc/pvr/windows/GUIEPGGridContainer.h2
-rw-r--r--xbmc/pvr/windows/GUIEPGGridContainerModel.cpp47
-rw-r--r--xbmc/pvr/windows/GUIEPGGridContainerModel.h1
-rw-r--r--xbmc/pvr/windows/GUIViewStatePVR.cpp2
-rw-r--r--xbmc/pvr/windows/GUIWindowPVRBase.cpp6
-rw-r--r--xbmc/pvr/windows/GUIWindowPVRGuide.cpp79
-rw-r--r--xbmc/pvr/windows/GUIWindowPVRGuide.h4
-rw-r--r--xbmc/pvr/windows/GUIWindowPVRSearch.cpp27
-rw-r--r--xbmc/pvr/windows/GUIWindowPVRSearch.h2
-rw-r--r--xbmc/pvr/windows/GUIWindowPVRTimerRules.cpp2
-rw-r--r--xbmc/pvr/windows/GUIWindowPVRTimers.cpp2
-rw-r--r--xbmc/pvr/windows/GUIWindowPVRTimersBase.cpp3
-rw-r--r--xbmc/utils/Observer.h1
-rw-r--r--xbmc/windowing/X11/GLContextEGL.cpp4
-rw-r--r--xbmc/windowing/android/WinSystemAndroid.cpp32
-rw-r--r--xbmc/windowing/android/WinSystemAndroid.h2
87 files changed, 1943 insertions, 2247 deletions
diff --git a/.codedocs b/.codedocs
index 9c0590eb1d..63407e0ff3 100644
--- a/.codedocs
+++ b/.codedocs
@@ -5,5 +5,5 @@ DOXYFILE = docs/doxygen/Doxyfile.doxy
PROJECT_LOGO = docs/doxygen/Thumbnail-symbol-whitebg-small.jpg
INPUT= xbmc \
- docs/doxygen/CODING_GUIDELINES.dox \
+ docs/CODE_GUIDELINES.md \
docs/doxygen
diff --git a/.github/triage.yml b/.github/triage.yml
new file mode 100644
index 0000000000..857bcd4ed7
--- /dev/null
+++ b/.github/triage.yml
@@ -0,0 +1,2 @@
+label: "Triage: Needed"
+enabled: true
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/addons/skin.estouchy/xml/MyWeather.xml b/addons/skin.estouchy/xml/MyWeather.xml
index 3e84723ffd..f097c82361 100644
--- a/addons/skin.estouchy/xml/MyWeather.xml
+++ b/addons/skin.estouchy/xml/MyWeather.xml
@@ -294,7 +294,7 @@
<posx>100</posx>
<posy>70</posy>
<width>200</width>
- <height>30</height>
+ <height>34</height>
<font>font22</font>
<selectedcolor>selected</selectedcolor>
<align>center</align>
@@ -306,13 +306,13 @@
<posx>210</posx>
<posy>70</posy>
<width>200</width>
- <height>30</height>
+ <height>34</height>
<font>font22</font>
<selectedcolor>selected</selectedcolor>
<align>center</align>
<aligny>center</aligny>
<label>[COLOR=grey]$LOCALIZE[418][/COLOR][CR][B]$INFO[ListItem.Property(LowTemp)][/B]$INFO[ListItem.Property(TempUnits)]</label>
- <visible>!String.IsEmpty(ListItem.Property(HighTemp))</visible>
+ <visible>!String.IsEmpty(ListItem.Property(LowTemp))</visible>
</control>
<control type="textbox">
<posx>20</posx>
@@ -355,7 +355,7 @@
<posx>100</posx>
<posy>70</posy>
<width>200</width>
- <height>30</height>
+ <height>34</height>
<font>font22</font>
<selectedcolor>selected</selectedcolor>
<align>center</align>
@@ -367,13 +367,13 @@
<posx>210</posx>
<posy>70</posy>
<width>200</width>
- <height>30</height>
+ <height>34</height>
<font>font22</font>
<selectedcolor>selected</selectedcolor>
<align>center</align>
<aligny>center</aligny>
<label>[COLOR=grey]$LOCALIZE[418][/COLOR][CR][B]$INFO[ListItem.Property(LowTemp)][/B]$INFO[ListItem.Property(TempUnits)]</label>
- <visible>!String.IsEmpty(ListItem.Property(HighTemp))</visible>
+ <visible>!String.IsEmpty(ListItem.Property(LowTemp))</visible>
</control>
<control type="textbox">
<posx>20</posx>
diff --git a/addons/skin.estuary/xml/Variables.xml b/addons/skin.estuary/xml/Variables.xml
index 78e1421301..2da53aab5f 100644
--- a/addons/skin.estuary/xml/Variables.xml
+++ b/addons/skin.estuary/xml/Variables.xml
@@ -271,14 +271,14 @@
<variable name="NowPlayingBreadcrumbsVar">
<value condition="VideoPlayer.Content(livetv)">$INFO[VideoPlayer.Title]</value>
<value condition="VideoPlayer.Content(episodes) + !String.IsEmpty(Player.Art(tvshow.clearlogo))">$INFO[VideoPlayer.Season,[COLOR button_focus]S,[/COLOR]]$INFO[VideoPlayer.Episode,[COLOR button_focus]E,: [/COLOR]]$INFO[VideoPlayer.Title]</value>
- <value condition="Window.IsActive(fullscreenvideo)">$INFO[VideoPlayer.Title]$INFO[VideoPlayer.Year, ([COLOR button_focus],[/COLOR])]</value>
+ <value condition="Window.IsActive(fullscreenvideo)">$INFO[VideoPlayer.TVShowTitle]$INFO[VideoPlayer.Year, ([COLOR button_focus],[/COLOR])]</value>
<value condition="MusicPartyMode.Enabled">$LOCALIZE[589]</value>
<value>$LOCALIZE[31000]...</value>
</variable>
<variable name="OSDSubLabelVar">
<value condition="Window.IsActive(visualisation) + Integer.IsGreater(Playlist.Length,1) + Integer.IsGreater(Playlist.Position,0)">$LOCALIZE[554] $INFO[Playlist.Position] / $INFO[Playlist.Length]</value>
<value condition="VideoPlayer.Content(musicvideos)">$INFO[VideoPlayer.Artist]$INFO[VideoPlayer.Album, - ]</value>
- <value condition="VideoPlayer.Content(episodes)">$INFO[VideoPlayer.Season,[COLOR button_focus]S,[/COLOR]]$INFO[VideoPlayer.Episode,[COLOR button_focus]E,: [/COLOR]]$INFO[VideoPlayer.TVShowTitle]</value>
+ <value condition="VideoPlayer.Content(episodes)">$INFO[VideoPlayer.Season,[COLOR button_focus]S,[/COLOR]]$INFO[VideoPlayer.Episode,[COLOR button_focus]E,: [/COLOR]]$INFO[VideoPlayer.Title]</value>
<value condition="VideoPlayer.Content(LiveTV) | PVR.IsPlayingRecording | PVR.IsPlayingEpgTag">$INFO[VideoPlayer.ChannelNumberLabel,([COLOR button_focus],[/COLOR]) ]$INFO[VideoPlayer.ChannelName] $INFO[VideoPlayer.EpisodeName, - ]</value>
<value>$INFO[VideoPlayer.Genre]</value>
</variable>
diff --git a/docs/CODE_GUIDELINES.md b/docs/CODE_GUIDELINES.md
index 8e2c421363..81c235f48e 100644
--- a/docs/CODE_GUIDELINES.md
+++ b/docs/CODE_GUIDELINES.md
@@ -1,7 +1,7 @@
-![Kodi Logo](resources/banner_slim.png)
-
# Code Guidelines
+![Kodi Logo](https://github.com/xbmc/xbmc/raw/master/docs/resources/banner_slim.png)
+
## Table of Contents
* [1. Motivation](#1-motivation)
* [2. Language standard](#2-language-standard)
diff --git a/docs/doxygen/CODING_GUIDELINES.dox b/docs/doxygen/CODING_GUIDELINES.dox
deleted file mode 100644
index bd22c1b168..0000000000
--- a/docs/doxygen/CODING_GUIDELINES.dox
+++ /dev/null
@@ -1,414 +0,0 @@
-/*!
-
-\page code_guidelines Code guidelines and formatting conventions
-
-@brief \doc_header{ Code guidelines and formatting conventions }
-
-\tableofcontents
-
-When working in a large group, the two most important values are readability
-and maintainability. We code for other people, not computers. To accomplish
-these goals, we have created a unified set of code conventions.
-
-Conventions can be bent or broken in the interest of making code more readable
-and maintainable. However, if you submit a patch that contains excessive style
-conflicts, you may be asked to improve your code before your pull request is
-reviewed.
-
-================================================================================
-\section code_guidelines_1 Indentation
-
-Use spaces as tab policy with an indentation size of 2
-
---------------------------------------------------------------------------------
-\subsection code_guidelines_1_1 Statements
-
-No multiple statements on a single line, like this:
-~~~~~~~~~~~~~
-std::vector<std::string> test; test.push_back("foobar"); // This is the bad way
-~~~~~~~~~~~~~
-
-Always use a new line for a new statement:
-~~~~~~~~~~~~~
-std::vector<std::string> test;
-test.push_back("foobar");
-~~~~~~~~~~~~~
-
-With them becomes it much more easy for debugging of faults to see direct on the
-line what has created the fault.
-
-
---------------------------------------------------------------------------------
-\subsection code_guidelines_1_2 Namespaces
-
-Namespaces are not required to use any indentation to simplify nested namespaces
-and wrapping `.cpp` files in a namespace
-
-~~~~~~~~~~~~~
-namespace KODI
-{
-namespace UTILS
-{
-class ILogger
-{
- void Log(...) = 0;
-}
-}
-}
-~~~~~~~~~~~~~
-
-\subsection code_guidelines_1_3 Headers
-
-Included header files have to be sorted alphabetically to prevent duplicates and
-allow better overview, with an empty line clearly separating sections.
-
-Header order has to be:
-
-- Own header file
-- Other Kodi includes
-- C and C++ system files
-- Other libraries' header files
-
-~~~~~~~~~~~~~
-#include "PVRManager.h"
-
-#include "addons/AddonInstaller.h"
-#include "dialogs/GUIDialogExtendedProgressBar.h"
-#include "messaging/helpers/DialogHelper.h"
-#include "messaging/ApplicationMessenger.h"
-#include "messaging/ThreadMessage.h"
-#include "music/tags/MusicInfoTag.h"
-#include "music/MusicDatabase.h"
-#include "network/Network.h"
-#include "pvr/addons/PVRClients.h"
-#include "pvr/channels/PVRChannel.h"
-#include "settings/Settings.h"
-#include "threads/SingleLock.h"
-#include "utils/JobManager.h"
-#include "utils/log.h"
-#include "utils/Variant.h"
-#include "video/VideoDatabase.h"
-#include "Application.h"
-#include "ServiceBroker.h"
-
-#include <cassert>
-#include <utility>
-
-#include <libavutil/pixfmt.h>
-~~~~~~~~~~~~~
-
-Place directories before files. If the headers aren't sorted, either do your best
-to match the existing order, or precede your commit with an alphabetization commit.
-
-If possible, avoid including headers in another header. Instead, you can
-forward-declare the class and use a `std::unique_ptr`:
-
-~~~~~~~~~~~~~
-class CFileItem;
-
-class Example
-{
- ...
- std::unique_ptr<CFileItem> m_fileItem;
-}
-~~~~~~~~~~~~~
-
-================================================================================
-\section code_guidelines_2 Braces
-
-Braces have to go to a new line.
-
-~~~~~~~~~~~~~
-if (int i = 0; i < t; i++)
-{
- [...]
-}
-else
-{
- [...]
-}
-
-class Dummy()
-{
- [...]
-}
-~~~~~~~~~~~~~
-
-================================================================================
-\section code_guidelines_3 Whitespaces
-
-Conventional operators have to be surrounded by a whitespace.
-
-~~~~~~~~~~~~~
-a = (b + c) * d;
-~~~~~~~~~~~~~
-
-Reserved words have to be separated from opening parentheses by a whitespace.
-
-~~~~~~~~~~~~~
-while (true)
-for (int i = 0; i < x; ++i)
-~~~~~~~~~~~~~
-
-Commas have to be followed by a whitespace.
-
-~~~~~~~~~~~~~
-void Dummy::Method(int a, int b, int c);
-int d, e;
-~~~~~~~~~~~~~
-
-Semicolons have to be followed by a newline.
-
-~~~~~~~~~~~~~
-for (int i = 0; i < x; ++i)
-doSomething(e);
-doSomething(f);
-~~~~~~~~~~~~~
-
-Initializer lists have spaces between elements, but no surrounding spaces.
-
-~~~~~~~~~~~~~
-const char *aStringArray[] = {"one", "two", "three"};
-~~~~~~~~~~~~~
-
---------------------------------------------------------------------------------
-\subsection code_guidelines_3_1 No vertical alignment
-
-Do not use whitespaces to align value names together. This causes problems
-on code review if one needs to realign all values to their new position.
-
-Wrong:
-~~~~~~~~~~~~~
-...
-
-int value1 = 0;
-int value2 = 0;
-CExampleClass *exampleClass = nullptr;
-CBiggerExampleClass *biggerExampleClass = nullptr;
-
-exampleClass = new CExampleClass (value1, value2);
-biggerExampleClass = new CBiggerExampleClass(value1, value2);
-
-exampleClass ->InitExample();
-biggerExampleClass->InitExample();
-
-...
-~~~~~~~~~~~~~
-
-Right:
-~~~~~~~~~~~~~
-...
-
-int value1 = 0;
-int value2 = 0;
-CExampleClass *exampleClass = nullptr;
-CBiggerExampleClass *biggerExampleClass = nullptr;
-
-exampleClass = new CExampleClass(value1, value2);
-biggerExampleClass = new CBiggerExampleClass(value1, value2);
-
-exampleClass->InitExample();
-biggerExampleClass->InitExample();
-
-...
-~~~~~~~~~~~~~
-
-================================================================================
-\section code_guidelines_4 Control statements
-
-Insert new line before
-
-- else in an if statement
-- catch in a try statement
-- while in a do statement
-
-
---------------------------------------------------------------------------------
-\subsection code_guidelines_4_1 if else
-
-- put then statement, return or throw to new line
-- keep else if on one line
-
-~~~~~~~~~~~~~
-if (true)
- return;
-
-if (true)
-{
- [...]
-}
-else if (false)
-{
- return;
-}
-else
- return;
-~~~~~~~~~~~~~
-
---------------------------------------------------------------------------------
-\subsection code_guidelines_4_2 switch / case
-
-~~~~~~~~~~~~~
-switch (cmd)
-{
- case x:
- {
- doSomething();
- break;
- }
- case x:
- case z:
- return true;
- default:
- doSomething();
-}
-~~~~~~~~~~~~~
-
-================================================================================
-\section code_guidelines_5 Naming
-\subsection code_guidelines_5_1 Namespaces
-
-Namespaces have to be in uppercase.
-
-~~~~~~~~~~~~~
-namespace KODI
-{
-...
-}
-~~~~~~~~~~~~~
-
-\subsection code_guidelines_5_2 Constants
-
-Use uppercase with underscore spacing where necessary.
-
-~~~~~~~~~~~~~
-const int MY_CONSTANT = 1;
-~~~~~~~~~~~~~
-
---------------------------------------------------------------------------------
-\subsection code_guidelines_5_3 Enums
-
-Use CamelCase for the enum name and uppercase for the values.
-
-~~~~~~~~~~~~~
-enum Dummy
-{
- VALUE_X,
- VALUE_Y
-};
-~~~~~~~~~~~~~
-
---------------------------------------------------------------------------------
-\subsection code_guidelines_5_4 Interfaces
-
-Use CamelCase for interface names and they have to be prefixed with an
-uppercase I. Filename has to match the interface name, e.g. `ILogger.h`
-
-~~~~~~~~~~~~~
-class ILogger
-{
- void Log(...) = 0;
-}
-~~~~~~~~~~~~~
-
---------------------------------------------------------------------------------
-\subsection code_guidelines_5_5 Classes
-
-We use CamelCase for class names and they have to be prefixed with an uppercase C.
-Filenamehas match the class name without the prefixed C, e.g. `Logger.cpp`
-
-~~~~~~~~~~~~~
-class CLogger : public ILogger
-{
- void Log(...)
-}
-~~~~~~~~~~~~~
-
---------------------------------------------------------------------------------
-\subsection code_guidelines_5_6 Methods
-
-Use CamelCase for method names and first letter shas to be uppercase.
-Even if the methods are private or protected.
-
-~~~~~~~~~~~~~
-void MyDummyClass::DoSomething();
-~~~~~~~~~~~~~
-
---------------------------------------------------------------------------------
-\subsection code_guidelines_5_7 Variables
-
-We use CamelCase for variables. Type prefixing is optional.
-\subsubsection code_guidelines_5_7_1 Global Variables
-
-Prefix global variables with g_
-
-~~~~~~~~~~~~~
-int g_globalVariableA;
-~~~~~~~~~~~~~
-
-\warning Use of globals reduces the chance of submitted code to be accepted to a minimum
-
-\subsubsection code_guidelines_5_7_2 Member Variables
-
-Prefix member variables with m_
-
-~~~~~~~~~~~~~
-int m_variableA;
-~~~~~~~~~~~~~
-
-================================================================================
-\section code_guidelines_6 Conventions
-
---------------------------------------------------------------------------------
-\subsection code_guidelines_6_1 Casts
-
-New code has to use C++ style casts and not older C style casts. When modifying
-existing code the developer can choose to update it to C++ style casts or leave
-as is. Remember that whenever a dynamic_cast is used the result can be a nullptr
-and needs to be checked accordingly.
-
---------------------------------------------------------------------------------
-\subsection code_guidelines_6_2 NULL vs nullptr
-
-Prefer the use of nullptr instead of NULL. nullptr is a typesafe version and as
-such can't be implicitly converted to int or anything else.
-
---------------------------------------------------------------------------------
-\subsection code_guidelines_6_3 auto
-
-Feel free to use auto wherever it improves readability. Good places are
-iterators or when dealing with containers.
-
-~~~~~~~~~~~~~
-std::map<std::string, std::vector<int>>::iterator i = var.begin();
-vs
-auto i = var.being();
-~~~~~~~~~~~~~
-
---------------------------------------------------------------------------------
-\subsection code_guidelines_6_4 for loops
-
-Use newer style foreach loops whenever it makes sense. If iterators are used see
-above about using auto.
-
-~~~~~~~~~~~~~
-for (auto& : var)
-{
- ...
-}
-~~~~~~~~~~~~~
-
-Use const auto& if there's no reason to modify the value.
-
---------------------------------------------------------------------------------
-\subsection code_guidelines_6_5 default member initialization
-
-Use default member initialization instead of initializer lists or constructor assignments whenever it makes sense.
-~~~~~~~~~~~~~
-class Foo
-{
- bool bar = false;
-};
-~~~~~~~~~~~~~
-
-*/
diff --git a/docs/doxygen/Doxyfile.doxy b/docs/doxygen/Doxyfile.doxy
index 9115f3a19a..5806aa4a6c 100644
--- a/docs/doxygen/Doxyfile.doxy
+++ b/docs/doxygen/Doxyfile.doxy
@@ -807,7 +807,7 @@ WARN_LOGFILE =
# Note: If this tag is empty the current directory is searched.
INPUT = ../../xbmc \
- CODING_GUIDELINES.dox \
+ ../CODE_GUIDELINES.md \
.
# This tag can be used to specify the character encoding of the source files
diff --git a/tools/depends/target/ffmpeg/FFMPEG-VERSION b/tools/depends/target/ffmpeg/FFMPEG-VERSION
index d678d32e23..d7883f0ee8 100644
--- a/tools/depends/target/ffmpeg/FFMPEG-VERSION
+++ b/tools/depends/target/ffmpeg/FFMPEG-VERSION
@@ -1,4 +1,4 @@
LIBNAME=ffmpeg
BASE_URL=https://github.com/xbmc/FFmpeg
-VERSION=4.0.3-Leia-RC5
+VERSION=4.0.3-Leia-18.2
ARCHIVE=$(LIBNAME)-$(VERSION).tar.gz
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..5748f5295a 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())
@@ -1484,7 +1499,7 @@ void CPVRClient::cb_transfer_channel_group(void *kodiInstance, const ADDON_HANDL
}
/* transfer this entry to the groups container */
- CPVRChannelGroup transferGroup(*group);
+ CPVRChannelGroup transferGroup(*group, kodiGroups->GetGroupAll());
kodiGroups->UpdateFromClient(transferGroup);
}
@@ -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/addons/kodi-addon-dev-kit/doxygen/Doxyfile b/xbmc/addons/kodi-addon-dev-kit/doxygen/Doxyfile
index 06eb8be6da..1fba414e96 100644
--- a/xbmc/addons/kodi-addon-dev-kit/doxygen/Doxyfile
+++ b/xbmc/addons/kodi-addon-dev-kit/doxygen/Doxyfile
@@ -812,7 +812,6 @@ WARN_LOGFILE =
INPUT = main.txt \
General/General.dox \
General/DoxygenOnAddon.dox \
- ../../../../docs/doxygen/CODING_GUIDELINES.dox \
../../../GUIInfoManager.cpp \
Modules/modules_general.dox \
Modules/modules_cpp.dox \
diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecAndroidMediaCodec.cpp b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecAndroidMediaCodec.cpp
index c8a799c71b..eb51c164ba 100644
--- a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecAndroidMediaCodec.cpp
+++ b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecAndroidMediaCodec.cpp
@@ -1061,11 +1061,6 @@ void CDVDVideoCodecAndroidMediaCodec::SetCodecControl(int flags)
{
CLog::Log(LOGDEBUG, LOGVIDEO, "CDVDVideoCodecAndroidMediaCodec::%s %x->%x", __func__, m_codecControlFlags, flags);
m_codecControlFlags = flags;
-
- if (m_codecControlFlags & DVD_CODEC_CTRL_DROP)
- m_videobuffer.iFlags |= DVP_FLAG_DROPPED;
- else
- m_videobuffer.iFlags &= ~DVP_FLAG_DROPPED;
}
}
@@ -1227,8 +1222,9 @@ int CDVDVideoCodecAndroidMediaCodec::GetOutputPicture(void)
if (m_codecControlFlags & DVD_CODEC_CTRL_DROP)
{
+ m_noPictureLoop = 0;
AMediaCodec_releaseOutputBuffer(m_codec->codec(), index, false);
- return -1;
+ return -2;
}
if (bufferInfo.flags & AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM)
diff --git a/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.cpp b/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.cpp
index dec7d04567..11af64a251 100644
--- a/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.cpp
+++ b/xbmc/cores/VideoPlayer/DVDDemuxers/DVDDemuxFFmpeg.cpp
@@ -2078,6 +2078,21 @@ bool CDVDDemuxFFmpeg::IsVideoReady()
hasVideo = true;
}
}
+ // Workaround for live audio-only MPEG-TS streams: If there are no elementary video streams
+ // present attempt to set the start time from the first available elementary audio stream instead
+ if (!hasVideo && !m_startTime)
+ {
+ for (unsigned int i = 0; i < m_pFormatContext->programs[m_program]->nb_stream_indexes; i++)
+ {
+ int idx = m_pFormatContext->programs[m_program]->stream_index[i];
+ st = m_pFormatContext->streams[idx];
+ if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO)
+ {
+ m_startTime = static_cast<double>(av_rescale(st->cur_dts, st->time_base.num, st->time_base.den));
+ break;
+ }
+ }
+ }
}
else
{
@@ -2095,6 +2110,20 @@ bool CDVDDemuxFFmpeg::IsVideoReady()
hasVideo = true;
}
}
+ // Workaround for live audio-only MPEG-TS streams: If there are no elementary video streams
+ // present attempt to set the start time from the first available elementary audio stream instead
+ if (!hasVideo && !m_startTime)
+ {
+ for (unsigned int i = 0; i < m_pFormatContext->nb_streams; i++)
+ {
+ st = m_pFormatContext->streams[i];
+ if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO)
+ {
+ m_startTime = static_cast<double>(av_rescale(st->cur_dts, st->time_base.num, st->time_base.den));
+ break;
+ }
+ }
+ }
}
return !hasVideo;
}
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/cores/VideoPlayer/VideoPlayerVideo.cpp b/xbmc/cores/VideoPlayer/VideoPlayerVideo.cpp
index 5ad2bcbf33..0cb65c7850 100644
--- a/xbmc/cores/VideoPlayer/VideoPlayerVideo.cpp
+++ b/xbmc/cores/VideoPlayer/VideoPlayerVideo.cpp
@@ -462,6 +462,7 @@ void CVideoPlayerVideo::Process()
}
m_renderManager.DiscardBuffer();
+ FlushMessages();
}
else if (pMsg->IsType(CDVDMsg::PLAYER_SETSPEED))
{
@@ -776,7 +777,6 @@ void CVideoPlayerVideo::Flush(bool sync)
/* flush using message as this get's called from VideoPlayer thread */
/* and any demux packet that has been taken out of queue need to */
/* be disposed of before we flush */
- FlushMessages();
SendMessage(new CDVDMsgBool(CDVDMsg::GENERAL_FLUSH, sync), 1);
m_bAbortOutput = true;
}
diff --git a/xbmc/filesystem/CurlFile.cpp b/xbmc/filesystem/CurlFile.cpp
index d5dcc7d430..3bc6527d21 100644
--- a/xbmc/filesystem/CurlFile.cpp
+++ b/xbmc/filesystem/CurlFile.cpp
@@ -1024,7 +1024,7 @@ bool CCurlFile::Open(const CURL& url)
// since we can't know the stream size up front if we're gzipped/deflated
// flag the stream with an unknown file size rather than the compressed
// file size.
- if (!m_acceptencoding.empty())
+ if (!m_state->m_httpheader.GetValue("Content-Encoding").empty() && !StringUtils::EqualsNoCase(m_state->m_httpheader.GetValue("Content-Encoding"), "identity"))
m_state->m_fileSize = 0;
// check if this stream is a shoutcast stream. sometimes checking the protocol line is not enough so examine other headers as well.
diff --git a/xbmc/games/controllers/windows/GUIControllerWindow.cpp b/xbmc/games/controllers/windows/GUIControllerWindow.cpp
index f8a2b9ffdc..65cfba0563 100644
--- a/xbmc/games/controllers/windows/GUIControllerWindow.cpp
+++ b/xbmc/games/controllers/windows/GUIControllerWindow.cpp
@@ -190,6 +190,8 @@ void CGUIControllerWindow::OnEvent(const ADDON::CRepositoryUpdater::RepositoryUp
void CGUIControllerWindow::OnInitWindow(void)
{
+ // subscribe to events
+ CServiceBroker::GetRepositoryUpdater().Events().Subscribe(this, &CGUIControllerWindow::OnEvent);
// Get active game add-on
GameClientPtr gameClient;
{
@@ -237,6 +239,8 @@ void CGUIControllerWindow::OnInitWindow(void)
void CGUIControllerWindow::OnDeinitWindow(int nextWindowID)
{
+ CServiceBroker::GetRepositoryUpdater().Events().Unsubscribe(this);
+
if (m_controllerList)
{
m_controllerList->Deinitialize();
diff --git a/xbmc/interfaces/json-rpc/PVROperations.cpp b/xbmc/interfaces/json-rpc/PVROperations.cpp
index 9442fa443d..0e33a03ddf 100644
--- a/xbmc/interfaces/json-rpc/PVROperations.cpp
+++ b/xbmc/interfaces/json-rpc/PVROperations.cpp
@@ -157,7 +157,12 @@ JSONRPC_STATUS CPVROperations::GetBroadcasts(const std::string &method, ITranspo
return InternalError;
CFileItemList programFull;
- channelEpg->Get(programFull);
+
+ const std::vector<std::shared_ptr<CPVREpgInfoTag>> tags = channelEpg->GetTags();
+ for (const auto& tag : tags)
+ {
+ programFull.Add(std::make_shared<CFileItem>(tag));
+ }
HandleFileItemList("broadcastid", false, "broadcasts", programFull, parameterObject, result, programFull.Size(), true);
@@ -169,7 +174,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(nullptr,
+ parameterObject["broadcastid"].asUnsignedInteger());
if (!epgTag)
return InvalidParams;
@@ -210,13 +216,14 @@ JSONRPC_STATUS CPVROperations::Record(const std::string &method, ITransportLayer
return FailedToExecute;
CVariant record = parameterObject["record"];
+ bool bIsRecording = CServiceBroker::GetPVRManager().Timers()->IsRecordingOnChannel(*pChannel);
bool toggle = true;
- if (record.isBoolean() && record.asBoolean() == pChannel->IsRecording())
+ if (record.isBoolean() && record.asBoolean() == bIsRecording)
toggle = false;
if (toggle)
{
- if (!CServiceBroker::GetPVRManager().GUIActions()->SetRecordingOnChannel(pChannel, !pChannel->IsRecording()))
+ if (!CServiceBroker::GetPVRManager().GUIActions()->SetRecordingOnChannel(pChannel, !bIsRecording))
return FailedToExecute;
}
@@ -321,12 +328,13 @@ 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(nullptr,
+ parameterObject["broadcastid"].asUnsignedInteger());
if (!epgTag)
return InvalidParams;
- if (epgTag->HasTimer())
+ if (CServiceBroker::GetPVRManager().Timers()->GetTimerForEpgTag(epgTag))
return InvalidParams;
CPVRTimerInfoTagPtr newTimer = CPVRTimerInfoTag::CreateFromEpg(epgTag, parameterObject["timerrule"].asBoolean(false));
@@ -363,14 +371,15 @@ 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(nullptr,
+ parameterObject["broadcastid"].asUnsignedInteger());
if (!epgTag)
return InvalidParams;
bool timerrule = parameterObject["timerrule"].asBoolean(false);
bool sentOkay = false;
- CPVRTimerInfoTagPtr timer(epgTag->Timer());
+ std::shared_ptr<CPVRTimerInfoTag> timer = CServiceBroker::GetPVRManager().Timers()->GetTimerForEpgTag(epgTag);
if (timer)
{
if (timerrule)
diff --git a/xbmc/music/MusicDatabase.cpp b/xbmc/music/MusicDatabase.cpp
index 26b2723d03..c3a750e7d2 100644
--- a/xbmc/music/MusicDatabase.cpp
+++ b/xbmc/music/MusicDatabase.cpp
@@ -1401,7 +1401,7 @@ bool CMusicDatabase::GetArtist(int idArtist, CArtist &artist, bool fetchAll /* =
int discographyOffset = artist_enumCount;
artist.discography.clear();
- artist = GetArtistFromDataset(m_pDS.get()->get_sql_record(), 0, fetchAll);
+ artist = GetArtistFromDataset(m_pDS.get()->get_sql_record(), 0, true); // inc scraped art URLs
if (fetchAll)
{
while (!m_pDS->eof())
@@ -9707,7 +9707,7 @@ void CMusicDatabase::ExportToXML(const CLibExportSettings& settings, CGUIDialog
for (const auto &artistId : artistIds)
{
CArtist artist;
- GetArtist(artistId, artist);
+ GetArtist(artistId, artist, true); // include discography
std::string strPath;
std::map<std::string, std::string> artwork;
if (settings.IsSingleFile())
@@ -9866,7 +9866,7 @@ void CMusicDatabase::ImportFromXML(const std::string &xmlFile)
if (idArtist > -1)
{
CArtist artist;
- GetArtist(idArtist, artist);
+ GetArtist(idArtist, artist, true); // include discography
artist.MergeScrapedArtist(importedArtist, true);
UpdateArtist(artist);
}
@@ -10484,13 +10484,6 @@ bool CMusicDatabase::GetFilter(CDbUrl &musicUrl, Filter &filter, SortDescription
}
// remove the null string
filter.AppendWhere("artistview.strArtist != ''");
-
- // and the various artist entry if applicable
- if (!albumArtistsOnly)
- {
- std::string strVariousArtists = g_localizeStrings.Get(340);
- filter.AppendWhere(PrepareSQL("artistview.strArtist <> '%s'", strVariousArtists.c_str()));
- }
}
else if (type == "albums")
{
diff --git a/xbmc/peripherals/devices/PeripheralCecAdapter.cpp b/xbmc/peripherals/devices/PeripheralCecAdapter.cpp
index e65bf729b3..802dd0779e 100644
--- a/xbmc/peripherals/devices/PeripheralCecAdapter.cpp
+++ b/xbmc/peripherals/devices/PeripheralCecAdapter.cpp
@@ -599,6 +599,8 @@ void CPeripheralCecAdapter::OnTvStandby(void)
case LOCALISED_ID_STOP:
KODI::MESSAGING::CApplicationMessenger::GetInstance().PostMsg(TMSG_MEDIA_STOP);
break;
+ case LOCALISED_ID_IGNORE:
+ break;
default:
CLog::Log(LOGERROR, "%s - Unexpected [standby_pc_on_tv_standby] setting value", __FUNCTION__);
break;
diff --git a/xbmc/platform/android/activity/XBMCApp.cpp b/xbmc/platform/android/activity/XBMCApp.cpp
index 3a6e6f65c5..e9ae1ab073 100644
--- a/xbmc/platform/android/activity/XBMCApp.cpp
+++ b/xbmc/platform/android/activity/XBMCApp.cpp
@@ -120,7 +120,6 @@ int CXBMCApp::m_batteryLevel = 0;
bool CXBMCApp::m_hasFocus = false;
bool CXBMCApp::m_headsetPlugged = false;
bool CXBMCApp::m_hdmiPlugged = true;
-bool CXBMCApp::m_hdmiReportedState = true;
bool CXBMCApp::m_hdmiSource = false;
IInputDeviceCallbacks* CXBMCApp::m_inputDeviceCallbacks = nullptr;
IInputDeviceEventHandler* CXBMCApp::m_inputDeviceEventHandler = nullptr;
@@ -524,11 +523,6 @@ void CXBMCApp::SetRefreshRateCallback(CVariant* rateVariant)
CJNIWindowManagerLayoutParams params = window.getAttributes();
if (fabs(params.getpreferredRefreshRate() - rate) > 0.001)
{
- if (m_hdmiSource && g_application.GetAppPlayer().IsPlaying())
- {
- dynamic_cast<CWinSystemAndroid*>(CServiceBroker::GetWinSystem())->SetHDMIState(false, 1000);
- m_hdmiReportedState = false;
- }
params.setpreferredRefreshRate(rate);
if (params.getpreferredRefreshRate() > 0.0)
{
@@ -552,11 +546,6 @@ void CXBMCApp::SetDisplayModeCallback(CVariant* variant)
CJNIWindowManagerLayoutParams params = window.getAttributes();
if (params.getpreferredDisplayModeId() != mode)
{
- if (m_hdmiSource && g_application.GetAppPlayer().IsPlaying())
- {
- dynamic_cast<CWinSystemAndroid*>(CServiceBroker::GetWinSystem())->SetHDMIState(false);
- m_hdmiReportedState = false;
- }
params.setpreferredDisplayModeId(mode);
params.setpreferredRefreshRate(rate);
window.setAttributes(params);
@@ -585,7 +574,11 @@ void CXBMCApp::SetRefreshRate(float rate)
CVariant *variant = new CVariant(rate);
runNativeOnUiThread(SetRefreshRateCallback, variant);
if (g_application.IsInitialized())
+ {
m_displayChangeEvent.WaitMSec(5000);
+ if (m_hdmiSource && g_application.GetAppPlayer().IsPlaying())
+ dynamic_cast<CWinSystemAndroid*>(CServiceBroker::GetWinSystem())->SetHDMIState(false);
+ }
}
void CXBMCApp::SetDisplayMode(int mode, float rate)
@@ -602,7 +595,6 @@ void CXBMCApp::SetDisplayMode(int mode, float rate)
}
m_displayChangeEvent.Reset();
-
std::map<std::string, CVariant> vmap;
vmap["mode"] = mode;
vmap["rate"] = rate;
@@ -610,7 +602,11 @@ void CXBMCApp::SetDisplayMode(int mode, float rate)
CVariant *variant = new CVariant(vmap);
runNativeOnUiThread(SetDisplayModeCallback, variant);
if (g_application.IsInitialized())
+ {
m_displayChangeEvent.WaitMSec(5000);
+ if (m_hdmiSource && g_application.GetAppPlayer().IsPlaying())
+ dynamic_cast<CWinSystemAndroid*>(CServiceBroker::GetWinSystem())->SetHDMIState(false);
+ }
}
int CXBMCApp::android_printf(const char *format, ...)
@@ -1018,24 +1014,13 @@ void CXBMCApp::onReceive(CJNIIntent intent)
}
else if (action == "android.media.action.HDMI_AUDIO_PLUG")
{
- bool newstate;
- newstate = (intent.getIntExtra("android.media.extra.AUDIO_PLUG_STATE", 0) != 0);
-
- if (newstate != m_hdmiPlugged)
+ m_hdmiPlugged = (intent.getIntExtra("android.media.extra.AUDIO_PLUG_STATE", 0) != 0);
+ CLog::Log(LOGDEBUG, "-- HDMI state: %s", m_hdmiPlugged ? "on" : "off");
+ if (m_hdmiSource && g_application.IsInitialized())
{
- CLog::Log(LOGDEBUG, "-- HDMI state: %s", newstate ? "on" : "off");
- m_hdmiPlugged = newstate;
- if (m_hdmiPlugged != m_hdmiReportedState)
- {
- if (g_application.IsInitialized())
- {
- CWinSystemBase* winSystem = CServiceBroker::GetWinSystem();
- if (winSystem && dynamic_cast<CWinSystemAndroid*>(winSystem))
- dynamic_cast<CWinSystemAndroid*>(winSystem)->SetHDMIState(m_hdmiPlugged);
-
- m_hdmiReportedState = m_hdmiPlugged;
- }
- }
+ CWinSystemBase* winSystem = CServiceBroker::GetWinSystem();
+ if (winSystem && dynamic_cast<CWinSystemAndroid*>(winSystem))
+ dynamic_cast<CWinSystemAndroid*>(winSystem)->SetHDMIState(m_hdmiPlugged);
}
}
else if (action == "android.intent.action.SCREEN_OFF")
@@ -1409,6 +1394,7 @@ void CXBMCApp::onDisplayAdded(int displayId)
void CXBMCApp::onDisplayChanged(int displayId)
{
+ CLog::Log(LOGDEBUG, "CXBMCApp::%s: id: %d", __FUNCTION__, displayId);
m_displayChangeEvent.Set();
android_printf("%s: ", __PRETTY_FUNCTION__);
}
diff --git a/xbmc/pvr/PVRContextMenus.cpp b/xbmc/pvr/PVRContextMenus.cpp
index 653b5f3e49..0eb9802383 100644
--- a/xbmc/pvr/PVRContextMenus.cpp
+++ b/xbmc/pvr/PVRContextMenus.cpp
@@ -20,8 +20,10 @@
#include "pvr/channels/PVRChannel.h"
#include "pvr/epg/EpgInfoTag.h"
#include "pvr/recordings/PVRRecording.h"
+#include "pvr/recordings/PVRRecordings.h"
#include "pvr/recordings/PVRRecordingsPath.h"
#include "pvr/timers/PVRTimers.h"
+#include "pvr/timers/PVRTimersPath.h"
namespace PVR
{
@@ -85,7 +87,7 @@ namespace PVR
const CPVREpgInfoTagPtr epg(item.GetEPGInfoTag());
if (epg)
- timer = epg->Timer();
+ timer = CServiceBroker::GetPVRManager().Timers()->GetTimerForEpgTag(epg);
if (!timer)
timer = item.GetPVRTimerInfoTag();
@@ -115,12 +117,7 @@ namespace PVR
bool PlayRecording::IsVisible(const CFileItem &item) const
{
- CPVRRecordingPtr recording;
-
- const CPVREpgInfoTagPtr epg(item.GetEPGInfoTag());
- if (epg)
- recording = epg->Recording();
-
+ const std::shared_ptr<CPVRRecording> recording = CServiceBroker::GetPVRManager().Recordings()->GetRecordingForEpgTag(item.GetEPGInfoTag());
if (recording)
return !recording->IsDeleted();
@@ -220,10 +217,13 @@ namespace PVR
const CPVRChannelPtr channel = item.GetPVRChannelInfoTag();
if (channel)
- return !channel->IsRecording() && client && client->GetClientCapabilities().SupportsTimers();
+ return client && client->GetClientCapabilities().SupportsTimers() &&
+ !CServiceBroker::GetPVRManager().Timers()->IsRecordingOnChannel(*channel);
const CPVREpgInfoTagPtr epg = item.GetEPGInfoTag();
- if (epg && !epg->Timer() && epg->Channel() && epg->IsRecordable())
+ if (epg &&
+ !CServiceBroker::GetPVRManager().Timers()->GetTimerForEpgTag(epg) &&
+ epg->IsRecordable())
return client && client->GetClientCapabilities().SupportsTimers();
return false;
@@ -245,7 +245,7 @@ namespace PVR
const CPVRChannelPtr channel(item.GetPVRChannelInfoTag());
if (channel)
- return channel->IsRecording();
+ return CServiceBroker::GetPVRManager().Timers()->IsRecordingOnChannel(*channel);
const CPVRTimerInfoTagPtr timer(GetTimerInfoTagFromItem(item));
if (timer && !URIUtils::PathEquals(item.GetPath(), CPVRTimersPath::PATH_ADDTIMER))
@@ -381,7 +381,7 @@ namespace PVR
bool AddTimerRule::IsVisible(const CFileItem &item) const
{
const CPVREpgInfoTagPtr epg = item.GetEPGInfoTag();
- if (epg && epg->Channel() && !epg->Timer())
+ if (epg && !CServiceBroker::GetPVRManager().Timers()->GetTimerForEpgTag(epg))
{
const CPVRClientPtr client = CServiceBroker::GetPVRManager().GetClient(item);
return client && client->GetClientCapabilities().SupportsTimers();
diff --git a/xbmc/pvr/PVRDatabase.cpp b/xbmc/pvr/PVRDatabase.cpp
index 6eaa6131d2..ffcdb13d3b 100644
--- a/xbmc/pvr/PVRDatabase.cpp
+++ b/xbmc/pvr/PVRDatabase.cpp
@@ -521,7 +521,7 @@ bool CPVRDatabase::Get(CPVRChannelGroups &results)
{
while (!m_pDS->eof())
{
- CPVRChannelGroup data(m_pDS->fv("bIsRadio").get_asBool(), m_pDS->fv("idGroup").get_asInt(), m_pDS->fv("sName").get_asString());
+ CPVRChannelGroup data(m_pDS->fv("bIsRadio").get_asBool(), m_pDS->fv("idGroup").get_asInt(), m_pDS->fv("sName").get_asString(), results.GetGroupAll());
data.SetGroupType(m_pDS->fv("iGroupType").get_asInt());
data.SetLastWatched(static_cast<time_t>(m_pDS->fv("iLastWatched").get_asInt()));
data.SetHidden(m_pDS->fv("bIsHidden").get_asBool());
diff --git a/xbmc/pvr/PVRGUIActions.cpp b/xbmc/pvr/PVRGUIActions.cpp
index c320ae9d32..d6d2f01bd9 100644
--- a/xbmc/pvr/PVRGUIActions.cpp
+++ b/xbmc/pvr/PVRGUIActions.cpp
@@ -308,7 +308,7 @@ namespace PVR
return false;
}
- CPVRTimerInfoTagPtr timer(bCreateRule || !epgTag ? nullptr : epgTag->Timer());
+ CPVRTimerInfoTagPtr timer(bCreateRule || !epgTag ? nullptr : CServiceBroker::GetPVRManager().Timers()->GetTimerForEpgTag(epgTag));
CPVRTimerInfoTagPtr rule (bCreateRule ? CServiceBroker::GetPVRManager().Timers()->GetTimerRule(timer) : nullptr);
if (timer || rule)
{
@@ -483,7 +483,7 @@ namespace PVR
{
const CPVRChannelPtr channel = CServiceBroker::GetPVRManager().GetPlayingChannel();
if (channel && channel->CanRecord())
- return SetRecordingOnChannel(channel, !channel->IsRecording());
+ return SetRecordingOnChannel(channel, !CServiceBroker::GetPVRManager().Timers()->IsRecordingOnChannel(*channel));
return false;
}
@@ -502,7 +502,7 @@ namespace PVR
if (client && client->GetClientCapabilities().SupportsTimers())
{
/* timers are supported on this channel */
- if (bOnOff && !channel->IsRecording())
+ if (bOnOff && !CServiceBroker::GetPVRManager().Timers()->IsRecordingOnChannel(*channel))
{
CPVREpgInfoTagPtr epgTag;
int iDuration = m_settings.GetIntValue(CSettings::SETTING_PVRRECORD_INSTANTRECORDTIME);
@@ -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)
@@ -609,7 +613,7 @@ namespace PVR
if (!bReturn)
HELPERS::ShowOKDialogText(CVariant{257}, CVariant{19164}); // "Error", "Could not start recording. Check the log for more information about this message."
}
- else if (!bOnOff && channel->IsRecording())
+ else if (!bOnOff && CServiceBroker::GetPVRManager().Timers()->IsRecordingOnChannel(*channel))
{
/* delete active timers */
bReturn = CServiceBroker::GetPVRManager().Timers()->DeleteTimersOnChannel(channel, true, true);
@@ -751,7 +755,7 @@ namespace PVR
CPVRTimerInfoTagPtr timer;
const CPVRRecordingPtr recording(CPVRItem(item).GetRecording());
if (recording)
- timer = CServiceBroker::GetPVRManager().Timers()->GetRecordingTimerForRecording(*recording);
+ timer = recording->GetRecordingTimer();
if (!timer)
timer = CPVRItem(item).GetTimerInfoTag();
@@ -1130,20 +1134,33 @@ namespace PVR
if (item->m_bIsFolder)
return false;
+ std::shared_ptr<CPVRRecording> recording;
const CPVRChannelPtr channel(CPVRItem(item).GetChannel());
- if ((channel && CServiceBroker::GetPVRManager().IsPlayingChannel(channel)) ||
- (channel && channel->HasRecording() && CServiceBroker::GetPVRManager().IsPlayingRecording(channel->GetRecording())))
+ if (channel)
{
- CGUIMessage msg(GUI_MSG_FULLSCREEN, 0, CServiceBroker::GetGUI()->GetWindowManager().GetActiveWindow());
- CServiceBroker::GetGUI()->GetWindowManager().SendMessage(msg);
- return true;
+ bool bSwitchToFullscreen = CServiceBroker::GetPVRManager().IsPlayingChannel(channel);
+
+ if (!bSwitchToFullscreen)
+ {
+ recording = CServiceBroker::GetPVRManager().Recordings()->GetRecordingForEpgTag(channel->GetEPGNow());
+ bSwitchToFullscreen = recording && CServiceBroker::GetPVRManager().IsPlayingRecording(recording);
+ }
+
+ if (bSwitchToFullscreen)
+ {
+ CGUIMessage msg(GUI_MSG_FULLSCREEN, 0, CServiceBroker::GetGUI()->GetWindowManager().GetActiveWindow());
+ CServiceBroker::GetGUI()->GetWindowManager().SendMessage(msg);
+ return true;
+ }
}
ParentalCheckResult result = channel ? CheckParentalLock(channel) : ParentalCheckResult::FAILED;
if (result == ParentalCheckResult::SUCCESS)
{
// switch to channel or if recording present, ask whether to switch or play recording...
- const CPVRRecordingPtr recording(channel->GetRecording());
+ if (!recording)
+ recording = CServiceBroker::GetPVRManager().Recordings()->GetRecordingForEpgTag(channel->GetEPGNow());
+
if (recording)
{
bool bCancel(false);
@@ -1682,12 +1699,12 @@ namespace PVR
bool CPVRGUIActions::AllLocalBackendsIdle(CPVRTimerInfoTagPtr& causingEvent) const
{
// active recording on local backend?
- const std::vector<CFileItemPtr> activeRecordings = CServiceBroker::GetPVRManager().Timers()->GetActiveRecordings();
+ const std::vector<std::shared_ptr<CPVRTimerInfoTag>> activeRecordings = CServiceBroker::GetPVRManager().Timers()->GetActiveRecordings();
for (const auto& timer : activeRecordings)
{
- if (EventOccursOnLocalBackend(timer))
+ if (EventOccursOnLocalBackend(std::make_shared<CFileItem>(timer)))
{
- causingEvent = timer->GetPVRTimerInfoTag();
+ causingEvent = timer;
return false;
}
}
@@ -1695,17 +1712,17 @@ namespace PVR
// soon recording on local backend?
if (IsNextEventWithinBackendIdleTime())
{
- const CFileItemPtr item = CServiceBroker::GetPVRManager().Timers()->GetNextActiveTimer();
- if (!item)
+ const std::shared_ptr<CPVRTimerInfoTag> timer = CServiceBroker::GetPVRManager().Timers()->GetNextActiveTimer();
+ if (!timer)
{
// Next event is due to automatic daily wakeup of PVR!
causingEvent.reset();
return false;
}
- if (EventOccursOnLocalBackend(item))
+ if (EventOccursOnLocalBackend(std::make_shared<CFileItem>(timer)))
{
- causingEvent = item->GetPVRTimerInfoTag();
+ causingEvent = timer;
return false;
}
}
diff --git a/xbmc/pvr/PVRGUIInfo.cpp b/xbmc/pvr/PVRGUIInfo.cpp
index a09cb158a3..7988e610c5 100644
--- a/xbmc/pvr/PVRGUIInfo.cpp
+++ b/xbmc/pvr/PVRGUIInfo.cpp
@@ -16,6 +16,7 @@
#include "ServiceBroker.h"
#include "guilib/GUIComponent.h"
#include "guilib/LocalizeStrings.h"
+#include "guilib/GUIWindowManager.h"
#include "guilib/guiinfo/GUIInfo.h"
#include "guilib/guiinfo/GUIInfoHelper.h"
#include "guilib/guiinfo/GUIInfoLabels.h"
@@ -275,6 +276,25 @@ bool CPVRGUIInfo::GetLabel(std::string& value, const CFileItem *item, int contex
GetRadioRDSLabel(item, info, value);
}
+namespace
+{
+ std::string GetAsLocalizedDateString(const CDateTime& datetime, bool bLongDate)
+ {
+ return datetime.IsValid() ? datetime.GetAsLocalizedDate(bLongDate) : "";
+ }
+
+ std::string GetAsLocalizedTimeString(const CDateTime& datetime)
+ {
+ return datetime.IsValid() ? datetime.GetAsLocalizedTime("", false) : "";
+ }
+
+ std::string GetAsLocalizedDateTimeString(const CDateTime& datetime)
+ {
+ return datetime.IsValid() ? datetime.GetAsLocalizedDateTime(false, false) : "";
+ }
+
+} // unnamed namespace
+
bool CPVRGUIInfo::GetListItemAndPlayerLabel(const CFileItem *item, const CGUIInfo &info, std::string &strValue) const
{
const CPVRTimerInfoTagPtr timer = item->GetPVRTimerInfoTag();
@@ -286,16 +306,16 @@ bool CPVRGUIInfo::GetListItemAndPlayerLabel(const CFileItem *item, const CGUIInf
strValue = timer->Summary();
return true;
case LISTITEM_STARTDATE:
- strValue = timer->StartAsLocalTime().GetAsLocalizedDate(true);
+ strValue = GetAsLocalizedDateString(timer->StartAsLocalTime(), true);
return true;
case LISTITEM_STARTTIME:
- strValue = timer->StartAsLocalTime().GetAsLocalizedTime("", false);
+ strValue = GetAsLocalizedTimeString(timer->StartAsLocalTime());
return true;
case LISTITEM_ENDDATE:
- strValue = timer->EndAsLocalTime().GetAsLocalizedDate(true);
+ strValue = GetAsLocalizedDateString(timer->EndAsLocalTime(), true);
return true;
case LISTITEM_ENDTIME:
- strValue = timer->EndAsLocalTime().GetAsLocalizedTime("", false);
+ strValue = GetAsLocalizedTimeString(timer->EndAsLocalTime());
return true;
case LISTITEM_DURATION:
if (timer->GetDuration() > 0)
@@ -308,7 +328,7 @@ bool CPVRGUIInfo::GetListItemAndPlayerLabel(const CFileItem *item, const CGUIInf
strValue = timer->Title();
return true;
case LISTITEM_COMMENT:
- strValue = timer->GetStatus();
+ strValue = timer->GetStatus(CServiceBroker::GetGUI()->GetWindowManager().GetActiveWindow() == WINDOW_RADIO_TIMER_RULES);
return true;
case LISTITEM_TIMERTYPE:
strValue = timer->GetTypeAsString();
@@ -343,33 +363,33 @@ bool CPVRGUIInfo::GetListItemAndPlayerLabel(const CFileItem *item, const CGUIInf
switch (info.m_info)
{
case LISTITEM_DATE:
- strValue = recording->RecordingTimeAsLocalTime().GetAsLocalizedDateTime(false, false);
+ strValue = GetAsLocalizedDateTimeString(recording->RecordingTimeAsLocalTime());
return true;
case LISTITEM_STARTDATE:
- strValue = recording->RecordingTimeAsLocalTime().GetAsLocalizedDate(true);
+ strValue = GetAsLocalizedDateString(recording->RecordingTimeAsLocalTime(), true);
return true;
case VIDEOPLAYER_STARTTIME:
case LISTITEM_STARTTIME:
- strValue = recording->RecordingTimeAsLocalTime().GetAsLocalizedTime("", false);
+ strValue = GetAsLocalizedTimeString(recording->RecordingTimeAsLocalTime());
return true;
case LISTITEM_ENDDATE:
- strValue = recording->EndTimeAsLocalTime().GetAsLocalizedDate(true);
+ strValue = GetAsLocalizedDateString(recording->EndTimeAsLocalTime(), true);
return true;
case VIDEOPLAYER_ENDTIME:
case LISTITEM_ENDTIME:
- strValue = recording->EndTimeAsLocalTime().GetAsLocalizedTime("", false);
+ strValue = GetAsLocalizedTimeString(recording->EndTimeAsLocalTime());
return true;
case LISTITEM_EXPIRATION_DATE:
if (recording->HasExpirationTime())
{
- strValue = recording->ExpirationTimeAsLocalTime().GetAsLocalizedDate(false);
+ strValue = GetAsLocalizedDateString(recording->ExpirationTimeAsLocalTime(), false);
return true;
}
break;
case LISTITEM_EXPIRATION_TIME:
if (recording->HasExpirationTime())
{
- strValue = recording->ExpirationTimeAsLocalTime().GetAsLocalizedTime("", false);;
+ strValue = GetAsLocalizedTimeString(recording->ExpirationTimeAsLocalTime());;
return true;
}
break;
@@ -448,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;
@@ -469,36 +492,38 @@ 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 = epgTag->StartAsLocalTime().GetAsLocalizedDateTime(false, false);
+ strValue = GetAsLocalizedDateTimeString(epgTag->StartAsLocalTime());
return true;
case LISTITEM_STARTDATE:
case LISTITEM_NEXT_STARTDATE:
- strValue = epgTag->StartAsLocalTime().GetAsLocalizedDate(true);
+ strValue = GetAsLocalizedDateString(epgTag->StartAsLocalTime(), true);
return true;
case VIDEOPLAYER_STARTTIME:
case VIDEOPLAYER_NEXT_STARTTIME:
case LISTITEM_STARTTIME:
case LISTITEM_NEXT_STARTTIME:
- strValue = epgTag->StartAsLocalTime().GetAsLocalizedTime("", false);
+ strValue = GetAsLocalizedTimeString(epgTag->StartAsLocalTime());
return true;
case LISTITEM_ENDDATE:
case LISTITEM_NEXT_ENDDATE:
- strValue = epgTag->EndAsLocalTime().GetAsLocalizedDate(true);
+ strValue = GetAsLocalizedDateString(epgTag->EndAsLocalTime(), true);
return true;
case VIDEOPLAYER_ENDTIME:
case VIDEOPLAYER_NEXT_ENDTIME:
case LISTITEM_ENDTIME:
case LISTITEM_NEXT_ENDTIME:
- strValue = epgTag->EndAsLocalTime().GetAsLocalizedTime("", false);
+ strValue = GetAsLocalizedTimeString(epgTag->EndAsLocalTime());
return true;
// note: for some reason, there is no VIDEOPLAYER_DURATION
case LISTITEM_DURATION:
@@ -516,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:
@@ -547,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:
@@ -1083,7 +1110,7 @@ bool CPVRGUIInfo::GetListItemAndPlayerBool(const CFileItem *item, const CGUIInfo
case LISTITEM_ISRECORDING:
if (item->IsPVRChannel())
{
- bValue = item->GetPVRChannelInfoTag()->IsRecording();
+ bValue = CServiceBroker::GetPVRManager().Timers()->IsRecordingOnChannel(*item->GetPVRChannelInfoTag());
return true;
}
else if (item->IsEPG() || item->IsPVRTimer())
@@ -1113,7 +1140,7 @@ bool CPVRGUIInfo::GetListItemAndPlayerBool(const CFileItem *item, const CGUIInfo
{
const CPVREpgInfoTagPtr epgTag = CPVRItem(item).GetEpgInfoTag();
if (epgTag)
- bValue = epgTag->HasTimer();
+ bValue = !!CServiceBroker::GetPVRManager().Timers()->GetTimerForEpgTag(epgTag);
return true;
}
break;
@@ -1158,7 +1185,7 @@ bool CPVRGUIInfo::GetListItemAndPlayerBool(const CFileItem *item, const CGUIInfo
{
const CPVREpgInfoTagPtr epgTag = CPVRItem(item).GetEpgInfoTag();
if (epgTag)
- bValue = epgTag->HasRecording();
+ bValue = !!CServiceBroker::GetPVRManager().Recordings()->GetRecordingForEpgTag(epgTag);
return true;
}
break;
@@ -1205,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/PVRGUITimerInfo.cpp b/xbmc/pvr/PVRGUITimerInfo.cpp
index 12b8870bfc..eafbbaa5ab 100644
--- a/xbmc/pvr/PVRGUITimerInfo.cpp
+++ b/xbmc/pvr/PVRGUITimerInfo.cpp
@@ -87,10 +87,10 @@ void CPVRGUITimerInfo::UpdateTimersToggle()
/* safe to fetch these unlocked, since they're updated from the same thread as this one */
if (m_iRecordingTimerAmount > 0)
{
- std::vector<CFileItemPtr> activeTags = GetActiveRecordings();
- if (m_iTimerInfoToggleCurrent < activeTags.size() && activeTags.at(m_iTimerInfoToggleCurrent)->HasPVRTimerInfoTag())
+ std::vector<std::shared_ptr<CPVRTimerInfoTag>> activeTags = GetActiveRecordings();
+ if (m_iTimerInfoToggleCurrent < activeTags.size())
{
- CPVRTimerInfoTagPtr tag = activeTags.at(m_iTimerInfoToggleCurrent)->GetPVRTimerInfoTag();
+ const std::shared_ptr<CPVRTimerInfoTag> tag = activeTags.at(m_iTimerInfoToggleCurrent);
strActiveTimerTitle = StringUtils::Format("%s", tag->Title().c_str());
strActiveTimerChannelName = StringUtils::Format("%s", tag->ChannelName().c_str());
strActiveTimerChannelIcon = StringUtils::Format("%s", tag->ChannelIcon().c_str());
@@ -128,10 +128,9 @@ void CPVRGUITimerInfo::UpdateNextTimer()
std::string strNextRecordingTime;
std::string strNextTimerInfo;
- CFileItemPtr tag = GetNextActiveTimer();
- if (tag && tag->HasPVRTimerInfoTag())
+ const std::shared_ptr<CPVRTimerInfoTag> timer = GetNextActiveTimer();
+ if (timer)
{
- CPVRTimerInfoTagPtr timer = tag->GetPVRTimerInfoTag();
strNextRecordingTitle = StringUtils::Format("%s", timer->Title().c_str());
strNextRecordingChannelName = StringUtils::Format("%s", timer->ChannelName().c_str());
strNextRecordingChannelIcon = StringUtils::Format("%s", timer->ChannelIcon().c_str());
@@ -216,12 +215,12 @@ int CPVRGUIAnyTimerInfo::AmountActiveRecordings()
return CServiceBroker::GetPVRManager().Timers()->AmountActiveRecordings();
}
-std::vector<CFileItemPtr> CPVRGUIAnyTimerInfo::GetActiveRecordings()
+std::vector<std::shared_ptr<CPVRTimerInfoTag>> CPVRGUIAnyTimerInfo::GetActiveRecordings()
{
return CServiceBroker::GetPVRManager().Timers()->GetActiveRecordings();
}
-CFileItemPtr CPVRGUIAnyTimerInfo::GetNextActiveTimer()
+std::shared_ptr<CPVRTimerInfoTag> CPVRGUIAnyTimerInfo::GetNextActiveTimer()
{
return CServiceBroker::GetPVRManager().Timers()->GetNextActiveTimer();
}
@@ -236,12 +235,12 @@ int CPVRGUITVTimerInfo::AmountActiveRecordings()
return CServiceBroker::GetPVRManager().Timers()->AmountActiveTVRecordings();
}
-std::vector<CFileItemPtr> CPVRGUITVTimerInfo::GetActiveRecordings()
+std::vector<std::shared_ptr<CPVRTimerInfoTag>> CPVRGUITVTimerInfo::GetActiveRecordings()
{
return CServiceBroker::GetPVRManager().Timers()->GetActiveTVRecordings();
}
-CFileItemPtr CPVRGUITVTimerInfo::GetNextActiveTimer()
+std::shared_ptr<CPVRTimerInfoTag> CPVRGUITVTimerInfo::GetNextActiveTimer()
{
return CServiceBroker::GetPVRManager().Timers()->GetNextActiveTVTimer();
}
@@ -256,12 +255,12 @@ int CPVRGUIRadioTimerInfo::AmountActiveRecordings()
return CServiceBroker::GetPVRManager().Timers()->AmountActiveRadioRecordings();
}
-std::vector<CFileItemPtr> CPVRGUIRadioTimerInfo::GetActiveRecordings()
+std::vector<std::shared_ptr<CPVRTimerInfoTag>> CPVRGUIRadioTimerInfo::GetActiveRecordings()
{
return CServiceBroker::GetPVRManager().Timers()->GetActiveRadioRecordings();
}
-CFileItemPtr CPVRGUIRadioTimerInfo::GetNextActiveTimer()
+std::shared_ptr<CPVRTimerInfoTag> CPVRGUIRadioTimerInfo::GetNextActiveTimer()
{
return CServiceBroker::GetPVRManager().Timers()->GetNextActiveRadioTimer();
}
diff --git a/xbmc/pvr/PVRGUITimerInfo.h b/xbmc/pvr/PVRGUITimerInfo.h
index 2bc6f2f21b..4db4edb5b4 100644
--- a/xbmc/pvr/PVRGUITimerInfo.h
+++ b/xbmc/pvr/PVRGUITimerInfo.h
@@ -14,11 +14,10 @@
#include "threads/CriticalSection.h"
-class CFileItem;
-typedef std::shared_ptr<CFileItem> CFileItemPtr;
-
namespace PVR
{
+ class CPVRTimerInfoTag;
+
class CPVRGUITimerInfo
{
public:
@@ -50,8 +49,8 @@ namespace PVR
virtual int AmountActiveTimers() = 0;
virtual int AmountActiveRecordings() = 0;
- virtual std::vector<CFileItemPtr> GetActiveRecordings() = 0;
- virtual CFileItemPtr GetNextActiveTimer() = 0;
+ virtual std::vector<std::shared_ptr<CPVRTimerInfoTag>> GetActiveRecordings() = 0;
+ virtual std::shared_ptr<CPVRTimerInfoTag> GetNextActiveTimer() = 0;
unsigned int m_iTimerAmount;
unsigned int m_iRecordingTimerAmount;
@@ -80,8 +79,8 @@ namespace PVR
private:
int AmountActiveTimers() override;
int AmountActiveRecordings() override;
- std::vector<CFileItemPtr> GetActiveRecordings() override;
- CFileItemPtr GetNextActiveTimer() override;
+ std::vector<std::shared_ptr<CPVRTimerInfoTag>> GetActiveRecordings() override;
+ std::shared_ptr<CPVRTimerInfoTag> GetNextActiveTimer() override;
};
class CPVRGUITVTimerInfo : public CPVRGUITimerInfo
@@ -92,8 +91,8 @@ namespace PVR
private:
int AmountActiveTimers() override;
int AmountActiveRecordings() override;
- std::vector<CFileItemPtr> GetActiveRecordings() override;
- CFileItemPtr GetNextActiveTimer() override;
+ std::vector<std::shared_ptr<CPVRTimerInfoTag>> GetActiveRecordings() override;
+ std::shared_ptr<CPVRTimerInfoTag> GetNextActiveTimer() override;
};
class CPVRGUIRadioTimerInfo : public CPVRGUITimerInfo
@@ -104,8 +103,8 @@ namespace PVR
private:
int AmountActiveTimers() override;
int AmountActiveRecordings() override;
- std::vector<CFileItemPtr> GetActiveRecordings() override;
- CFileItemPtr GetNextActiveTimer() override;
+ std::vector<std::shared_ptr<CPVRTimerInfoTag>> GetActiveRecordings() override;
+ std::shared_ptr<CPVRTimerInfoTag> GetNextActiveTimer() override;
};
} // namespace PVR
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 d9667d2477..1f51ed6693 100644
--- a/xbmc/pvr/PVRItem.cpp
+++ b/xbmc/pvr/PVRItem.cpp
@@ -14,8 +14,10 @@
#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"
#include "pvr/timers/PVRTimerInfoTag.h"
#include "pvr/timers/PVRTimers.h"
@@ -46,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();
}
@@ -75,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())
{
@@ -96,19 +98,11 @@ namespace PVR
}
else if (m_item->IsEPG())
{
- return m_item->GetEPGInfoTag()->Timer();
+ return CServiceBroker::GetPVRManager().Timers()->GetTimerForEpgTag(m_item->GetEPGInfoTag());
}
else if (m_item->IsPVRChannel())
{
- CPVRTimerInfoTagPtr timer;
- const CPVREpgInfoTagPtr epgTag(m_item->GetPVRChannelInfoTag()->GetEPGNow());
- if (epgTag)
- timer = epgTag->Timer(); // cheap method, but not reliable as timers get set at epg tags asynchronously
-
- if (timer)
- return timer;
-
- return CServiceBroker::GetPVRManager().Timers()->GetActiveTimerForChannel(m_item->GetPVRChannelInfoTag()); // more expensive, but reliable and works even for channels with no epg data
+ return CServiceBroker::GetPVRManager().Timers()->GetActiveTimerForChannel(m_item->GetPVRChannelInfoTag());
}
else
{
@@ -125,7 +119,7 @@ namespace PVR
}
else if (m_item->IsEPG())
{
- return m_item->GetEPGInfoTag()->Recording();
+ return CServiceBroker::GetPVRManager().Recordings()->GetRecordingForEpgTag(m_item->GetEPGInfoTag());
}
else
{
@@ -142,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..df41b440e2 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;
@@ -678,7 +686,7 @@ int CPVRManager::GetPlayingClientID(void) const
bool CPVRManager::IsRecordingOnPlayingChannel(void) const
{
const CPVRChannelPtr currentChannel = GetPlayingChannel();
- return currentChannel && currentChannel->IsRecording();
+ return currentChannel && CServiceBroker::GetPVRManager().Timers()->IsRecordingOnChannel(*currentChannel);
}
bool CPVRManager::CanRecordOnPlayingChannel(void) const
@@ -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/addons/PVRClients.cpp b/xbmc/pvr/addons/PVRClients.cpp
index 36dd2717d8..54f79330e4 100644
--- a/xbmc/pvr/addons/PVRClients.cpp
+++ b/xbmc/pvr/addons/PVRClients.cpp
@@ -233,7 +233,8 @@ void CPVRClients::OnAddonEvent(const AddonEvent& event)
typeid(event) == typeid(AddonEvents::ReInstalled))
{
// update addons
- CJobManager::GetInstance().AddJob(new CPVRUpdateAddonsJob(event.id), nullptr);
+ if (CServiceBroker::GetAddonMgr().HasType(event.id, ADDON_PVRDLL))
+ CJobManager::GetInstance().AddJob(new CPVRUpdateAddonsJob(event.id), nullptr);
}
}
diff --git a/xbmc/pvr/channels/PVRChannel.cpp b/xbmc/pvr/channels/PVRChannel.cpp
index 173100c0ea..3ddc457369 100644
--- a/xbmc/pvr/channels/PVRChannel.cpp
+++ b/xbmc/pvr/channels/PVRChannel.cpp
@@ -19,9 +19,8 @@
#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"
using namespace PVR;
@@ -49,7 +48,6 @@ CPVRChannel::CPVRChannel(bool bRadio /* = false */)
m_bChanged = false;
m_iEpgId = -1;
- m_bEPGCreated = false;
m_bEPGEnabled = true;
m_strEPGScraper = "client";
@@ -79,7 +77,6 @@ CPVRChannel::CPVRChannel(const PVR_CHANNEL &channel, unsigned int iClientId)
m_bEPGEnabled = !channel.bIsHidden;
m_strEPGScraper = "client";
m_iEpgId = -1;
- m_bEPGCreated = false;
m_bChanged = false;
if (m_strChannelName.empty())
@@ -115,7 +112,7 @@ void CPVRChannel::Serialize(CVariant& value) const
if (epg)
epg->Serialize(value["broadcastnext"]);
- value["isrecording"] = IsRecording();
+ value["isrecording"] = false; // compat
}
/********** XBMC related channel methods **********/
@@ -130,11 +127,10 @@ bool CPVRChannel::Delete(void)
const CPVREpgPtr epg = GetEPG();
if (epg)
{
- epg->SetChannel(CPVRChannelPtr());
CServiceBroker::GetPVRManager().EpgContainer().DeleteEpg(epg, true);
CSingleLock lock(m_critSection);
- m_bEPGCreated = false;
+ m_epg.reset();
}
bReturn = database->Delete(*this);
@@ -143,28 +139,26 @@ bool CPVRChannel::Delete(void)
CPVREpgPtr CPVRChannel::GetEPG(void) const
{
- int iEpgId(-1);
- {
- CSingleLock lock(m_critSection);
- if (!m_bIsHidden && m_bEPGEnabled && m_iEpgId > 0)
- iEpgId = m_iEpgId;
- }
+ CSingleLock lock(m_critSection);
+ if (!m_bIsHidden && m_bEPGEnabled)
+ return m_epg;
- return iEpgId > 0 ? CServiceBroker::GetPVRManager().EpgContainer().GetById(iEpgId) : CPVREpgPtr();
+ return {};
}
-bool CPVRChannel::CreateEPG(bool bForce)
+bool CPVRChannel::CreateEPG()
{
CSingleLock lock(m_critSection);
- if (!m_bEPGCreated || bForce)
+ if (!m_epg)
{
- const CPVREpgPtr epg = CServiceBroker::GetPVRManager().EpgContainer().CreateChannelEpg(shared_from_this());
- if (epg)
+ m_epg = CServiceBroker::GetPVRManager().EpgContainer().CreateChannelEpg(m_iEpgId,
+ m_strEPGScraper,
+ std::make_shared<CPVREpgChannelData>(*this));
+ if (m_epg)
{
- m_bEPGCreated = true;
- if (epg->EpgID() != m_iEpgId)
+ if (m_epg->EpgID() != m_iEpgId)
{
- m_iEpgId = epg->EpgID();
+ m_iEpgId = m_epg->EpgID();
m_bChanged = true;
}
return true;
@@ -230,6 +224,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 +251,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 +274,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;
@@ -287,30 +299,17 @@ void CPVRChannel::SetRadioRDSInfoTag(const std::shared_ptr<CPVRRadioRDSInfoTag>&
m_rdsTag = tag;
}
-bool CPVRChannel::IsRecording(void) const
-{
- return CServiceBroker::GetPVRManager().Timers()->IsRecordingOnChannel(*this);
-}
-
-CPVRRecordingPtr CPVRChannel::GetRecording(void) const
-{
- const CPVREpgInfoTagPtr epgTag = GetEPGNow();
- return (epgTag && epgTag->HasRecording()) ? epgTag->Recording() : CPVRRecordingPtr();
-}
-
-bool CPVRChannel::HasRecording(void) const
-{
- const CPVREpgInfoTagPtr epgTag = GetEPGNow();
- return epgTag && epgTag->HasRecording();
-}
-
bool CPVRChannel::SetIconPath(const std::string &strIconPath, bool bIsUserSetIcon /* = false */)
{
CSingleLock lock(m_critSection);
-
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();
@@ -341,8 +340,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;
}
@@ -353,7 +357,14 @@ 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();
@@ -386,17 +397,14 @@ bool CPVRChannel::SetClientID(int iClientId)
return false;
}
-void CPVRChannel::UpdatePath(CPVRChannelGroupInternal* group)
+void CPVRChannel::UpdatePath(const std::string& groupPath)
{
- if (!group)
- return;
-
const CPVRClientPtr client = CServiceBroker::GetPVRManager().GetClient(m_iClientId);
if (client)
{
CSingleLock lock(m_critSection);
const std::string strFileNameAndPath = StringUtils::Format("%s%s_%d.pvr",
- group->GetPath(),
+ groupPath,
client->ID().c_str(),
m_iUniqueId);
if (m_strFileNameAndPath != strFileNameAndPath)
@@ -519,16 +527,16 @@ void CPVRChannel::UpdateEncryptionName(void)
/********** EPG methods **********/
-int CPVRChannel::GetEPG(CFileItemList &results) const
+std::vector<std::shared_ptr<CPVREpgInfoTag>> CPVRChannel::GetEpgTags() const
{
const CPVREpgPtr epg = GetEPG();
if (!epg)
{
CLog::LogFC(LOGDEBUG, LOGPVR, "Cannot get EPG for channel '%s'", m_strChannelName.c_str());
- return -1;
+ return {};
}
- return epg->Get(results);
+ return epg->GetTags();
}
bool CPVRChannel::ClearEPG() const
@@ -577,11 +585,16 @@ 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;
/* clear the previous EPG entries if needed */
- if (!m_bEPGEnabled && m_bEPGCreated)
+ if (!m_bEPGEnabled && m_epg)
ClearEPG();
return true;
@@ -603,7 +616,7 @@ bool CPVRChannel::SetEPGScraper(const std::string &strScraper)
m_bChanged = true;
/* clear the previous EPG entries if needed */
- if (bCleanEPG && m_bEPGEnabled && m_bEPGCreated)
+ if (bCleanEPG && m_bEPGEnabled && m_epg)
ClearEPG();
return true;
@@ -615,7 +628,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
@@ -765,10 +785,10 @@ int CPVRChannel::EpgID(void) const
void CPVRChannel::SetEpgID(int iEpgId)
{
CSingleLock lock(m_critSection);
-
if (m_iEpgId != iEpgId)
{
m_iEpgId = iEpgId;
+ m_epg.reset();
SetChanged();
m_bChanged = true;
}
diff --git a/xbmc/pvr/channels/PVRChannel.h b/xbmc/pvr/channels/PVRChannel.h
index 243ef7a3af..cf040c3e58 100644
--- a/xbmc/pvr/channels/PVRChannel.h
+++ b/xbmc/pvr/channels/PVRChannel.h
@@ -11,6 +11,7 @@
#include <memory>
#include <string>
#include <utility>
+#include <vector>
#include "addons/kodi-addon-dev-kit/include/kodi/xbmc_pvr_types.h"
#include "threads/CriticalSection.h"
@@ -22,18 +23,16 @@
#include "pvr/PVRTypes.h"
class CVariant;
-class CFileItemList;
namespace PVR
{
- class CPVRChannelGroupInternal;
+ class CPVREpg;
class CPVRRadioRDSInfoTag;
/** PVR Channel class */
class CPVRChannel : public Observable,
public ISerializable,
- public ISortable,
- public std::enable_shared_from_this<CPVRChannel>
+ public ISortable
{
friend class CPVRDatabase;
@@ -140,16 +139,6 @@ namespace PVR
bool SetLocked(bool bIsLocked);
/*!
- * @return True if a recording is currently running on this channel. False if not.
- */
- bool IsRecording(void) const;
-
- /*!
- * @return If recording, gets the recording if the add-on provides the epg id in recordings
- */
- CPVRRecordingPtr GetRecording(void) const;
-
- /*!
* @brief Obtain the Radio RDS data for this channel, if available.
* @return The Radio RDS data or nullptr.
*/
@@ -162,11 +151,6 @@ namespace PVR
void SetRadioRDSInfoTag(const std::shared_ptr<CPVRRadioRDSInfoTag>& tag);
/*!
- * @return True if this channel has a corresponding recording, false otherwise
- */
- bool HasRecording(void) const;
-
- /*!
* @return The path to the icon for this channel.
*/
std::string IconPath(void) const;
@@ -292,10 +276,10 @@ namespace PVR
void ToSortable(SortItem& sortable, Field field) const override;
/*!
- * @brief Update the path this channel got added to the internal group
- * @param group The internal group that contains this channel
+ * @brief Update the channel path
+ * @param groupPath The new path of the group this channel belongs to
*/
- void UpdatePath(CPVRChannelGroupInternal* group);
+ void UpdatePath(const std::string& groupPath);
/*!
* @return Storage id for this channel in CPVRChannelGroup
@@ -345,10 +329,9 @@ namespace PVR
/*!
* @brief Create the EPG for this channel, if it does not yet exist
- * @param bForce to create a new EPG, even if it already exists.
* @return true if a new epg was created, false otherwise.
*/
- bool CreateEPG(bool bForce);
+ bool CreateEPG();
/*!
* @brief Get the EPG table for this channel.
@@ -357,11 +340,10 @@ namespace PVR
CPVREpgPtr GetEPG(void) const;
/*!
- * @brief Get the EPG table for this channel.
- * @param results The file list to store the results in.
- * @return The number of tables that were added.
+ * @brief Get the EPG tags for this channel.
+ * @return The tags.
*/
- int GetEPG(CFileItemList &results) const;
+ std::vector<std::shared_ptr<CPVREpgInfoTag>> GetEpgTags() const;
/*!
* @brief Clear the EPG for this channel.
@@ -464,9 +446,9 @@ namespace PVR
*/
//@{
int m_iEpgId; /*!< the id of the EPG for this channel */
- bool m_bEPGCreated; /*!< true if an EPG has been created for this channel */
bool m_bEPGEnabled; /*!< don't use an EPG for this channel if set to false */
std::string m_strEPGScraper; /*!< the name of the scraper to be used for this channel */
+ std::shared_ptr<CPVREpg> m_epg;
//@}
/*! @name Client related channel data
diff --git a/xbmc/pvr/channels/PVRChannelGroup.cpp b/xbmc/pvr/channels/PVRChannelGroup.cpp
index 4293a18cf5..ac140fcae2 100644
--- a/xbmc/pvr/channels/PVRChannelGroup.cpp
+++ b/xbmc/pvr/channels/PVRChannelGroup.cpp
@@ -29,7 +29,7 @@
#include "pvr/PVRGUIProgressHandler.h"
#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;
@@ -39,18 +39,24 @@ CPVRChannelGroup::CPVRChannelGroup(void)
OnInit();
}
-CPVRChannelGroup::CPVRChannelGroup(bool bRadio, unsigned int iGroupId, const std::string &strGroupName) :
+CPVRChannelGroup::CPVRChannelGroup(bool bRadio,
+ unsigned int iGroupId,
+ const std::string& strGroupName,
+ const std::shared_ptr<CPVRChannelGroup>& allChannelsGroup) :
m_bRadio(bRadio),
m_iGroupId(iGroupId),
- m_strGroupName(strGroupName)
+ m_strGroupName(strGroupName),
+ m_allChannelsGroup(allChannelsGroup)
{
OnInit();
}
-CPVRChannelGroup::CPVRChannelGroup(const PVR_CHANNEL_GROUP &group) :
+CPVRChannelGroup::CPVRChannelGroup(const PVR_CHANNEL_GROUP& group,
+ const std::shared_ptr<CPVRChannelGroup>& allChannelsGroup) :
m_bRadio(group.bIsRadio),
m_strGroupName(group.strGroupName),
- m_iPosition(group.iPosition)
+ m_iPosition(group.iPosition),
+ m_allChannelsGroup(allChannelsGroup)
{
OnInit();
}
@@ -73,6 +79,8 @@ CPVRChannelGroup::CPVRChannelGroup(const CPVRChannelGroup &group) :
m_iPosition = group.m_iPosition;
m_failedClientsForChannels = group.m_failedClientsForChannels;
m_failedClientsForChannelGroupMembers = group.m_failedClientsForChannelGroupMembers;
+ m_allChannelsGroup = group.m_allChannelsGroup;
+
OnInit();
}
@@ -106,7 +114,7 @@ void CPVRChannelGroup::OnInit(void)
});
}
-bool CPVRChannelGroup::Load(void)
+bool CPVRChannelGroup::Load(std::vector<std::shared_ptr<CPVRChannel>>& channelsToRemove)
{
/* make sure this container is empty before loading */
Unload();
@@ -118,7 +126,7 @@ bool CPVRChannelGroup::Load(void)
int iChannelCount = m_iGroupId > 0 ? LoadFromDb() : 0;
CLog::LogFC(LOGDEBUG, LOGPVR, "%d channels loaded from the database for group '%s'", iChannelCount, m_strGroupName.c_str());
- if (!Update())
+ if (!Update(channelsToRemove))
{
CLog::LogF(LOGERROR, "Failed to update channels for group '%s', m_strGroupName.c_str()");
return false;
@@ -146,17 +154,17 @@ void CPVRChannelGroup::Unload(void)
m_failedClientsForChannelGroupMembers.clear();
}
-bool CPVRChannelGroup::Update(void)
+bool CPVRChannelGroup::Update(std::vector<std::shared_ptr<CPVRChannel>>& channelsToRemove)
{
if (GroupType() == PVR_GROUP_TYPE_USER_DEFINED ||
!CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool(CSettings::SETTING_PVRMANAGER_SYNCCHANNELGROUPS))
return true;
- CPVRChannelGroup PVRChannels_tmp(m_bRadio, m_iGroupId, m_strGroupName);
+ CPVRChannelGroup PVRChannels_tmp(m_bRadio, m_iGroupId, m_strGroupName, m_allChannelsGroup);
PVRChannels_tmp.SetPreventSortAndRenumber();
PVRChannels_tmp.LoadFromClients();
m_failedClientsForChannelGroupMembers = PVRChannels_tmp.m_failedClientsForChannelGroupMembers;
- return UpdateGroupEntries(PVRChannels_tmp);
+ return UpdateGroupEntries(PVRChannels_tmp, channelsToRemove);
}
std::string CPVRChannelGroup::GetPath() const
@@ -522,18 +530,6 @@ void CPVRChannelGroup::GetChannelNumbers(std::vector<std::string>& channelNumber
channelNumbers.emplace_back(member.channelNumber.FormattedChannelNumber());
}
-CPVRChannelGroupPtr CPVRChannelGroup::GetNextGroup(void) const
-{
- return CServiceBroker::GetPVRManager().ChannelGroups()->Get(m_bRadio)->GetNextGroup(*this);
-}
-
-CPVRChannelGroupPtr CPVRChannelGroup::GetPreviousGroup(void) const
-{
- return CServiceBroker::GetPVRManager().ChannelGroups()->Get(m_bRadio)->GetPreviousGroup(*this);
-}
-
-/********** private methods **********/
-
int CPVRChannelGroup::LoadFromDb(bool bCompress /* = false */)
{
const CPVRDatabasePtr database(CServiceBroker::GetPVRManager().GetTVDatabase());
@@ -542,11 +538,7 @@ int CPVRChannelGroup::LoadFromDb(bool bCompress /* = false */)
int iChannelCount = Size();
- const CPVRChannelGroupPtr allGroup = CServiceBroker::GetPVRManager().ChannelGroups()->GetGroupAll(IsRadio());
- if (!allGroup)
- return -1;
-
- database->Get(*this, *allGroup);
+ database->Get(*this, *m_allChannelsGroup);
return Size() - iChannelCount;
}
@@ -560,14 +552,13 @@ bool CPVRChannelGroup::LoadFromClients(void)
bool CPVRChannelGroup::AddAndUpdateChannels(const CPVRChannelGroup &channels, bool bUseBackendChannelNumbers)
{
bool bReturn(false);
- const CPVRChannelGroupPtr groupAll(CServiceBroker::GetPVRManager().ChannelGroups()->GetGroupAll(m_bRadio));
/* go through the channel list and check for new channels.
channels will only by updated in CPVRChannelGroupInternal to prevent dupe updates */
for (PVR_CHANNEL_GROUP_MEMBERS::const_iterator it = channels.m_members.begin(); it != channels.m_members.end(); ++it)
{
/* check whether this channel is known in the internal group */
- const PVRChannelGroupMember& existingChannel(groupAll->GetByUniqueID(it->first));
+ const PVRChannelGroupMember& existingChannel(m_allChannelsGroup->GetByUniqueID(it->first));
if (!existingChannel.channel)
continue;
@@ -633,7 +624,7 @@ std::vector<CPVRChannelPtr> CPVRChannelGroup::RemoveDeletedChannels(const CPVRCh
return removedChannels;
}
-bool CPVRChannelGroup::UpdateGroupEntries(const CPVRChannelGroup &channels)
+bool CPVRChannelGroup::UpdateGroupEntries(const CPVRChannelGroup& channels, std::vector<std::shared_ptr<CPVRChannel>>& channelsToRemove)
{
bool bReturn(false);
bool bChanged(false);
@@ -644,7 +635,8 @@ bool CPVRChannelGroup::UpdateGroupEntries(const CPVRChannelGroup &channels)
bool bUseBackendChannelNumbers(m_members.empty() || m_bUsingBackendChannelOrder);
SetPreventSortAndRenumber(true);
- bRemoved = !RemoveDeletedChannels(channels).empty();
+ channelsToRemove = RemoveDeletedChannels(channels);
+ bRemoved = !channelsToRemove.empty();
bChanged = AddAndUpdateChannels(channels, bUseBackendChannelNumbers) || bRemoved;
SetPreventSortAndRenumber(false);
@@ -703,14 +695,13 @@ bool CPVRChannelGroup::RemoveFromGroup(const CPVRChannelPtr &channel)
bool CPVRChannelGroup::AddToGroup(const CPVRChannelPtr &channel, const CPVRChannelNumber &channelNumber, bool bUseBackendChannelNumbers)
{
bool bReturn(false);
- const CPVRChannelGroupPtr groupAll(CServiceBroker::GetPVRManager().ChannelGroups()->GetGroupAll(m_bRadio));
CSingleLock lock(m_critSection);
if (!CPVRChannelGroup::IsGroupMember(channel))
{
const PVRChannelGroupMember& realChannel(IsInternalGroup() ?
GetByUniqueID(channel->StorageId()) :
- groupAll->GetByUniqueID(channel->StorageId()));
+ m_allChannelsGroup->GetByUniqueID(channel->StorageId()));
if (realChannel.channel)
{
@@ -814,9 +805,6 @@ bool CPVRChannelGroup::Renumber(void)
unsigned int iChannelNumber(0);
bool bUseBackendChannelNumbers(CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool(CSettings::SETTING_PVRMANAGER_USEBACKENDCHANNELNUMBERS) &&
CServiceBroker::GetPVRManager().Clients()->EnabledClientAmount() == 1);
- CPVRChannelGroupPtr groupAll;
- if (!bUseBackendChannelNumbers && !IsInternalGroup())
- groupAll = CServiceBroker::GetPVRManager().ChannelGroups()->GetGroupAll(m_bRadio);
CSingleLock lock(m_critSection);
@@ -836,7 +824,7 @@ bool CPVRChannelGroup::Renumber(void)
if (IsInternalGroup())
currentChannelNumber = CPVRChannelNumber(++iChannelNumber, 0);
else
- currentChannelNumber = groupAll->GetChannelNumber((*it).channel);
+ currentChannelNumber = m_allChannelsGroup->GetChannelNumber((*it).channel);
}
if ((*it).channelNumber != currentChannelNumber)
@@ -925,9 +913,10 @@ void CPVRChannelGroup::OnSettingChanged(std::shared_ptr<const CSetting> setting)
}
}
-int CPVRChannelGroup::GetEPGAll(CFileItemList &results, bool bIncludeChannelsWithoutEPG /* = false */) const
+std::vector<std::shared_ptr<CPVREpgInfoTag>> CPVRChannelGroup::GetEPGAll(bool bIncludeChannelsWithoutEPG /* = false */) const
{
- int iInitialSize = results.Size();
+ std::vector<std::shared_ptr<CPVREpgInfoTag>> tags;
+
CPVREpgInfoTagPtr epgTag;
CPVRChannelPtr channel;
CSingleLock lock(m_critSection);
@@ -937,26 +926,31 @@ int CPVRChannelGroup::GetEPGAll(CFileItemList &results, bool bIncludeChannelsWit
channel = (*it).channel;
if (!channel->IsHidden())
{
- int iAdded = 0;
+ bool bEmpty = false;
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);
+ const std::vector<std::shared_ptr<CPVREpgInfoTag>> epgTags = epg->GetTags();
+ bEmpty = epgTags.empty();
+ if (!bEmpty)
+ tags.insert(tags.end(), epgTags.begin(), epgTags.end());
}
- if (bIncludeChannelsWithoutEPG && iAdded == 0)
+ if (bIncludeChannelsWithoutEPG && bEmpty)
{
// Add dummy EPG tag associated with this channel
- epgTag = std::make_shared<CPVREpgInfoTag>(channel);
- results.Add(std::make_shared<CFileItem>(epgTag));
+ if (epg)
+ epgTag = std::make_shared<CPVREpgInfoTag>(epg->GetChannelData(), epg->EpgID());
+ else
+ epgTag = std::make_shared<CPVREpgInfoTag>(std::make_shared<CPVREpgChannelData>(*channel), -1);
+
+ tags.emplace_back(epgTag);
}
}
}
- return results.Size() - iInitialSize;
+ return tags;
}
CDateTime CPVRChannelGroup::GetEPGDate(EpgDateType epgDateType) const
diff --git a/xbmc/pvr/channels/PVRChannelGroup.h b/xbmc/pvr/channels/PVRChannelGroup.h
index de3e5ce5a6..eca9feb89d 100644
--- a/xbmc/pvr/channels/PVRChannelGroup.h
+++ b/xbmc/pvr/channels/PVRChannelGroup.h
@@ -22,6 +22,8 @@
class CFileItem;
typedef std::shared_ptr<CFileItem> CFileItemPtr;
+class CFileItemList;
+
namespace PVR
{
#define PVR_GROUP_TYPE_DEFAULT 0
@@ -64,14 +66,16 @@ namespace PVR
* @param bRadio True if this group holds radio channels.
* @param iGroupId The database ID of this group.
* @param strGroupName The name of this group.
+ * @param allChannelsGroup The channel group containing all TV or radio channels.
*/
- CPVRChannelGroup(bool bRadio, unsigned int iGroupId, const std::string &strGroupName);
+ CPVRChannelGroup(bool bRadio, unsigned int iGroupId, const std::string& strGroupName, const std::shared_ptr<CPVRChannelGroup>& allChannelsGroup);
/*!
* @brief Create a new channel group instance from a channel group provided by an add-on.
* @param group The channel group provided by the add-on.
+ * @param allChannelsGroup The channel group containing all TV or radio channels.
*/
- explicit CPVRChannelGroup(const PVR_CHANNEL_GROUP &group);
+ CPVRChannelGroup(const PVR_CHANNEL_GROUP& group, const std::shared_ptr<CPVRChannelGroup>& allChannelsGroup);
/*!
* @brief Copy constructor
@@ -91,9 +95,10 @@ namespace PVR
/*!
* @brief Load the channels from the database.
+ * @param channelsToRemove Returns the channels to be removed from all groups, if any
* @return True when loaded successfully, false otherwise.
*/
- virtual bool Load(void);
+ virtual bool Load(std::vector<std::shared_ptr<CPVRChannel>>& channelsToRemove);
/*!
* @return The amount of group members
@@ -102,8 +107,9 @@ namespace PVR
/*!
* @brief Refresh the channel list from the clients.
+ * @param channelsToRemove Returns the channels to be removed from all groups, if any
*/
- virtual bool Update(void);
+ virtual bool Update(std::vector<std::shared_ptr<CPVRChannel>>& channelsToRemove);
/*!
* @brief Get the path of this group.
@@ -336,16 +342,6 @@ namespace PVR
void GetChannelNumbers(std::vector<std::string>& channelNumbers) const;
/*!
- * @return The next channel group.
- */
- CPVRChannelGroupPtr GetNextGroup(void) const;
-
- /*!
- * @return The previous channel group.
- */
- CPVRChannelGroupPtr GetPreviousGroup(void) const;
-
- /*!
* @brief The amount of hidden channels in this container.
* @return The amount of hidden channels in this container.
*/
@@ -380,12 +376,11 @@ namespace PVR
virtual bool CreateChannelEpgs(bool bForce = false);
/*!
- * @brief Get all EPG tables.
- * @param results The fileitem list to store the results in.
+ * @brief Get all EPG tags for all channels in this group.
* @param bIncludeChannelsWithoutEPG, for channels without EPG data, put an empty EPG tag associated with the channel into results
- * @return The amount of entries that were added.
+ * @return The tags.
*/
- int GetEPGAll(CFileItemList &results, bool bIncludeChannelsWithoutEPG = false) const;
+ std::vector<std::shared_ptr<CPVREpgInfoTag>> GetEPGAll(bool bIncludeChannelsWithoutEPG = false) const;
/*!
* @brief Get the start time of the first entry.
@@ -457,9 +452,10 @@ namespace PVR
* Only the new channels will be present in the passed list after this call.
*
* @param channels The channels to use to update this list.
+ * @param channelsToRemove Returns the channels to be removed from all groups, if any
* @return True if everything went well, false otherwise.
*/
- virtual bool UpdateGroupEntries(const CPVRChannelGroup &channels);
+ virtual bool UpdateGroupEntries(const CPVRChannelGroup& channels, std::vector<std::shared_ptr<CPVRChannel>>& channelsToRemove);
/*!
* @brief Add new channels to this group; updtae data.
@@ -522,5 +518,7 @@ namespace PVR
private:
CDateTime GetEPGDate(EpgDateType epgDateType) const;
+
+ std::shared_ptr<CPVRChannelGroup> m_allChannelsGroup;
};
}
diff --git a/xbmc/pvr/channels/PVRChannelGroupInternal.cpp b/xbmc/pvr/channels/PVRChannelGroupInternal.cpp
index 4f95705f36..015fa291ba 100644
--- a/xbmc/pvr/channels/PVRChannelGroupInternal.cpp
+++ b/xbmc/pvr/channels/PVRChannelGroupInternal.cpp
@@ -22,9 +22,7 @@
#include "pvr/PVRDatabase.h"
#include "pvr/PVRManager.h"
#include "pvr/addons/PVRClients.h"
-#include "pvr/channels/PVRChannelGroupsContainer.h"
#include "pvr/epg/EpgContainer.h"
-#include "pvr/timers/PVRTimers.h"
using namespace PVR;
using namespace KODI::MESSAGING;
@@ -49,9 +47,9 @@ CPVRChannelGroupInternal::~CPVRChannelGroupInternal(void)
CServiceBroker::GetPVRManager().Events().Unsubscribe(this);
}
-bool CPVRChannelGroupInternal::Load(void)
+bool CPVRChannelGroupInternal::Load(std::vector<std::shared_ptr<CPVRChannel>>& channelsToRemove)
{
- if (CPVRChannelGroup::Load())
+ if (CPVRChannelGroup::Load(channelsToRemove))
{
UpdateChannelPaths();
CServiceBroker::GetPVRManager().Events().Subscribe(this, &CPVRChannelGroupInternal::OnPVRManagerEvent);
@@ -84,7 +82,7 @@ void CPVRChannelGroupInternal::UpdateChannelPaths(void)
if (it->second.channel->IsHidden())
++m_iHiddenChannels;
else
- it->second.channel->UpdatePath(this);
+ it->second.channel->UpdatePath(GetPath());
}
}
@@ -104,7 +102,7 @@ CPVRChannelPtr CPVRChannelGroupInternal::UpdateFromClient(const CPVRChannelPtr &
iChannelNumber = static_cast<int>(m_sortedMembers.size()) + 1;
PVRChannelGroupMember newMember(channel, CPVRChannelNumber(iChannelNumber, channelNumber.GetSubChannelNumber()), 0);
- channel->UpdatePath(this);
+ channel->UpdatePath(GetPath());
m_sortedMembers.push_back(newMember);
m_members.insert(std::make_pair(channel->StorageId(), newMember));
m_bChanged = true;
@@ -114,13 +112,13 @@ CPVRChannelPtr CPVRChannelGroupInternal::UpdateFromClient(const CPVRChannelPtr &
return channel;
}
-bool CPVRChannelGroupInternal::Update(void)
+bool CPVRChannelGroupInternal::Update(std::vector<std::shared_ptr<CPVRChannel>>& channelsToRemove)
{
CPVRChannelGroupInternal PVRChannels_tmp(m_bRadio);
PVRChannels_tmp.SetPreventSortAndRenumber();
PVRChannels_tmp.LoadFromClients();
m_failedClientsForChannels = PVRChannels_tmp.m_failedClientsForChannels;
- return UpdateGroupEntries(PVRChannels_tmp);
+ return UpdateGroupEntries(PVRChannels_tmp, channelsToRemove);
}
bool CPVRChannelGroupInternal::AddToGroup(const CPVRChannelPtr &channel, const CPVRChannelNumber &channelNumber, bool bUseBackendChannelNumbers)
@@ -270,12 +268,8 @@ std::vector<CPVRChannelPtr> CPVRChannelGroupInternal::RemoveDeletedChannels(cons
if (!removedChannels.empty())
{
- CPVRChannelGroups* groups = CServiceBroker::GetPVRManager().ChannelGroups()->Get(m_bRadio);
for (const auto& channel : removedChannels)
{
- /* remove this channel from all non-system groups */
- groups->RemoveFromAllGroups(channel);
-
/* do we have valid data from channel's client? */
if (!IsMissingChannelsFromClient(channel->ClientID()))
{
@@ -288,17 +282,16 @@ std::vector<CPVRChannelPtr> CPVRChannelGroupInternal::RemoveDeletedChannels(cons
return removedChannels;
}
-bool CPVRChannelGroupInternal::UpdateGroupEntries(const CPVRChannelGroup &channels)
+bool CPVRChannelGroupInternal::UpdateGroupEntries(const CPVRChannelGroup& channels, std::vector<std::shared_ptr<CPVRChannel>>& channelsToRemove)
{
bool bReturn(false);
- if (CPVRChannelGroup::UpdateGroupEntries(channels))
+ if (CPVRChannelGroup::UpdateGroupEntries(channels, channelsToRemove))
{
/* try to find channel icons */
if (CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_bPVRChannelIconsAutoScan)
SearchAndSetChannelIcons();
- CServiceBroker::GetPVRManager().Timers()->UpdateChannels();
Persist();
bReturn = true;
@@ -307,10 +300,10 @@ bool CPVRChannelGroupInternal::UpdateGroupEntries(const CPVRChannelGroup &channe
return bReturn;
}
-void CPVRChannelGroupInternal::CreateChannelEpg(const CPVRChannelPtr &channel, bool bForce /* = false */)
+void CPVRChannelGroupInternal::CreateChannelEpg(const std::shared_ptr<CPVRChannel>& channel)
{
if (channel)
- channel->CreateEPG(bForce);
+ channel->CreateEPG();
}
bool CPVRChannelGroupInternal::CreateChannelEpgs(bool bForce /* = false */)
diff --git a/xbmc/pvr/channels/PVRChannelGroupInternal.h b/xbmc/pvr/channels/PVRChannelGroupInternal.h
index bcf5adf0db..7dc4a87d80 100644
--- a/xbmc/pvr/channels/PVRChannelGroupInternal.h
+++ b/xbmc/pvr/channels/PVRChannelGroupInternal.h
@@ -95,9 +95,10 @@ namespace PVR
* Only the new channels will be present in the passed list after this call.
*
* @param channels The channels to use to update this list.
+ * @param channelsToRemove Returns the channels to be removed from all groups, if any
* @return True if everything went well, false otherwise.
*/
- bool UpdateGroupEntries(const CPVRChannelGroup &channels) override;
+ bool UpdateGroupEntries(const CPVRChannelGroup& channels, std::vector<std::shared_ptr<CPVRChannel>>& channelsToRemove) override;
/*!
* @brief Add new channels to this group; updtae data.
@@ -116,8 +117,9 @@ namespace PVR
/*!
* @brief Refresh the channel list from the clients.
+ * @param channelsToRemove Returns the channels to be removed from all groups, if any
*/
- bool Update(void) override;
+ bool Update(std::vector<std::shared_ptr<CPVRChannel>>& channelsToRemove) override;
/*!
* @brief Load the channels from the database.
@@ -125,16 +127,17 @@ namespace PVR
* Load the channels from the database.
* If no channels are stored in the database, then the channels will be loaded from the clients.
*
+ * @param channelsToRemove Returns the channels to be removed from all groups, if any
* @return True when loaded successfully, false otherwise.
*/
- bool Load(void) override;
+ bool Load(std::vector<std::shared_ptr<CPVRChannel>>& channelsToRemove) override;
/*!
* @brief Update the vfs paths of all channels.
*/
void UpdateChannelPaths(void);
- void CreateChannelEpg(const CPVRChannelPtr &channel, bool bForce = false);
+ void CreateChannelEpg(const std::shared_ptr<CPVRChannel>& channel);
size_t m_iHiddenChannels; /*!< the amount of hidden channels in this container */
diff --git a/xbmc/pvr/channels/PVRChannelGroups.cpp b/xbmc/pvr/channels/PVRChannelGroups.cpp
index bf4b1d9286..9218c3852b 100644
--- a/xbmc/pvr/channels/PVRChannelGroups.cpp
+++ b/xbmc/pvr/channels/PVRChannelGroups.cpp
@@ -76,7 +76,7 @@ bool CPVRChannelGroups::Update(const CPVRChannelGroup &group, bool bUpdateFromCl
{
// create a new group if none was found. Copy the properties immediately
// so the group doesn't get flagged as "changed" further down.
- updateGroup = CPVRChannelGroupPtr(new CPVRChannelGroup(group.IsRadio(), group.GroupID(), group.GroupName()));
+ updateGroup.reset(new CPVRChannelGroup(group.IsRadio(), group.GroupID(), group.GroupName(), GetGroupAll()));
m_groups.push_back(updateGroup);
}
@@ -189,6 +189,15 @@ CPVRChannelGroupPtr CPVRChannelGroups::GetByName(const std::string &strName) con
return empty;
}
+void CPVRChannelGroups::RemoveFromAllGroups(const std::vector<std::shared_ptr<CPVRChannel>>& channelsToRemove)
+{
+ for (const auto& channel : channelsToRemove)
+ {
+ // remove this channel from all non-system groups
+ RemoveFromAllGroups(channel);
+ }
+}
+
void CPVRChannelGroups::RemoveFromAllGroups(const CPVRChannelPtr &channel)
{
CSingleLock lock(m_critSection);
@@ -221,7 +230,11 @@ bool CPVRChannelGroups::Update(bool bChannelsOnly /* = false */)
for (const auto &group : groups)
{
if (bUpdateAllGroups || group->IsInternalGroup())
- bReturn = group->Update() && bReturn;
+ {
+ std::vector<std::shared_ptr<CPVRChannel>> channelsToRemove;
+ bReturn = group->Update(channelsToRemove) && bReturn;
+ RemoveFromAllGroups(channelsToRemove);
+ }
}
// persist changes
@@ -252,12 +265,15 @@ bool CPVRChannelGroups::LoadUserDefinedChannelGroups(void)
// load only user defined groups, as internal group is already loaded
if (!(*it)->IsInternalGroup())
{
- if (!(*it)->Load())
+ std::vector<std::shared_ptr<CPVRChannel>> channelsToRemove;
+ if (!(*it)->Load(channelsToRemove))
{
CLog::LogFC(LOGDEBUG, LOGPVR, "Failed to load user defined channel group '%s'", (*it)->GroupName().c_str());
return false;
}
+ RemoveFromAllGroups(channelsToRemove);
+
// remove empty groups when sync with backend is enabled
if (bSyncWithBackends && (*it)->Size() == 0)
emptyGroups.push_back(*it);
@@ -296,12 +312,15 @@ bool CPVRChannelGroups::Load(void)
CLog::LogFC(LOGDEBUG, LOGPVR, "%d %s groups fetched from the database", m_groups.size(), m_bRadio ? "radio" : "TV");
// load channels of internal group
- if (!internalGroup->Load())
+ std::vector<std::shared_ptr<CPVRChannel>> channelsToRemove;
+ if (!internalGroup->Load(channelsToRemove))
{
CLog::LogF(LOGERROR, "Failed to load 'all channels' group");
return false;
}
+ RemoveFromAllGroups(channelsToRemove);
+
// load the other groups from the database
if (!LoadUserDefinedChannelGroups())
{
@@ -528,7 +547,7 @@ bool CPVRChannelGroups::DeleteGroup(const CPVRChannelGroup &group)
}
if (playingGroup)
- CServiceBroker::GetPVRManager().SetPlayingGroup(playingGroup);
+ SetSelectedGroup(playingGroup);
if (group.GroupID() > 0)
{
@@ -546,7 +565,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/PVRChannelGroups.h b/xbmc/pvr/channels/PVRChannelGroups.h
index edccd36d0b..61c853682f 100644
--- a/xbmc/pvr/channels/PVRChannelGroups.h
+++ b/xbmc/pvr/channels/PVRChannelGroups.h
@@ -179,12 +179,6 @@ namespace PVR
bool CreateChannelEpgs(void);
/*!
- * @brief Remove a channel from all non-system groups.
- * @param channel The channel to remove.
- */
- void RemoveFromAllGroups(const CPVRChannelPtr &channel);
-
- /*!
* @brief Persist all changes in channel groups.
* @return True if everything was persisted, false otherwise.
*/
@@ -207,6 +201,18 @@ namespace PVR
bool GetGroupsFromClients(void);
void SortGroups(void);
+ /*!
+ * @brief Remove the given channels from all non-system groups.
+ * @param channel The channels to remove.
+ */
+ void RemoveFromAllGroups(const std::vector<std::shared_ptr<CPVRChannel>>& channelsToRemove);
+
+ /*!
+ * @brief Remove a channel from all non-system groups.
+ * @param channel The channel to remove.
+ */
+ void RemoveFromAllGroups(const std::shared_ptr<CPVRChannel>& channel);
+
bool m_bRadio; /*!< true if this is a container for radio channels, false if it is for tv channels */
CPVRChannelGroupPtr m_selectedGroup; /*!< the group that's currently selected in the UI */
std::vector<CPVRChannelGroupPtr> m_groups; /*!< the groups in this container */
diff --git a/xbmc/pvr/channels/PVRChannelGroupsContainer.cpp b/xbmc/pvr/channels/PVRChannelGroupsContainer.cpp
index 2f879d28c8..fb47e02d2c 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 {};
+
+ 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/GUIDialogPVRChannelGuide.cpp b/xbmc/pvr/dialogs/GUIDialogPVRChannelGuide.cpp
index c0adbce456..ffda657cd6 100644
--- a/xbmc/pvr/dialogs/GUIDialogPVRChannelGuide.cpp
+++ b/xbmc/pvr/dialogs/GUIDialogPVRChannelGuide.cpp
@@ -42,7 +42,12 @@ void CGUIDialogPVRChannelGuide::OnInitWindow()
Init();
- m_channel->GetEPG(*m_vecItems);
+ const std::vector<std::shared_ptr<CPVREpgInfoTag>> tags = m_channel->GetEpgTags();
+ for (const auto& tag : tags)
+ {
+ m_vecItems->Add(std::make_shared<CFileItem>(tag));
+ }
+
m_viewControl.SetItems(*m_vecItems);
CGUIDialogPVRItemsViewBase::OnInitWindow();
diff --git a/xbmc/pvr/dialogs/GUIDialogPVRChannelsOSD.cpp b/xbmc/pvr/dialogs/GUIDialogPVRChannelsOSD.cpp
index 13805ce1d9..be73f42332 100644
--- a/xbmc/pvr/dialogs/GUIDialogPVRChannelsOSD.cpp
+++ b/xbmc/pvr/dialogs/GUIDialogPVRChannelsOSD.cpp
@@ -21,6 +21,7 @@
#include "pvr/PVRGUIActions.h"
#include "pvr/PVRManager.h"
#include "pvr/channels/PVRChannelGroup.h"
+#include "pvr/channels/PVRChannelGroupsContainer.h"
#include "pvr/epg/EpgContainer.h"
using namespace PVR;
@@ -113,7 +114,10 @@ bool CGUIDialogPVRChannelsOSD::OnAction(const CAction &action)
SaveControlStates();
// switch to next or previous group
- const CPVRChannelGroupPtr nextGroup = action.GetID() == ACTION_NEXT_CHANNELGROUP ? m_group->GetNextGroup() : m_group->GetPreviousGroup();
+ const CPVRChannelGroups* groups = CServiceBroker::GetPVRManager().ChannelGroups()->Get(m_group->IsRadio());
+ const std::shared_ptr<CPVRChannelGroup> nextGroup = action.GetID() == ACTION_NEXT_CHANNELGROUP
+ ? groups->GetNextGroup(*m_group)
+ : groups->GetPreviousGroup(*m_group);
CServiceBroker::GetPVRManager().SetPlayingGroup(nextGroup);
m_group = nextGroup;
Init();
diff --git a/xbmc/pvr/dialogs/GUIDialogPVRGuideInfo.cpp b/xbmc/pvr/dialogs/GUIDialogPVRGuideInfo.cpp
index aa95a7d76c..e2ae28ed9d 100644
--- a/xbmc/pvr/dialogs/GUIDialogPVRGuideInfo.cpp
+++ b/xbmc/pvr/dialogs/GUIDialogPVRGuideInfo.cpp
@@ -25,7 +25,9 @@
#include "pvr/PVRManager.h"
#include "pvr/channels/PVRChannelGroupsContainer.h"
#include "pvr/epg/EpgInfoTag.h"
+#include "pvr/recordings/PVRRecordings.h"
#include "pvr/timers/PVRTimerInfoTag.h"
+#include "pvr/timers/PVRTimers.h"
#include "pvr/windows/GUIWindowPVRSearch.h"
using namespace PVR;
@@ -67,15 +69,7 @@ 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 CPVRTimerInfoTagPtr timerTag(m_progItem->Timer());
+ const std::shared_ptr<CPVRTimerInfoTag> timerTag = CServiceBroker::GetPVRManager().Timers()->GetTimerForEpgTag(m_progItem);
if (timerTag)
{
const CFileItemPtr item(new CFileItem(timerTag));
@@ -103,7 +97,7 @@ bool CGUIDialogPVRGuideInfo::OnClickButtonAddTimer(CGUIMessage &message)
if (message.GetSenderId() == CONTROL_BTN_ADD_TIMER)
{
- if (m_progItem && !m_progItem->Timer())
+ if (m_progItem && !CServiceBroker::GetPVRManager().Timers()->GetTimerForEpgTag(m_progItem))
{
const CFileItemPtr item(new CFileItem(m_progItem));
bReturn = CServiceBroker::GetPVRManager().GUIActions()->AddTimerRule(item, true);
@@ -191,7 +185,7 @@ void CGUIDialogPVRGuideInfo::OnInitWindow()
return;
}
- if (!m_progItem->HasRecording())
+ if (!CServiceBroker::GetPVRManager().Recordings()->GetRecordingForEpgTag(m_progItem))
{
/* not recording. hide the play recording button */
SET_CONTROL_HIDDEN(CONTROL_BTN_PLAY_RECORDING);
@@ -200,20 +194,21 @@ void CGUIDialogPVRGuideInfo::OnInitWindow()
bool bHideRecord(true);
bool bHideAddTimer(true);
- if (m_progItem->HasTimer())
+ const std::shared_ptr<CPVRTimerInfoTag> timer = CServiceBroker::GetPVRManager().Timers()->GetTimerForEpgTag(m_progItem);
+ if (timer)
{
- if (m_progItem->Timer()->IsRecording())
+ if (timer->IsRecording())
{
SET_CONTROL_LABEL(CONTROL_BTN_RECORD, 19059); /* Stop recording */
bHideRecord = false;
}
- else if (m_progItem->Timer()->HasTimerType() && !m_progItem->Timer()->GetTimerType()->IsReadOnly())
+ else if (timer->HasTimerType() && !timer->GetTimerType()->IsReadOnly())
{
SET_CONTROL_LABEL(CONTROL_BTN_RECORD, 19060); /* Delete timer */
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 eee188f7f7..42ec788c20 100644
--- a/xbmc/pvr/epg/Epg.cpp
+++ b/xbmc/pvr/epg/Epg.cpp
@@ -12,35 +12,35 @@
#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"
+#include "settings/Settings.h"
#include "settings/SettingsComponent.h"
#include "threads/SingleLock.h"
#include "utils/log.h"
#include "pvr/PVRManager.h"
-#include "pvr/recordings/PVRRecordings.h"
-#include "pvr/timers/PVRTimers.h"
+#include "pvr/epg/EpgChannelData.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)
{
}
@@ -56,7 +56,8 @@ void CPVREpg::ForceUpdate(void)
m_bUpdatePending = true;
}
- CServiceBroker::GetPVRManager().EpgContainer().SetHasPendingUpdates(true);
+ SetChanged(true);
+ NotifyObservers(ObservableMessageEpgUpdatePending);
}
bool CPVREpg::HasValidEntries(void) const
@@ -73,9 +74,8 @@ void CPVREpg::Clear(void)
m_tags.clear();
}
-void CPVREpg::Cleanup(void)
+void CPVREpg::Cleanup(int iPastDays)
{
- int iPastDays = CServiceBroker::GetPVRManager().EpgContainer().GetPastDaysToDisplay();
const CDateTime cleanupTime = CDateTime::GetUTCDateTime() - CDateTimeSpan(iPastDays, 0, 0, 0);
Cleanup(cleanupTime);
}
@@ -90,8 +90,6 @@ void CPVREpg::Cleanup(const CDateTime &time)
if (m_nowActiveStart == it->first)
m_nowActiveStart.SetValid(false);
- it->second->ClearTimer();
- it->second->ClearRecording();
it = m_tags.erase(it);
}
else
@@ -236,75 +234,41 @@ 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);
if (tag)
{
m_tags.insert(std::make_pair(tag->StartAsUTC(), tag));
- UpdateEntry(tag, !CServiceBroker::GetPVRManager().EpgContainer().IgnoreDB());
+ UpdateEntry(tag, !CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool(CSettings::SETTING_EPG_IGNOREDBFORCLIENT));
}
}
return tag;
}
-std::vector<CPVREpgInfoTagPtr> CPVREpg::GetTagsBetween(const CDateTime &beginTime, const CDateTime &endTime) const
-{
- std::vector<CPVREpgInfoTagPtr> epgTags;
-
- CSingleLock lock(m_critSection);
- for (const auto &infoTag : m_tags)
- {
- if (infoTag.second->StartAsUTC() >= beginTime)
- {
- if (infoTag.second->EndAsUTC() <= endTime)
- epgTags.emplace_back(infoTag.second);
- else
- break; // done.
- }
- }
-
- return epgTags;
-}
-
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->SetTimer(CServiceBroker::GetPVRManager().Timers()->GetTimerForEpgTag(newTag));
- newTag->SetRecording(CServiceBroker::GetPVRManager().Recordings()->GetRecordingForEpgTag(newTag));
+ 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)
+bool CPVREpg::Load(const std::shared_ptr<CPVREpgDatabase>& database)
{
bool bReturn = false;
- CPVREpgDatabasePtr database = CServiceBroker::GetPVRManager().EpgContainer().GetEpgDatabase();
if (!database)
{
@@ -324,7 +288,15 @@ bool CPVREpg::Load(void)
for (const auto& entry : result)
AddEntry(*entry);
- m_lastScanTime = GetLastScanTime();
+ if (!m_lastScanTime.IsValid())
+ database->GetLastEpgScanTime(m_iEpgID, &m_lastScanTime);
+
+ if (!m_lastScanTime.IsValid())
+ {
+ m_lastScanTime.SetDateTime(1970, 1, 1, 0, 0, 0);
+ m_bUpdateLastScanTime = true;
+ }
+
bReturn = true;
}
@@ -343,7 +315,7 @@ bool CPVREpg::UpdateEntries(const CPVREpg &epg, bool bStoreInDb /* = true */)
FixOverlappingEvents(bStoreInDb);
/* update the last scan time of this table */
- m_lastScanTime = CDateTime::GetCurrentDateTime().GetAsUTCDateTime();
+ m_lastScanTime = CDateTime::GetUTCDateTime();
m_bUpdateLastScanTime = true;
SetChanged(true);
@@ -354,35 +326,12 @@ bool CPVREpg::UpdateEntries(const CPVREpg &epg, bool bStoreInDb /* = true */)
return true;
}
-CDateTime CPVREpg::GetLastScanTime(void)
-{
- bool bIgnore = CServiceBroker::GetPVRManager().EpgContainer().IgnoreDB();
- CPVREpgDatabasePtr database = CServiceBroker::GetPVRManager().EpgContainer().GetEpgDatabase();
-
- CDateTime lastScanTime;
- {
- CSingleLock lock(m_critSection);
-
- if (!m_lastScanTime.IsValid())
- {
- if (!bIgnore && database)
- database->GetLastEpgScanTime(m_iEpgID, &m_lastScanTime);
-
- if (!m_lastScanTime.IsValid())
- m_lastScanTime.SetDateTime(1970, 1, 1, 0, 0, 0);
- }
- lastScanTime = m_lastScanTime;
- }
-
- return lastScanTime;
-}
-
bool CPVREpg::UpdateEntry(const EPG_TAG *data, int iClientId, bool bUpdateDatabase)
{
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);
}
@@ -390,32 +339,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->Update(*tag, bNewTag);
- infoTag->SetEpg(this);
- infoTag->SetChannel(m_pvrChannel);
-
- if (bUpdateDatabase)
- m_changedTags.insert(std::make_pair(infoTag->UniqueBroadcastID(), infoTag));
+ 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->SetTimer(CServiceBroker::GetPVRManager().Timers()->GetTimerForEpgTag(infoTag));
- infoTag->SetRecording(CServiceBroker::GetPVRManager().Recordings()->GetRecordingForEpgTag(infoTag));
+ infoTag->Update(*tag, bNewTag);
+ infoTag->SetEpgID(m_iEpgID);
+
+ if (bUpdateDatabase)
+ m_changedTags.insert(std::make_pair(infoTag->UniqueBroadcastID(), infoTag));
return true;
}
@@ -446,15 +389,13 @@ bool CPVREpg::UpdateEntry(const CPVREpgInfoTagPtr &tag, EPG_EVENT_STATE newState
else
{
// Respect epg linger time.
- int iPastDays = CServiceBroker::GetPVRManager().EpgContainer().GetPastDaysToDisplay();
+ int iPastDays = CServiceBroker::GetSettingsComponent()->GetSettings()->GetInt(CSettings::SETTING_EPG_PAST_DAYSTODISPLAY);
const CDateTime cleanupTime(CDateTime::GetUTCDateTime() - CDateTimeSpan(iPastDays, 0, 0, 0));
if (it->second->EndAsUTC() < cleanupTime)
{
if (bUpdateDatabase)
m_deletedTags.insert(std::make_pair(it->second->UniqueBroadcastID(), it->second));
- it->second->ClearTimer();
- it->second->ClearRecording();
m_tags.erase(it);
}
else
@@ -478,24 +419,26 @@ bool CPVREpg::UpdateEntry(const CPVREpgInfoTagPtr &tag, EPG_EVENT_STATE newState
return bRet;
}
-bool CPVREpg::Update(const time_t start, const time_t end, int iUpdateTime, bool bForceUpdate /* = false */)
+bool CPVREpg::Update(time_t start,
+ time_t end,
+ int iUpdateTime,
+ int iPastDays,
+ const std::shared_ptr<CPVREpgDatabase>& database,
+ bool bForceUpdate /* = false */)
{
bool bGrabSuccess = true;
bool bUpdate = false;
/* load the entries from the db first */
- if (!m_bLoaded && !CServiceBroker::GetPVRManager().EpgContainer().IgnoreDB())
- Load();
+ if (!m_bLoaded && database)
+ Load(database);
/* clean up if needed */
if (m_bLoaded)
- Cleanup();
-
- /* get the last update time from the database */
- const CDateTime lastScanTime = GetLastScanTime();
+ Cleanup(iPastDays);
- /* 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)
@@ -503,8 +446,8 @@ bool CPVREpg::Update(const time_t start, const time_t end, int iUpdateTime, bool
/* check if we have to update */
time_t iNow = 0;
time_t iLastUpdate = 0;
- CDateTime::GetCurrentDateTime().GetAsUTCDateTime().GetAsTime(iNow);
- lastScanTime.GetAsTime(iLastUpdate);
+ CDateTime::GetUTCDateTime().GetAsTime(iNow);
+ m_lastScanTime.GetAsTime(iLastUpdate);
bUpdate = (iNow > iLastUpdate + iUpdateTime);
}
else
@@ -524,43 +467,22 @@ bool CPVREpg::Update(const time_t start, const time_t end, int iUpdateTime, bool
return bGrabSuccess;
}
-int CPVREpg::Get(CFileItemList &results) const
-{
- int iInitialSize = results.Size();
-
- CSingleLock lock(m_critSection);
- for (const auto& tag : m_tags)
- results.Add(std::make_shared<CFileItem>(tag.second));
-
- return results.Size() - iInitialSize;
-}
-
-int CPVREpg::Get(CFileItemList &results, const CPVREpgSearchFilter &filter) const
+std::vector<std::shared_ptr<CPVREpgInfoTag>> CPVREpg::GetTags() const
{
- int iInitialSize = results.Size();
-
- if (!HasValidEntries())
- return -1;
+ std::vector<std::shared_ptr<CPVREpgInfoTag>> tags;
CSingleLock lock(m_critSection);
for (const auto& tag : m_tags)
- {
- if (filter.FilterEntry(tag.second))
- results.Add(std::make_shared<CFileItem>(tag.second));
- }
+ tags.emplace_back(tag.second);
- return results.Size() - iInitialSize;
+ return tags;
}
-bool CPVREpg::Persist(void)
+bool CPVREpg::Persist(const std::shared_ptr<CPVREpgDatabase>& database)
{
- if (CServiceBroker::GetPVRManager().EpgContainer().IgnoreDB() || !NeedsSave())
- return true;
-
- const CPVREpgDatabasePtr database = CServiceBroker::GetPVRManager().EpgContainer().GetEpgDatabase();
if (!database)
{
- CLog::LogF(LOGERROR, "Could not open the EPG database");
+ CLog::LogF(LOGERROR, "No EPG database");
return false;
}
@@ -568,21 +490,31 @@ 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)
database->Delete(*tag.second);
for (const auto& tag : m_changedTags)
- tag.second->Persist(false);
+ tag.second->Persist(database, false);
if (m_bUpdateLastScanTime)
- database->PersistLastEpgScanTime(m_iEpgID, true);
+ database->PersistLastEpgScanTime(m_iEpgID, m_lastScanTime, true);
+
+ if (bEpgIdChanged)
+ {
+ for (const auto& tag : m_tags)
+ tag.second->SetEpgID(m_iEpgID);
+ }
m_deletedTags.clear();
m_changedTags.clear();
@@ -642,8 +574,6 @@ bool CPVREpg::FixOverlappingEvents(bool bUpdateDb /* = false */)
if (m_nowActiveStart == it->first)
m_nowActiveStart.SetValid(false);
- it->second->ClearTimer();
- it->second->ClearRecording();
m_tags.erase(it++);
}
else if (previousTag->EndAsUTC() > currentTag->StartAsUTC())
@@ -671,43 +601,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())
+ {
+ // ignore. not interested in any updates.
+ return true;
+ }
+
+ const std::shared_ptr<CPVRClient> client = CServiceBroker::GetPVRManager().GetClient(m_channelData->ClientId());
+ if (client)
{
- if (!channel->EPGEnabled() || channel->IsHidden())
+ 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...
@@ -771,49 +696,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());
+ bReturn = UpdateEntries(*tmpEpg, !CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool(CSettings::SETTING_EPG_IGNOREDBFORCLIENT));
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
@@ -850,7 +758,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 c1f9fda627..84f423f4b5 100644
--- a/xbmc/pvr/epg/Epg.h
+++ b/xbmc/pvr/epg/Epg.h
@@ -12,18 +12,17 @@
#include <string>
#include <vector>
-#include "FileItem.h"
#include "threads/CriticalSection.h"
#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 +33,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.
@@ -50,28 +51,29 @@ namespace PVR
~CPVREpg(void) override;
/*!
- * @brief Load all entries for this table from the database.
+ * @brief Load all entries for this table from the given database.
+ * @param database The database.
* @return True if any entries were loaded, false otherwise.
*/
- bool Load(void);
+ bool Load(const std::shared_ptr<CPVREpgDatabase>& database);
/*!
- * @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.
@@ -109,19 +111,12 @@ namespace PVR
bool HasValidEntries(void) const;
/*!
- * @brief Remove all entries from this EPG that finished before the given time
- * and that have no timers set.
+ * @brief Remove all entries from this EPG that finished before the given time.
* @param time Delete entries with an end time before this time in UTC.
*/
void Cleanup(const CDateTime &time);
/*!
- * @brief Remove all entries from this EPG that finished before the given time
- * and that have no timers set.
- */
- void Cleanup(void);
-
- /*!
* @brief Remove all entries from this EPG.
*/
void Clear(void);
@@ -154,14 +149,6 @@ namespace PVR
CPVREpgInfoTagPtr GetTagBetween(const CDateTime &beginTime, const CDateTime &endTime, bool bUpdateFromClient = false);
/*!
- * @brief Get all events occurring between the given begin and end time.
- * @param beginTime Minimum start time in UTC of the event.
- * @param endTime Maximum end time in UTC of the event.
- * @return The tags found or an empty vector if none was found.
- */
- std::vector<CPVREpgInfoTagPtr> GetTagsBetween(const CDateTime &beginTime, const CDateTime &endTime) const;
-
- /*!
* @brief Get the event matching the given unique broadcast id
* @param iUniqueBroadcastId The uid to look up
* @return The matching event or NULL if it wasn't found.
@@ -199,31 +186,25 @@ namespace PVR
* @param start The start time.
* @param end The end time.
* @param iUpdateTime Update the table after the given amount of time has passed.
+ * @param iPastDays Amount of past days from now on, for which past entries are to be kept.
+ * @param database If given, the database to store the data.
* @param bForceUpdate Force update from client even if it's not the time to
* @return True if the update was successful, false otherwise.
*/
- bool Update(const time_t start, const time_t end, int iUpdateTime, bool bForceUpdate = false);
-
- /*!
- * @brief Get all EPG entries.
- * @param results The file list to store the results in.
- * @return The amount of entries that were added.
- */
- int Get(CFileItemList &results) const;
+ bool Update(time_t start, time_t end, int iUpdateTime, int iPastDays, const std::shared_ptr<CPVREpgDatabase>& database, bool bForceUpdate = false);
/*!
- * @brief Get all EPG entries that and apply a filter.
- * @param results The file list to store the results in.
- * @param filter The filter to apply.
- * @return The amount of entries that were added.
+ * @brief Get all EPG tags.
+ * @return The tags.
*/
- int Get(CFileItemList &results, const CPVREpgSearchFilter &filter) const;
+ std::vector<std::shared_ptr<CPVREpgInfoTag>> GetTags() const;
/*!
- * @brief Persist this table in the database.
+ * @brief Persist this table in the given database
+ * @param database The database.
* @return True if the table was persisted, false otherwise.
*/
- bool Persist(void);
+ bool Persist(const std::shared_ptr<CPVREpgDatabase>& database);
/*!
* @brief Get the start time of the first entry in this table.
@@ -238,12 +219,6 @@ namespace PVR
CDateTime GetLastDate(void) const;
/*!
- * @brief Get the time the EPG data were last updated.
- * @return The last time this table was scanned.
- */
- CDateTime GetLastScanTime(void);
-
- /*!
* @brief Notify observers when the currently active tag changed.
* @return True if the playing tag has changed, false otherwise.
*/
@@ -314,6 +289,12 @@ namespace PVR
*/
bool UpdateEntries(const CPVREpg &epg, bool bStoreInDb = true);
+ /*!
+ * @brief Remove all entries from this EPG that finished before the given amount of days.
+ * @param iPastDays Delete entries with an end time before the given amount of days from now on.
+ */
+ void Cleanup(int iPastDays);
+
std::map<CDateTime, CPVREpgInfoTagPtr> m_tags;
std::map<int, CPVREpgInfoTagPtr> m_changedTags;
std::map<int, CPVREpgInfoTagPtr> m_deletedTags;
@@ -325,12 +306,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 0e13688a0f..1d4bdc966f 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,11 +20,9 @@
#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"
-#include "pvr/recordings/PVRRecordings.h"
-#include "pvr/timers/PVRTimerInfoTag.h"
namespace PVR
{
@@ -35,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;
}
@@ -79,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) :
@@ -136,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;
@@ -152,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;
@@ -254,6 +246,11 @@ void CPVREpgContainer::Notify(const Observable &obs, const ObservableMessage msg
m_bUpdateNotificationPending = true;
return;
}
+ else if (msg == ObservableMessageEpgUpdatePending)
+ {
+ SetHasPendingUpdates(true);
+ return;
+ }
SetChanged();
CSingleExit ex(m_critSection);
@@ -276,21 +273,21 @@ void CPVREpgContainer::LoadFromDB(void)
m_database->Lock();
m_iNextEpgId = m_database->GetLastEPGId();
m_database->DeleteEpgEntries(cleanupTime);
- const std::vector<CPVREpgPtr> result = m_database->Get(*this);
+ const std::vector<std::shared_ptr<CPVREpg>> result = m_database->GetAll();
m_database->Unlock();
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();
+ epgEntry.second->Load(GetEpgDatabase());
lock.Enter();
}
@@ -301,16 +298,21 @@ void CPVREpgContainer::LoadFromDB(void)
bool CPVREpgContainer::PersistAll(void)
{
- bool bReturn = true;
-
- m_critSection.lock();
- const auto epgs = m_epgs;
- m_critSection.unlock();
+ bool bReturn = IgnoreDB();
- for (const auto& epg : epgs)
+ if (!bReturn)
{
- if (epg.second && epg.second->NeedsSave())
- bReturn &= epg.second->Persist();
+ m_critSection.lock();
+ const auto epgs = m_epgIdToEpgMap;
+ m_critSection.unlock();
+
+ const std::shared_ptr<CPVREpgDatabase> database = GetEpgDatabase();
+
+ for (const auto& epg : epgs)
+ {
+ if (epg.second && epg.second->NeedsSave())
+ bReturn &= epg.second->Persist(database);
+ }
}
return bReturn;
@@ -440,29 +442,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)
@@ -473,20 +488,18 @@ CPVREpgInfoTagPtr CPVREpgContainer::GetTagById(const CPVRChannelPtr &channel, un
return retval;
}
-std::vector<CPVREpgInfoTagPtr> CPVREpgContainer::GetEpgTagsForTimer(const CPVRTimerInfoTagPtr &timer) const
+std::vector<std::shared_ptr<CPVREpgInfoTag>> CPVREpgContainer::GetAllTags() const
{
- CPVRChannelPtr channel = timer->Channel();
+ std::vector<std::shared_ptr<CPVREpgInfoTag>> allTags;
- if (!channel)
- channel = timer->UpdateChannel();
-
- if (channel)
+ CSingleLock lock(m_critSection);
+ for (const auto& epgEntry : m_epgIdToEpgMap)
{
- const CPVREpgPtr epg = channel->GetEPG();
- if (epg)
- return epg->GetTagsBetween(timer->StartAsUTC(), timer->EndAsUTC());
+ const std::vector<std::shared_ptr<CPVREpgInfoTag>> epgTags = epgEntry.second->GetTags();
+ allTags.insert(allTags.end(), epgTags.begin(), epgTags.end());
}
- return std::vector<CPVREpgInfoTagPtr>();
+
+ return allTags;
}
void CPVREpgContainer::InsertFromDB(const CPVREpgPtr &newEpg)
@@ -506,38 +519,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({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({iEpgId, epg});
+ m_channelUidToEpgMap.insert({{channelData->ClientId(), channelData->UniqueClientChannelId()}, epg});
SetChanged();
epg->RegisterObserver(this);
}
-
- epg->SetChannel(channel);
+ else if (epg->ChannelID() == -1)
+ {
+ CSingleLock lock(m_critSection);
+ m_channelUidToEpgMap.insert({{channelData->ClientId(), channelData->UniqueClientChannelId()}, epg});
+ epg->SetChannelData(channelData);
+ }
{
CSingleLock lock(m_critSection);
@@ -556,7 +572,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 */
@@ -576,16 +592,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;
}
@@ -652,7 +673,8 @@ bool CPVREpgContainer::UpdateEPG(bool bOnlyPending /* = false */)
/* load or update all EPG tables */
unsigned int iCounter = 0;
- for (const auto &epgEntry : m_epgs)
+ const std::shared_ptr<CPVREpgDatabase> database = IgnoreDB() ? nullptr : GetEpgDatabase();
+ for (const auto& epgEntry : m_epgIdToEpgMap)
{
if (InterruptUpdate())
{
@@ -665,22 +687,15 @@ 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))
+ epg->Update(start,
+ end,
+ m_settings.GetIntValue(CSettings::SETTING_EPG_EPGUPDATE) * 60,
+ m_settings.GetIntValue(CSettings::SETTING_EPG_PAST_DAYSTODISPLAY),
+ database,
+ bOnlyPending))
{
iUpdatedTables++;
}
@@ -732,7 +747,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)
@@ -750,7 +765,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)
@@ -763,24 +778,6 @@ const CDateTime CPVREpgContainer::GetLastEPGDate(void)
return returnValue;
}
-int CPVREpgContainer::GetEPGSearch(CFileItemList &results, const CPVREpgSearchFilter &filter)
-{
- int iInitialSize = results.Size();
-
- /* get filtered results from all tables */
- {
- CSingleLock lock(m_critSection);
- for (const auto &epgEntry : m_epgs)
- epgEntry.second->Get(results, filter);
- }
-
- /* remove duplicate entries */
- if (filter.ShouldRemoveDuplicates())
- filter.RemoveDuplicates(results);
-
- return results.Size() - iInitialSize;
-}
-
bool CPVREpgContainer::CheckPlayingEvents(void)
{
bool bReturn = false;
@@ -796,7 +793,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);
@@ -833,7 +830,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 cd43345ab8..6e10e6eaee 100644
--- a/xbmc/pvr/epg/EpgContainer.h
+++ b/xbmc/pvr/epg/EpgContainer.h
@@ -8,6 +8,11 @@
#pragma once
+#include <list>
+#include <map>
+#include <memory>
+#include <utility>
+
#include "XBDateTime.h"
#include "threads/CriticalSection.h"
#include "threads/Thread.h"
@@ -18,10 +23,11 @@
#include "pvr/epg/Epg.h"
#include "pvr/epg/EpgDatabase.h"
-class CFileItemList;
+class CFileItem;
namespace PVR
{
+ class CPVREpgChannelData;
class CEpgUpdateRequest;
class CEpgTagStateChange;
@@ -85,18 +91,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);
-
- /*!
- * @brief Get all EPG tables and apply a filter.
- * @param results The fileitem list to store the results in.
- * @param filter The filter to apply.
- * @return The amount of entries that were added.
- */
- int GetEPGSearch(CFileItemList &results, const CPVREpgSearchFilter &filter);
+ std::shared_ptr<CPVREpg> CreateChannelEpg(int iEpgId, const std::string& strScraperName, const std::shared_ptr<CPVREpgChannelData>& channelData);
/*!
* @brief Get the start time of the first entry.
@@ -111,26 +111,33 @@ 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 Get the EPG events matching the given timer
- * @param timer The timer to get the matching events for.
- * @return The matching events, or an empty vector when no matching tag was found
+ * @brief Get all EPG tags.
+ * @return The tags.
*/
- std::vector<CPVREpgInfoTagPtr> GetEpgTagsForTimer(const CPVRTimerInfoTagPtr &timer) const;
+ std::vector<std::shared_ptr<CPVREpgInfoTag>> GetAllTags() const;
/*!
* @brief Check whether data should be persisted to the EPG database.
@@ -149,7 +156,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
@@ -174,14 +181,13 @@ namespace PVR
* @brief Inform the epg container that playback of an item just started.
* @param item The item that started to play.
*/
- void OnPlaybackStarted(const CFileItemPtr &item);
+ void OnPlaybackStarted(const std::shared_ptr<CFileItem>& item);
/*!
* @brief Inform the epg container that playback of an item was stopped due to user interaction.
* @param item The item that stopped to play.
*/
- void OnPlaybackStopped(const CFileItemPtr &item);
-
+ void OnPlaybackStopped(const std::shared_ptr<CFileItem>& item);
private:
/*!
@@ -194,7 +200,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.
@@ -254,8 +260,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..8d08d45ee4 100644
--- a/xbmc/pvr/epg/EpgDatabase.cpp
+++ b/xbmc/pvr/epg/EpgDatabase.cpp
@@ -15,10 +15,12 @@
#include "dbwrappers/dataset.h"
#include "settings/AdvancedSettings.h"
#include "settings/SettingsComponent.h"
+#include "threads/SingleLock.h"
#include "utils/log.h"
#include "utils/StringUtils.h"
-#include "pvr/epg/EpgContainer.h"
+#include "pvr/epg/Epg.h"
+#include "pvr/epg/EpgInfoTag.h"
using namespace dbiplus;
using namespace PVR;
@@ -197,9 +199,9 @@ bool CPVREpgDatabase::Delete(const CPVREpgInfoTag &tag)
return DeleteValues("epgtags", filter);
}
-std::vector<CPVREpgPtr> CPVREpgDatabase::Get(const CPVREpgContainer &container)
+std::vector<std::shared_ptr<CPVREpg>> CPVREpgDatabase::GetAll()
{
- std::vector<CPVREpgPtr> result;
+ std::vector<std::shared_ptr<CPVREpg>> result;
CSingleLock lock(m_critSection);
std::string strQuery = PrepareSQL("SELECT idEpg, sName, sScraperName FROM epg;");
@@ -213,7 +215,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();
@@ -227,9 +229,9 @@ std::vector<CPVREpgPtr> CPVREpgDatabase::Get(const CPVREpgContainer &container)
return result;
}
-std::vector<CPVREpgInfoTagPtr> CPVREpgDatabase::Get(const CPVREpg &epg)
+std::vector<std::shared_ptr<CPVREpgInfoTag>> CPVREpgDatabase::Get(const CPVREpg &epg)
{
- std::vector<CPVREpgInfoTagPtr> result;
+ std::vector<std::shared_ptr<CPVREpgInfoTag>> result;
CSingleLock lock(m_critSection);
std::string strQuery = PrepareSQL("SELECT * FROM epgtags WHERE idEpg = %u;", epg.EpgID());
@@ -239,7 +241,7 @@ std::vector<CPVREpgInfoTagPtr> CPVREpgDatabase::Get(const CPVREpg &epg)
{
while (!m_pDS->eof())
{
- CPVREpgInfoTagPtr newTag(new CPVREpgInfoTag());
+ std::shared_ptr<CPVREpgInfoTag> newTag(new CPVREpgInfoTag());
time_t iStartTime, iEndTime, iFirstAired;
iStartTime = (time_t) m_pDS->fv("iStartTime").get_asInt();
@@ -317,11 +319,11 @@ bool CPVREpgDatabase::GetLastEpgScanTime(int iEpgId, CDateTime *lastScan)
return bReturn;
}
-bool CPVREpgDatabase::PersistLastEpgScanTime(int iEpgId /* = 0 */, bool bQueueWrite /* = false */)
+bool CPVREpgDatabase::PersistLastEpgScanTime(int iEpgId, const CDateTime& lastScanTime, bool bQueueWrite /* = false */)
{
CSingleLock lock(m_critSection);
std::string strQuery = PrepareSQL("REPLACE INTO lastepgscan(idEpg, sLastScan) VALUES (%u, '%s');",
- iEpgId, CDateTime::GetCurrentDateTime().GetAsUTCDateTime().GetAsDBDateTime().c_str());
+ iEpgId, lastScanTime.GetAsDBDateTime().c_str());
return bQueueWrite ? QueueInsertQuery(strQuery) : ExecuteQuery(strQuery);
}
@@ -359,7 +361,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 +386,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 +402,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/EpgDatabase.h b/xbmc/pvr/epg/EpgDatabase.h
index 011b134149..c7f5308be0 100644
--- a/xbmc/pvr/epg/EpgDatabase.h
+++ b/xbmc/pvr/epg/EpgDatabase.h
@@ -8,16 +8,15 @@
#pragma once
-#include "XBDateTime.h"
#include "dbwrappers/Database.h"
#include "threads/CriticalSection.h"
-#include "pvr/epg/Epg.h"
+class CDateTime;
namespace PVR
{
+ class CPVREpg;
class CPVREpgInfoTag;
- class CPVREpgContainer;
/** The EPG database */
@@ -99,17 +98,16 @@ namespace PVR
/*!
* @brief Get all EPG tables from the database. Does not get the EPG tables' entries.
- * @param container The container to get the EPG tables for.
* @return The entries.
*/
- std::vector<CPVREpgPtr> Get(const CPVREpgContainer &container);
+ std::vector<std::shared_ptr<CPVREpg>> GetAll();
/*!
* @brief Get all EPG entries for a table.
* @param epg The EPG table to get the entries for.
* @return The entries.
*/
- std::vector<CPVREpgInfoTagPtr> Get(const CPVREpg &epg);
+ std::vector<std::shared_ptr<CPVREpgInfoTag>> Get(const CPVREpg &epg);
/*!
* @brief Get the last stored EPG scan time.
@@ -121,11 +119,12 @@ namespace PVR
/*!
* @brief Update the last scan time.
- * @param iEpgId The table to update the time for. Use 0 for a global value.
+ * @param iEpgId The table to update the time for.
+ * @param lastScanTime The time to write to the database.
* @param bQueueWrite Don't execute the query immediately but queue it if true.
* @return True if it was updated successfully, false otherwise.
*/
- bool PersistLastEpgScanTime(int iEpgId = 0, bool bQueueWrite = false);
+ bool PersistLastEpgScanTime(int iEpgId, const CDateTime& lastScanTime, bool bQueueWrite = false);
/*!
* @brief Persist an EPG table. It's entries are not persisted.
diff --git a/xbmc/pvr/epg/EpgInfoTag.cpp b/xbmc/pvr/epg/EpgInfoTag.cpp
index a6b592c737..8c37ffe3b7 100644
--- a/xbmc/pvr/epg/EpgInfoTag.cpp
+++ b/xbmc/pvr/epg/EpgInfoTag.cpp
@@ -12,48 +12,66 @@
#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"
#include "utils/log.h"
#include "pvr/PVRManager.h"
-#include "pvr/epg/Epg.h"
-#include "pvr/epg/EpgContainer.h"
+#include "pvr/epg/EpgChannelData.h"
#include "pvr/epg/EpgDatabase.h"
-#include "pvr/timers/PVRTimers.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
@@ -83,19 +101,22 @@ 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 &&
+ CSingleLock lock(m_critSection);
+ return (m_bNotify == right.m_bNotify &&
m_iDatabaseID == right.m_iDatabaseID &&
m_iGenreType == right.m_iGenreType &&
m_iGenreSubType == right.m_iGenreSubType &&
@@ -106,7 +127,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 &&
@@ -118,12 +138,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,10 +158,9 @@ bool CPVREpgInfoTag::operator !=(const CPVREpgInfoTag& right) const
void CPVREpgInfoTag::Serialize(CVariant &value) const
{
- const CPVRRecordingPtr recording = Recording();
-
+ CSingleLock lock(m_critSection);
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;
@@ -162,37 +183,37 @@ void CPVREpgInfoTag::Serialize(CVariant &value) const
value["episodename"] = m_strEpisodeName;
value["episodenum"] = m_iEpisodeNumber;
value["episodepart"] = m_iEpisodePart;
- value["hastimer"] = HasTimer();
- value["hastimerrule"] = HasTimerRule();
- value["hasrecording"] = HasRecording();
- value["recording"] = recording ? recording->m_strFileNameAndPath : "";
+ value["hastimer"] = false; // compat
+ value["hastimerrule"] = false; // compat
+ value["hasrecording"] = false; // compat
+ value["recording"] = ""; // compat
value["isactive"] = IsActive();
value["wasactive"] = WasActive();
value["isseries"] = IsSeries();
value["serieslink"] = m_strSeriesLink;
}
-void CPVREpgInfoTag::ToSortable(SortItem& sortable, Field field) const
+int CPVREpgInfoTag::ClientID() const
{
CSingleLock lock(m_critSection);
+ return m_channelData->ClientId();
+}
- if (!m_channel)
- return;
+void CPVREpgInfoTag::ToSortable(SortItem& sortable, Field field) const
+{
+ CSingleLock lock(m_critSection);
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;
}
@@ -200,7 +221,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();
@@ -277,9 +298,10 @@ int CPVREpgInfoTag::DatabaseID(void) const
return m_iDatabaseID;
}
-unsigned int CPVREpgInfoTag::UniqueChannelID(void) const
+int CPVREpgInfoTag::UniqueChannelID(void) const
{
- return m_iUniqueChannelID;
+ CSingleLock lock(m_critSection);
+ return m_channelData->UniqueClientChannelId();
}
CDateTime CPVREpgInfoTag::StartAsUTC(void) const
@@ -319,59 +341,24 @@ int CPVREpgInfoTag::GetDuration(void) const
return end - start > 0 ? end - start : 3600;
}
-bool CPVREpgInfoTag::IsParentalLocked() const
-{
- CPVRChannelPtr channel;
- {
- CSingleLock lock(m_critSection);
- channel = m_channel;
- }
-
- return channel && CServiceBroker::GetPVRManager().IsParentalLocked(channel);
-}
-
-std::string CPVREpgInfoTag::Title(bool bOverrideParental /* = false */) const
+std::string CPVREpgInfoTag::Title() 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_strTitle;
}
-std::string CPVREpgInfoTag::PlotOutline(bool bOverrideParental /* = false */) const
+std::string CPVREpgInfoTag::PlotOutline() const
{
- std::string retVal;
-
- if (bOverrideParental || !IsParentalLocked())
- retVal = m_strPlotOutline;
-
- return retVal;
+ return m_strPlotOutline;
}
-std::string CPVREpgInfoTag::Plot(bool bOverrideParental /* = false */) const
+std::string CPVREpgInfoTag::Plot() const
{
- std::string retVal;
-
- if (bOverrideParental || !IsParentalLocked())
- retVal = m_strPlot;
-
- return retVal;
+ return m_strPlot;
}
-std::string CPVREpgInfoTag::OriginalTitle(bool bOverrideParental /* = false */) const
+std::string CPVREpgInfoTag::OriginalTitle() const
{
- std::string retVal;
-
- if (bOverrideParental || !IsParentalLocked())
- retVal = m_strOriginalTitle;
-
- return retVal;
+ return m_strOriginalTitle;
}
const std::vector<std::string> CPVREpgInfoTag::Cast(void) const
@@ -506,14 +493,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
@@ -526,149 +508,98 @@ std::string CPVREpgInfoTag::Path(void) const
return m_strFileNameAndPath;
}
-bool CPVREpgInfoTag::HasTimer(void) const
-{
- CSingleLock lock(m_critSection);
- return m_timer != nullptr;
-}
-
-bool CPVREpgInfoTag::HasTimerRule(void) const
-{
- CSingleLock lock(m_critSection);
- return m_timer && (m_timer->GetTimerRuleId() != PVR_TIMER_NO_PARENT);
-}
-
-CPVRTimerInfoTagPtr CPVREpgInfoTag::Timer(void) const
-{
- CSingleLock lock(m_critSection);
- return m_timer;
-}
-
-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);
- }
+ CSingleLock lock(m_critSection);
+ 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();
return bChanged;
}
-bool CPVREpgInfoTag::Persist(bool bSingleUpdate /* = true */)
+bool CPVREpgInfoTag::Persist(const std::shared_ptr<CPVREpgDatabase>& database, bool bSingleUpdate /* = true */)
{
bool bReturn = false;
- const CPVREpgDatabasePtr database = CServiceBroker::GetPVRManager().EpgContainer().GetEpgDatabase();
if (!database)
{
CLog::LogF(LOGERROR, "Could not open the EPG database");
@@ -690,7 +621,9 @@ 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);
+
+ CSingleLock lock(m_critSection);
+ const std::shared_ptr<CPVRClient> client = CServiceBroker::GetPVRManager().GetClient(m_channelData->ClientId());
if (client && client->GetClientCapabilities().SupportsEpgTagEdl())
client->GetEpgTagEdl(shared_from_this(), edls);
@@ -705,55 +638,21 @@ void CPVREpgInfoTag::UpdatePath(void)
int CPVREpgInfoTag::EpgID(void) const
{
- return m_epg ? m_epg->EpgID() : -1;
-}
-
-void CPVREpgInfoTag::SetTimer(const CPVRTimerInfoTagPtr &timer)
-{
- CSingleLock lock(m_critSection);
- m_timer = timer;
-}
-
-void CPVREpgInfoTag::ClearTimer(void)
-{
- CPVRTimerInfoTagPtr previousTag;
- {
- CSingleLock lock(m_critSection);
- previousTag = std::move(m_timer);
- }
-
- if (previousTag)
- previousTag->ClearEpgTag();
+ return m_iEpgID;
}
-void CPVREpgInfoTag::SetRecording(const CPVRRecordingPtr &recording)
+void CPVREpgInfoTag::SetEpgID(int iEpgID)
{
- CSingleLock lock(m_critSection);
- m_recording = recording;
-}
-
-void CPVREpgInfoTag::ClearRecording(void)
-{
- CSingleLock lock(m_critSection);
- m_recording.reset();
-}
-
-bool CPVREpgInfoTag::HasRecording(void) const
-{
- CSingleLock lock(m_critSection);
- return m_recording != nullptr;
-}
-
-CPVRRecordingPtr CPVREpgInfoTag::Recording(void) const
-{
- CSingleLock lock(m_critSection);
- return m_recording;
+ 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);
+
+ CSingleLock lock(m_critSection);
+ 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
@@ -765,7 +664,9 @@ bool CPVREpgInfoTag::IsRecordable(void) const
bool CPVREpgInfoTag::IsPlayable(void) const
{
bool bIsPlayable = false;
- const CPVRClientPtr client = CServiceBroker::GetPVRManager().GetClient(m_iClientId);
+
+ CSingleLock lock(m_critSection);
+ 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
@@ -774,12 +675,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)
@@ -788,6 +683,18 @@ bool CPVREpgInfoTag::IsSeries(void) const
return false;
}
+bool CPVREpgInfoTag::IsRadio() const
+{
+ CSingleLock lock(m_critSection);
+ return m_channelData->IsRadio();
+}
+
+bool CPVREpgInfoTag::IsParentalLocked() const
+{
+ CSingleLock lock(m_critSection);
+ 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 75625d2543..6166f667fe 100644
--- a/xbmc/pvr/epg/EpgInfoTag.h
+++ b/xbmc/pvr/epg/EpgInfoTag.h
@@ -14,19 +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"
-#include "pvr/recordings/PVRRecording.h"
-#include "pvr/timers/PVRTimerInfoTag.h"
class CVariant;
namespace PVR
{
- class CPVREpg;
+ class CPVREpgChannelData;
class CPVREpgInfoTag final : public ISerializable, public ISortable, public std::enable_shared_from_this<CPVREpgInfoTag>
{
@@ -38,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;
@@ -62,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.
@@ -101,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.
@@ -128,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.
@@ -168,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.
@@ -322,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.
@@ -340,58 +340,6 @@ namespace PVR
std::string Path(void) const;
/*!
- * @brief Set a timer for this event.
- * @param timer The timer.
- */
- void SetTimer(const CPVRTimerInfoTagPtr &timer);
-
- /*!
- * @brief Clear the timer for this event.
- */
- void ClearTimer(void);
-
- /*!
- * @brief Check whether this event has a timer tag.
- * @return True if it has a timer tag, false if not.
- */
- bool HasTimer(void) const;
-
- /*!
- * @brief Check whether this event has a timer rule.
- * @return True if it has a timer rule, false if not.
- */
- bool HasTimerRule(void) const;
-
- /*!
- * @brief Get the timer for this event, if any.
- * @return The timer or nullptr if there is none.
- */
- CPVRTimerInfoTagPtr Timer(void) const;
-
- /*!
- * @brief Set a recording for this event.
- * @param recording The recording.
- */
- void SetRecording(const CPVRRecordingPtr &recording);
-
- /*!
- * @brief Clear a recording for this event.
- */
- void ClearRecording(void);
-
- /*!
- * @brief Check whether this event has a recording.
- * @return True if it has a recording, false if not.
- */
- bool HasRecording(void) const;
-
- /*!
- * @brief Get the recording for this event, if any.
- * @return The pointer or nullptr if there is none.
- */
- CPVRRecordingPtr Recording(void) const;
-
- /*!
* @brief Check if this event can be recorded.
* @return True if it can be recorded, false otherwise.
*/
@@ -404,29 +352,12 @@ 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.
+ * @brief Persist this tag in the given database.
+ * @param database 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.
*/
- bool Persist(bool bSingleUpdate = true);
+ bool Persist(const std::shared_ptr<CPVREpgDatabase>& database, bool bSingleUpdate = true);
/*!
* @brief Update the information in this tag with the info in the given tag.
@@ -449,6 +380,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.
*/
@@ -469,18 +412,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.
@@ -499,7 +436,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 */
@@ -509,7 +445,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 */
@@ -530,9 +465,7 @@ namespace PVR
std::string m_strSeriesLink; /*!< series link */
mutable CCriticalSection m_critSection;
- CPVREpg *m_epg = nullptr;
- CPVRChannelPtr m_channel;
- CPVRTimerInfoTagPtr m_timer;
- CPVRRecordingPtr m_recording;
+ 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..829d8daae8 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,63 +138,42 @@ 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)
+void CPVREpgSearchFilter::RemoveDuplicates(std::vector<std::shared_ptr<CPVREpgInfoTag>>& results)
{
- unsigned int iSize = results.Size();
-
- for (unsigned int iResultPtr = 0; iResultPtr < iSize; iResultPtr++)
+ for (auto it = results.begin(); it != results.end();)
{
- const CPVREpgInfoTagPtr epgentry_1(results.Get(iResultPtr)->GetEPGInfoTag());
- if (!epgentry_1)
- continue;
-
- for (unsigned int iTagPtr = 0; iTagPtr < iSize; iTagPtr++)
- {
- if (iResultPtr == iTagPtr)
- continue;
-
- const CPVREpgInfoTagPtr epgentry_2(results.Get(iTagPtr)->GetEPGInfoTag());
- if (!epgentry_2)
- continue;
-
- if (epgentry_1->Title() != epgentry_2->Title() ||
- epgentry_1->Plot() != epgentry_2->Plot() ||
- epgentry_1->PlotOutline() != epgentry_2->PlotOutline())
- continue;
-
- results.Remove(iTagPtr);
- iResultPtr--;
- iTagPtr--;
- iSize--;
- }
+ it = results.erase(std::remove_if(results.begin(),
+ results.end(),
+ [&it](const std::shared_ptr<CPVREpgInfoTag>& entry)
+ {
+ return *it != entry &&
+ (*it)->Title() == entry->Title() &&
+ (*it)->Plot() == entry->Plot() &&
+ (*it)->PlotOutline() == entry->PlotOutline();
+ }),
+ results.end());
}
-
- return iSize;
}
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 +183,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 +198,13 @@ bool CPVREpgSearchFilter::MatchChannelGroup(const CPVREpgInfoTagPtr &tag) const
bool CPVREpgSearchFilter::MatchFreeToAir(const CPVREpgInfoTagPtr &tag) const
{
- return (!m_bFreeToAirOnly || !tag->Channel()->IsEncrypted());
+ if (m_bFreeToAirOnly)
+ {
+ const std::shared_ptr<CPVRChannel> channel = CServiceBroker::GetPVRManager().ChannelGroups()->GetChannelForEpgTag(tag);
+ return channel && !channel->IsEncrypted();
+ }
+
+ return true;
}
bool CPVREpgSearchFilter::MatchTimers(const CPVREpgInfoTagPtr &tag) const
diff --git a/xbmc/pvr/epg/EpgSearchFilter.h b/xbmc/pvr/epg/EpgSearchFilter.h
index 47b135d58d..597ab8e392 100644
--- a/xbmc/pvr/epg/EpgSearchFilter.h
+++ b/xbmc/pvr/epg/EpgSearchFilter.h
@@ -8,13 +8,15 @@
#pragma once
+#include <memory>
+#include <string>
+#include <vector>
+
#include "XBDateTime.h"
#include "pvr/PVRTypes.h"
#include "pvr/channels/PVRChannelNumber.h"
-class CFileItemList;
-
namespace PVR
{
#define EPG_SEARCH_UNSET (-1)
@@ -46,10 +48,9 @@ namespace PVR
/*!
* @brief remove duplicates from a list of epg tags.
- * @param results the list of epg tags.
- * @return the number of items in the list after removing duplicates.
+ * @param results The list of epg tags.
*/
- static int RemoveDuplicates(CFileItemList &results);
+ static void RemoveDuplicates(std::vector<std::shared_ptr<CPVREpgInfoTag>>& results);
/*!
* @brief Get the type of channels to search.
diff --git a/xbmc/pvr/recordings/PVRRecording.cpp b/xbmc/pvr/recordings/PVRRecording.cpp
index b50f68e0d7..33d3c7f4f4 100644
--- a/xbmc/pvr/recordings/PVRRecording.cpp
+++ b/xbmc/pvr/recordings/PVRRecording.cpp
@@ -217,25 +217,7 @@ void CPVRRecording::Reset(void)
bool CPVRRecording::Delete(void)
{
CPVRClientPtr client = CServiceBroker::GetPVRManager().GetClient(m_iClientId);
- if (!client || client->DeleteRecording(*this) != PVR_ERROR_NO_ERROR)
- return false;
-
- OnDelete();
- return true;
-}
-
-void CPVRRecording::OnDelete(void)
-{
- if (m_iEpgEventId != EPG_TAG_INVALID_UID)
- {
- const CPVRChannelPtr channel(Channel());
- if (channel)
- {
- const CPVREpgInfoTagPtr epgTag(CServiceBroker::GetPVRManager().EpgContainer().GetTagById(channel, m_iEpgEventId));
- if (epgTag)
- epgTag->ClearRecording();
- }
- }
+ return client && (client->DeleteRecording(*this) == PVR_ERROR_NO_ERROR);
}
bool CPVRRecording::Undelete(void)
@@ -410,9 +392,6 @@ void CPVRRecording::Update(const CPVRRecording &tag)
m_strShowTitle = strEpisode;
}
- if (m_bIsDeleted)
- OnDelete();
-
UpdatePath();
}
@@ -483,13 +462,38 @@ int CPVRRecording::ClientID(void) const
return m_iClientId;
}
+std::shared_ptr<CPVRTimerInfoTag> CPVRRecording::GetRecordingTimer() const
+{
+ const std::vector<std::shared_ptr<CPVRTimerInfoTag>> recordingTimers = CServiceBroker::GetPVRManager().Timers()->GetActiveRecordings();
+
+ for (const auto& timer : recordingTimers)
+ {
+ if (timer->m_iClientId == ClientID() &&
+ timer->m_iClientChannelUid == ChannelUid())
+ {
+ // first, match epg event uids, if available
+ if (timer->UniqueBroadcastID() == BroadcastUid() &&
+ timer->UniqueBroadcastID() != EPG_TAG_INVALID_UID)
+ return timer;
+
+ // alternatively, match start and end times
+ const CDateTime timerStart = timer->StartAsUTC() - CDateTimeSpan(0, 0, timer->m_iMarginStart, 0);
+ const CDateTime timerEnd = timer->EndAsUTC() + CDateTimeSpan(0, 0, timer->m_iMarginEnd, 0);
+ if (timerStart <= RecordingTimeAsUTC() &&
+ timerEnd >= EndTimeAsUTC())
+ return timer;
+ }
+ }
+ return {};
+}
+
bool CPVRRecording::IsInProgress() const
{
// Note: It is not enough to only check recording time and duration against 'now'.
// Only the state of the related timer is a safe indicator that the backend
// actually is recording this.
- return CServiceBroker::GetPVRManager().Timers()->HasRecordingTimerForRecording(*this);
+ return GetRecordingTimer() != nullptr;
}
void CPVRRecording::SetGenre(int iGenreType, int iGenreSubType, const std::string &strGenre)
diff --git a/xbmc/pvr/recordings/PVRRecording.h b/xbmc/pvr/recordings/PVRRecording.h
index 72e57eda8e..d038343187 100644
--- a/xbmc/pvr/recordings/PVRRecording.h
+++ b/xbmc/pvr/recordings/PVRRecording.h
@@ -95,11 +95,6 @@ namespace PVR
bool Delete(void);
/*!
- * @brief Called when this recording has been deleted
- */
- void OnDelete(void);
-
- /*!
* @brief Undelete this recording on the client (if supported).
* @return True if it was undeleted successfully, false otherwise.
*/
@@ -281,6 +276,12 @@ namespace PVR
bool IsInProgress() const;
/*!
+ * @brief return the timer for an in-progress recording, if any
+ * @return the timer if the recording is in progress, nullptr otherwise
+ */
+ std::shared_ptr<CPVRTimerInfoTag> GetRecordingTimer() const;
+
+ /*!
* @brief set the genre for this recording.
* @param iGenreType The genre type ID. If set to EPG_GENRE_USE_STRING, set genre to the value provided with strGenre. Otherwise, compile the genre string from the values given by iGenreType and iGenreSubType
* @param iGenreSubType The genre subtype ID
diff --git a/xbmc/pvr/recordings/PVRRecordings.cpp b/xbmc/pvr/recordings/PVRRecordings.cpp
index 492f5412ed..777e5a1320 100644
--- a/xbmc/pvr/recordings/PVRRecordings.cpp
+++ b/xbmc/pvr/recordings/PVRRecordings.cpp
@@ -395,16 +395,6 @@ void CPVRRecordings::UpdateFromClient(const CPVRRecordingPtr &tag)
{
newTag = CPVRRecordingPtr(new CPVRRecording);
newTag->Update(*tag);
- if (newTag->BroadcastUid() != EPG_TAG_INVALID_UID)
- {
- const CPVRChannelPtr channel(newTag->Channel());
- if (channel)
- {
- const CPVREpgInfoTagPtr epgTag = CServiceBroker::GetPVRManager().EpgContainer().GetTagById(channel, newTag->BroadcastUid());
- if (epgTag)
- epgTag->SetRecording(newTag);
- }
- }
newTag->m_iRecordingId = ++m_iLastId;
m_recordings.insert(std::make_pair(CPVRRecordingUid(newTag->m_iClientId, newTag->m_strRecordingId), newTag));
if (newTag->IsRadio())
@@ -416,6 +406,9 @@ void CPVRRecordings::UpdateFromClient(const CPVRRecordingPtr &tag)
CPVRRecordingPtr CPVRRecordings::GetRecordingForEpgTag(const CPVREpgInfoTagPtr &epgTag) const
{
+ if (!epgTag)
+ return {};
+
CSingleLock lock(m_critSection);
for (const auto recording : m_recordings)
@@ -423,25 +416,21 @@ CPVRRecordingPtr CPVRRecordings::GetRecordingForEpgTag(const CPVREpgInfoTagPtr &
if (recording.second->IsDeleted())
continue;
+ if (recording.second->ClientID() != epgTag->ClientID())
+ continue;
+
+ if (recording.second->ChannelUid() != epgTag->UniqueChannelID())
+ continue;
+
unsigned int iEpgEvent = recording.second->BroadcastUid();
if (iEpgEvent != EPG_TAG_INVALID_UID)
{
if (iEpgEvent == epgTag->UniqueBroadcastID())
- {
- // uid matches. perfect.
return recording.second;
- }
}
else
{
- // uid is optional, so check other relevant data.
-
- // note: don't use recording.second->Channel() for comparing channels here as this can lead
- // to deadlocks. compare client ids and channel ids instead, this has the same effect.
- if (epgTag->Channel() &&
- recording.second->ClientID() == epgTag->Channel()->ClientID() &&
- recording.second->ChannelUid() == epgTag->Channel()->UniqueID() &&
- recording.second->RecordingTimeAsUTC() <= epgTag->StartAsUTC() &&
+ if (recording.second->RecordingTimeAsUTC() <= epgTag->StartAsUTC() &&
recording.second->EndTimeAsUTC() >= epgTag->EndAsUTC())
return recording.second;
}
diff --git a/xbmc/pvr/timers/CMakeLists.txt b/xbmc/pvr/timers/CMakeLists.txt
index 52026ef0b8..fd4f19ce68 100644
--- a/xbmc/pvr/timers/CMakeLists.txt
+++ b/xbmc/pvr/timers/CMakeLists.txt
@@ -1,9 +1,11 @@
set(SOURCES PVRTimerInfoTag.cpp
PVRTimers.cpp
+ PVRTimersPath.cpp
PVRTimerType.cpp)
set(HEADERS PVRTimerInfoTag.h
PVRTimers.h
+ PVRTimersPath.h
PVRTimerType.h)
core_add_library(pvr_timers)
diff --git a/xbmc/pvr/timers/PVRTimerInfoTag.cpp b/xbmc/pvr/timers/PVRTimerInfoTag.cpp
index 363ebd6c7c..7dcf26efad 100644
--- a/xbmc/pvr/timers/PVRTimerInfoTag.cpp
+++ b/xbmc/pvr/timers/PVRTimerInfoTag.cpp
@@ -23,7 +23,7 @@
#include "pvr/addons/PVRClients.h"
#include "pvr/channels/PVRChannelGroupsContainer.h"
#include "pvr/epg/Epg.h"
-#include "pvr/timers/PVRTimers.h"
+#include "pvr/timers/PVRTimersPath.h"
using namespace PVR;
@@ -189,10 +189,14 @@ bool CPVRTimerInfoTag::operator ==(const CPVRTimerInfoTag& right) const
m_iTimerId == right.m_iTimerId &&
m_strSeriesLink == right.m_strSeriesLink &&
m_iEpgUid == right.m_iEpgUid &&
- m_iActiveChildTimers == right.m_iActiveChildTimers &&
- m_bHasChildConflictNOK== right.m_bHasChildConflictNOK &&
- m_bHasChildRecording == right.m_bHasChildRecording &&
- m_bHasChildErrors == right.m_bHasChildErrors);
+ m_iActiveTVChildTimers == right.m_iActiveTVChildTimers &&
+ m_iActiveRadioChildTimers == right.m_iActiveRadioChildTimers &&
+ m_bHasTVChildConflictNOK == right.m_bHasTVChildConflictNOK &&
+ m_bHasRadioChildConflictNOK == right.m_bHasRadioChildConflictNOK &&
+ m_bHasTVChildRecording == right.m_bHasTVChildRecording &&
+ m_bHasRadioChildRecording == right.m_bHasRadioChildRecording &&
+ m_bHasTVChildErrors == right.m_bHasTVChildErrors &&
+ m_bHasRadioChildErrors == right.m_bHasRadioChildErrors);
}
/**
@@ -291,13 +295,6 @@ void CPVRTimerInfoTag::Serialize(CVariant &value) const
value["serieslink"] = m_strSeriesLink;
}
-void CPVRTimerInfoTag::UpdateEpgInfoTag(void)
-{
- CSingleLock lock(m_critSection);
- m_epgTag.reset();
- GetEpgInfoTag();
-}
-
void CPVRTimerInfoTag::UpdateSummary(void)
{
CSingleLock lock(m_critSection);
@@ -362,7 +359,7 @@ void CPVRTimerInfoTag::SetTimerType(const CPVRTimerTypePtr &type)
/**
* Get the status string of this Timer, is used by the GUIInfoManager
*/
-std::string CPVRTimerInfoTag::GetStatus() const
+std::string CPVRTimerInfoTag::GetStatus(bool bRadio) const
{
std::string strReturn = g_localizeStrings.Get(305);
CSingleLock lock(m_critSection);
@@ -381,20 +378,21 @@ std::string CPVRTimerInfoTag::GetStatus() const
else if (m_state == PVR_TIMER_STATE_DISABLED)
strReturn = g_localizeStrings.Get(13106);
else if (m_state == PVR_TIMER_STATE_COMPLETED)
- if (m_bHasChildRecording)
+ if ((m_bHasTVChildRecording && !bRadio) || (m_bHasRadioChildRecording && bRadio))
strReturn = g_localizeStrings.Get(19162); // "Recording active"
else
strReturn = g_localizeStrings.Get(19256); // "Completed"
else if (m_state == PVR_TIMER_STATE_SCHEDULED || m_state == PVR_TIMER_STATE_NEW)
{
- if (m_bHasChildRecording)
+ if ((m_bHasTVChildRecording && !bRadio) || (m_bHasRadioChildRecording && bRadio))
strReturn = g_localizeStrings.Get(19162); // "Recording active"
- else if (m_bHasChildErrors)
+ else if ((m_bHasTVChildErrors && !bRadio) || (m_bHasRadioChildErrors && bRadio))
strReturn = g_localizeStrings.Get(257); // "Error"
- else if (m_bHasChildConflictNOK)
+ else if ((m_bHasTVChildConflictNOK && !bRadio) || (m_bHasRadioChildConflictNOK && bRadio))
strReturn = g_localizeStrings.Get(19276); // "Conflict error"
- else if (m_iActiveChildTimers > 0)
- strReturn = StringUtils::Format(g_localizeStrings.Get(19255).c_str(), m_iActiveChildTimers); // "%d scheduled"
+ else if ((m_iActiveTVChildTimers > 0 && !bRadio) || (m_iActiveRadioChildTimers > 0 && bRadio))
+ strReturn = StringUtils::Format(g_localizeStrings.Get(19255).c_str(),
+ bRadio ? m_iActiveRadioChildTimers : m_iActiveTVChildTimers); // "%d scheduled"
}
return strReturn;
@@ -581,17 +579,34 @@ bool CPVRTimerInfoTag::UpdateChildState(const CPVRTimerInfoTagPtr &childTimer)
case PVR_TIMER_STATE_NEW:
case PVR_TIMER_STATE_SCHEDULED:
case PVR_TIMER_STATE_CONFLICT_OK:
- m_iActiveChildTimers++;
+ if (childTimer->m_bIsRadio)
+ m_iActiveRadioChildTimers++;
+ else
+ m_iActiveTVChildTimers++;
break;
case PVR_TIMER_STATE_RECORDING:
- m_iActiveChildTimers++;
- m_bHasChildRecording = true;
+ if (childTimer->m_bIsRadio)
+ {
+ m_iActiveRadioChildTimers++;
+ m_bHasRadioChildRecording = true;
+ }
+ else
+ {
+ m_iActiveTVChildTimers++;
+ m_bHasTVChildRecording = true;
+ }
break;
case PVR_TIMER_STATE_CONFLICT_NOK:
- m_bHasChildConflictNOK = true;
+ if (childTimer->m_bIsRadio)
+ m_bHasRadioChildConflictNOK = true;
+ else
+ m_bHasTVChildConflictNOK = true;
break;
case PVR_TIMER_STATE_ERROR:
- m_bHasChildErrors = true;
+ if (childTimer->m_bIsRadio)
+ m_bHasRadioChildErrors = true;
+ else
+ m_bHasTVChildErrors = true;
break;
case PVR_TIMER_STATE_COMPLETED:
case PVR_TIMER_STATE_ABORTED:
@@ -605,10 +620,14 @@ bool CPVRTimerInfoTag::UpdateChildState(const CPVRTimerInfoTagPtr &childTimer)
void CPVRTimerInfoTag::ResetChildState()
{
- m_iActiveChildTimers = 0;
- m_bHasChildConflictNOK = false;
- m_bHasChildRecording = false;
- m_bHasChildErrors = false;
+ m_iActiveTVChildTimers = 0;
+ m_iActiveRadioChildTimers = 0;
+ m_bHasTVChildConflictNOK = false;
+ m_bHasRadioChildConflictNOK = false;
+ m_bHasTVChildRecording = false;
+ m_bHasRadioChildRecording = false;
+ m_bHasTVChildErrors = false;
+ m_bHasRadioChildErrors = false;
}
bool CPVRTimerInfoTag::UpdateOnClient()
@@ -687,7 +706,7 @@ CPVRTimerInfoTagPtr CPVRTimerInfoTag::CreateInstantTimerTag(const CPVRChannelPtr
newTimer->SetTimerType(timerType);
if (epgTag)
- newTimer->SetEpgTag(epgTag);
+ newTimer->SetEpgInfoTag(epgTag);
else
newTimer->UpdateEpgInfoTag();
}
@@ -723,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");
@@ -735,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();
@@ -794,7 +816,7 @@ CPVRTimerInfoTagPtr CPVRTimerInfoTag::CreateFromEpg(const CPVREpgInfoTagPtr &tag
newTag->SetTimerType(timerType);
newTag->UpdateSummary();
- newTag->SetEpgTag(tag);
+ newTag->SetEpgInfoTag(tag);
/* unused only for reference */
newTag->m_strFileNameAndPath = CPVRTimersPath::PATH_NEW;
@@ -912,6 +934,19 @@ std::string CPVRTimerInfoTag::GetDeletedNotificationText() const
return StringUtils::Format("%s: '%s'", g_localizeStrings.Get(stringID).c_str(), m_strTitle.c_str());
}
+void CPVRTimerInfoTag::SetEpgInfoTag(const std::shared_ptr<CPVREpgInfoTag>& tag)
+{
+ CSingleLock lock(m_critSection);
+ m_epgTag = tag;
+}
+
+void CPVRTimerInfoTag::UpdateEpgInfoTag()
+{
+ CSingleLock lock(m_critSection);
+ m_epgTag.reset();
+ GetEpgInfoTag();
+}
+
CPVREpgInfoTagPtr CPVRTimerInfoTag::GetEpgInfoTag(bool bCreate /* = true */) const
{
if (!m_epgTag && bCreate)
@@ -939,7 +974,7 @@ CPVREpgInfoTagPtr CPVRTimerInfoTag::GetEpgInfoTag(bool bCreate /* = true */) con
}
}
- if (!m_epgTag && m_epTagRefetchTimeout.IsTimePast())
+ if (!IsTimerRule() && !m_epgTag && m_epTagRefetchTimeout.IsTimePast())
{
m_epTagRefetchTimeout.Set(30000); // try to fetch missing epg tag from backend at most every 30 secs
@@ -953,26 +988,9 @@ CPVREpgInfoTagPtr CPVRTimerInfoTag::GetEpgInfoTag(bool bCreate /* = true */) con
if (startTime > 0 && endTime > 0)
{
// try to fetch missing epg tag from backend
- const CPVREpgInfoTagPtr epgTag = epg->GetTagBetween(StartAsUTC() - CDateTimeSpan(0, 0, 2, 0), EndAsUTC() + CDateTimeSpan(0, 0, 2, 0), true);
- if (epgTag)
- {
- bool bTagMatches = !IsTimerRule();
- if (!bTagMatches)
- {
- // Check whether the tag actually is an event that belongs to a child of this timer rule
- const CPVRTimerInfoTagPtr timer = epgTag->Timer();
- if (timer && (timer->GetTimerRuleId() == m_iClientIndex))
- {
- bTagMatches = true;
- }
- }
-
- if (bTagMatches)
- {
- m_epgTag = epgTag;
- m_iEpgUid = m_epgTag->UniqueBroadcastID();
- }
- }
+ m_epgTag = epg->GetTagBetween(StartAsUTC() - CDateTimeSpan(0, 0, 2, 0), EndAsUTC() + CDateTimeSpan(0, 0, 2, 0), true);
+ if (m_epgTag)
+ m_iEpgUid = m_epgTag->UniqueBroadcastID();
}
}
}
@@ -981,24 +999,6 @@ CPVREpgInfoTagPtr CPVRTimerInfoTag::GetEpgInfoTag(bool bCreate /* = true */) con
return m_epgTag;
}
-void CPVRTimerInfoTag::SetEpgTag(const CPVREpgInfoTagPtr &tag)
-{
- CPVREpgInfoTagPtr previousTag;
- {
- CSingleLock lock(m_critSection);
- previousTag = m_epgTag;
- m_epgTag = tag;
- }
-
- if (previousTag)
- previousTag->ClearTimer();
-}
-
-void CPVRTimerInfoTag::ClearEpgTag(void)
-{
- SetEpgTag(CPVREpgInfoTagPtr());
-}
-
bool CPVRTimerInfoTag::HasChannel() const
{
return m_channel.get() != nullptr;
diff --git a/xbmc/pvr/timers/PVRTimerInfoTag.h b/xbmc/pvr/timers/PVRTimerInfoTag.h
index e1408eae32..868d3569f0 100644
--- a/xbmc/pvr/timers/PVRTimerInfoTag.h
+++ b/xbmc/pvr/timers/PVRTimerInfoTag.h
@@ -55,7 +55,7 @@ namespace PVR
void UpdateSummary(void);
- std::string GetStatus() const;
+ std::string GetStatus(bool bRadio) const;
std::string GetTypeAsString() const;
static const int DEFAULT_PVRRECORD_INSTANTRECORDTIME = -1;
@@ -77,6 +77,12 @@ namespace PVR
static CPVRTimerInfoTagPtr CreateFromEpg(const CPVREpgInfoTagPtr &tag, bool bCreateRule = false);
/*!
+ * @brief Associate the given epg tag with this timer.
+ * @param tag The epg tag to assign.
+ */
+ void SetEpgInfoTag(const std::shared_ptr<CPVREpgInfoTag>& tag);
+
+ /*!
* @brief get the epg info tag associated with this timer, if any
* @param bCreate if true, try to find the epg tag if not yet set (lazy evaluation)
* @return the epg info tag associated with this timer or null if there is no tag
@@ -247,17 +253,6 @@ namespace PVR
bool UpdateOnClient();
/*!
- * @brief Associate the given epg tag with this timer; before, clear old timer at associated epg tag, if any.
- * @param tag The epg tag to assign.
- */
- void SetEpgTag(const CPVREpgInfoTagPtr &tag);
-
- /*!
- * @brief Clear the epg tag associated with this timer; before, clear this timer at associated epg tag, if any.
- */
- void ClearEpgTag(void);
-
- /*!
* @brief Update the channel associated with this timer.
* @return the channel for the timer. Can be empty for epg based repeating timers (e.g. "match any channel" rules)
*/
@@ -316,10 +311,14 @@ namespace PVR
CDateTime m_FirstDay; /*!< if it is a manual timer rule the first date it starts */
CPVRTimerTypePtr m_timerType; /*!< the type of this timer */
- unsigned int m_iActiveChildTimers; /*!< @brief Number of active timers which have this timer as their m_iParentClientIndex */
- bool m_bHasChildConflictNOK; /*!< @brief Has at least one child timer with status PVR_TIMER_STATE_CONFLICT_NOK */
- bool m_bHasChildRecording; /*!< @brief Has at least one child timer with status PVR_TIMER_STATE_RECORDING */
- bool m_bHasChildErrors; /*!< @brief Has at least one child timer with status PVR_TIMER_STATE_ERROR */
+ unsigned int m_iActiveTVChildTimers; /*!< @brief Number of active TV timers which have this timer as their m_iParentClientIndex */
+ unsigned int m_iActiveRadioChildTimers; /*!< @brief Number of active radio timers which have this timer as their m_iParentClientIndex */
+ bool m_bHasTVChildConflictNOK; /*!< @brief Has at least one child TV timer with status PVR_TIMER_STATE_CONFLICT_NOK */
+ bool m_bHasRadioChildConflictNOK; /*!< @brief Has at least one child radio timer with status PVR_TIMER_STATE_CONFLICT_NOK */
+ bool m_bHasTVChildRecording; /*!< @brief Has at least one TV child timer with status PVR_TIMER_STATE_RECORDING */
+ bool m_bHasRadioChildRecording; /*!< @brief Has at least one radio child timer with status PVR_TIMER_STATE_RECORDING */
+ bool m_bHasTVChildErrors; /*!< @brief Has at least one child TV timer with status PVR_TIMER_STATE_ERROR */
+ bool m_bHasRadioChildErrors; /*!< @brief Has at least one child radio timer with status PVR_TIMER_STATE_ERROR */
std::string m_strSeriesLink; /*!< series link */
diff --git a/xbmc/pvr/timers/PVRTimers.cpp b/xbmc/pvr/timers/PVRTimers.cpp
index 1fcda74243..23e18c3f9e 100644
--- a/xbmc/pvr/timers/PVRTimers.cpp
+++ b/xbmc/pvr/timers/PVRTimers.cpp
@@ -8,7 +8,6 @@
#include "PVRTimers.h"
-#include <cstdlib>
#include <utility>
#include "FileItem.h"
@@ -17,8 +16,6 @@
#include "guilib/LocalizeStrings.h"
#include "settings/Settings.h"
#include "threads/SingleLock.h"
-#include "utils/StringUtils.h"
-#include "utils/URIUtils.h"
#include "utils/log.h"
#include "pvr/PVRJobs.h"
@@ -26,6 +23,7 @@
#include "pvr/addons/PVRClients.h"
#include "pvr/channels/PVRChannelGroupsContainer.h"
#include "pvr/epg/EpgContainer.h"
+#include "pvr/timers/PVRTimersPath.h"
using namespace PVR;
@@ -140,42 +138,6 @@ bool CPVRTimers::IsRecording(void) const
return false;
}
-bool CPVRTimers::SetEpgTagTimer(const CPVRTimerInfoTagPtr &timer)
-{
- if (timer->IsTimerRule() || timer->m_bStartAnyTime || timer->m_bEndAnyTime)
- return false;
-
- std::vector<CPVREpgInfoTagPtr> tags(CServiceBroker::GetPVRManager().EpgContainer().GetEpgTagsForTimer(timer));
-
- if (tags.empty())
- return false;
-
- // assign first matching epg tag to the timer.
- timer->SetEpgTag(tags.front());
-
- // assign timer to every matching epg tag.
- for (const auto &tag : tags)
- tag->SetTimer(timer);
-
- return true;
-}
-
-bool CPVRTimers::ClearEpgTagTimer(const CPVRTimerInfoTagPtr &timer)
-{
- if (timer->IsTimerRule() || timer->m_bStartAnyTime || timer->m_bEndAnyTime)
- return false;
-
- std::vector<CPVREpgInfoTagPtr> tags(CServiceBroker::GetPVRManager().EpgContainer().GetEpgTagsForTimer(timer));
-
- if (tags.empty())
- return false;
-
- for (const auto &tag : tags)
- tag->ClearTimer();
-
- return true;
-}
-
bool CPVRTimers::UpdateEntries(const CPVRTimersContainer &timers, const std::vector<int> &failedClients)
{
bool bChanged(false);
@@ -195,11 +157,8 @@ bool CPVRTimers::UpdateEntries(const CPVRTimersContainer &timers, const std::vec
{
/* if it's present, update the current tag */
bool bStateChanged(existingTimer->m_state != (*timerIt)->m_state);
- ClearEpgTagTimer(existingTimer);
if (existingTimer->UpdateEntry(*timerIt))
{
- SetEpgTagTimer(existingTimer);
-
bChanged = true;
existingTimer->ResetChildState();
@@ -220,7 +179,6 @@ bool CPVRTimers::UpdateEntries(const CPVRTimersContainer &timers, const std::vec
CPVRTimerInfoTagPtr newTimer = CPVRTimerInfoTagPtr(new CPVRTimerInfoTag);
newTimer->UpdateEntry(*timerIt);
newTimer->m_iTimerId = ++m_iLastId;
- SetEpgTagTimer(newTimer);
InsertTimer(newTimer);
bChanged = true;
@@ -269,8 +227,6 @@ bool CPVRTimers::UpdateEntries(const CPVRTimersContainer &timers, const std::vec
timerNotifications.push_back(std::make_pair(timer->m_iClientId, timer->GetDeletedNotificationText()));
- ClearEpgTagTimer(timer);
-
it2 = it->second.erase(it2);
bChanged = true;
@@ -283,8 +239,6 @@ bool CPVRTimers::UpdateEntries(const CPVRTimersContainer &timers, const std::vec
CLog::LogFC(LOGDEBUG, LOGPVR, "Changed start time timer %d on client %d",
timer->m_iClientIndex, timer->m_iClientId);
- ClearEpgTagTimer(timer);
-
/* remember timer */
timersToMove.push_back(timer);
@@ -307,10 +261,7 @@ bool CPVRTimers::UpdateEntries(const CPVRTimersContainer &timers, const std::vec
/* reinsert timers with changed timer start */
for (VecTimerInfoTag::const_iterator timerIt = timersToMove.begin(); timerIt != timersToMove.end(); ++timerIt)
- {
- SetEpgTagTimer(*timerIt);
InsertTimer(*timerIt);
- }
/* update child information for all parent timers */
for (const auto &tagsEntry : m_tags)
@@ -367,7 +318,7 @@ bool CPVRTimers::KindMatchesTag(const TimerKind &eKind, const CPVRTimerInfoTagPt
(eKind == TimerKindRadio && tag->m_bIsRadio);
}
-CFileItemPtr CPVRTimers::GetNextActiveTimer(const TimerKind &eKind) const
+std::shared_ptr<CPVRTimerInfoTag> CPVRTimers::GetNextActiveTimer(const TimerKind &eKind) const
{
CSingleLock lock(m_critSection);
@@ -380,31 +331,31 @@ CFileItemPtr CPVRTimers::GetNextActiveTimer(const TimerKind &eKind) const
!timersEntry->IsRecording() &&
!timersEntry->IsTimerRule() &&
!timersEntry->IsBroken())
- return CFileItemPtr(new CFileItem(timersEntry));
+ return timersEntry;
}
}
- return CFileItemPtr();
+ return std::shared_ptr<CPVRTimerInfoTag>();
}
-CFileItemPtr CPVRTimers::GetNextActiveTimer(void) const
+std::shared_ptr<CPVRTimerInfoTag> CPVRTimers::GetNextActiveTimer(void) const
{
return GetNextActiveTimer(TimerKindAny);
}
-CFileItemPtr CPVRTimers::GetNextActiveTVTimer(void) const
+std::shared_ptr<CPVRTimerInfoTag> CPVRTimers::GetNextActiveTVTimer(void) const
{
return GetNextActiveTimer(TimerKindTV);
}
-CFileItemPtr CPVRTimers::GetNextActiveRadioTimer(void) const
+std::shared_ptr<CPVRTimerInfoTag> CPVRTimers::GetNextActiveRadioTimer(void) const
{
return GetNextActiveTimer(TimerKindRadio);
}
-std::vector<CFileItemPtr> CPVRTimers::GetActiveTimers(void) const
+std::vector<std::shared_ptr<CPVRTimerInfoTag>> CPVRTimers::GetActiveTimers(void) const
{
- std::vector<CFileItemPtr> tags;
+ std::vector<std::shared_ptr<CPVRTimerInfoTag>> tags;
CSingleLock lock(m_critSection);
for (MapTags::const_iterator it = m_tags.begin(); it != m_tags.end(); ++it)
@@ -414,8 +365,7 @@ std::vector<CFileItemPtr> CPVRTimers::GetActiveTimers(void) const
CPVRTimerInfoTagPtr current = *timerIt;
if (current->IsActive() && !current->IsTimerRule() && !current->IsBroken())
{
- CFileItemPtr fileItem(new CFileItem(current));
- tags.push_back(fileItem);
+ tags.emplace_back(current);
}
}
}
@@ -458,9 +408,9 @@ int CPVRTimers::AmountActiveRadioTimers(void) const
return AmountActiveTimers(TimerKindRadio);
}
-std::vector<CFileItemPtr> CPVRTimers::GetActiveRecordings(const TimerKind &eKind) const
+std::vector<std::shared_ptr<CPVRTimerInfoTag>> CPVRTimers::GetActiveRecordings(const TimerKind& eKind) const
{
- std::vector<CFileItemPtr> tags;
+ std::vector<std::shared_ptr<CPVRTimerInfoTag>> tags;
CSingleLock lock(m_critSection);
for (const auto &tagsEntry : m_tags)
@@ -472,8 +422,7 @@ std::vector<CFileItemPtr> CPVRTimers::GetActiveRecordings(const TimerKind &eKind
!timersEntry->IsTimerRule() &&
!timersEntry->IsBroken())
{
- CFileItemPtr fileItem(new CFileItem(timersEntry));
- tags.push_back(fileItem);
+ tags.emplace_back(timersEntry);
}
}
}
@@ -481,17 +430,17 @@ std::vector<CFileItemPtr> CPVRTimers::GetActiveRecordings(const TimerKind &eKind
return tags;
}
-std::vector<CFileItemPtr> CPVRTimers::GetActiveRecordings(void) const
+std::vector<std::shared_ptr<CPVRTimerInfoTag>> CPVRTimers::GetActiveRecordings() const
{
return GetActiveRecordings(TimerKindAny);
}
-std::vector<CFileItemPtr> CPVRTimers::GetActiveTVRecordings(void) const
+std::vector<std::shared_ptr<CPVRTimerInfoTag>> CPVRTimers::GetActiveTVRecordings() const
{
return GetActiveRecordings(TimerKindTV);
}
-std::vector<CFileItemPtr> CPVRTimers::GetActiveRadioRecordings(void) const
+std::vector<std::shared_ptr<CPVRTimerInfoTag>> CPVRTimers::GetActiveRadioRecordings() const
{
return GetActiveRecordings(TimerKindRadio);
}
@@ -561,7 +510,7 @@ bool CPVRTimers::GetRootDirectory(const CPVRTimersPath &path, CFileItemList &ite
{
for (const auto &timer : tagsEntry.second)
{
- if ((bRadio == timer->m_bIsRadio) &&
+ if ((bRadio == timer->m_bIsRadio || (bRules && timer->m_iClientChannelUid == PVR_TIMER_ANY_CHANNEL)) &&
(bRules == timer->IsTimerRule()) &&
(!bHideDisabled || (timer->m_state != PVR_TIMER_STATE_DISABLED)))
{
@@ -742,39 +691,29 @@ CPVRTimerInfoTagPtr CPVRTimers::GetTimerForEpgTag(const CPVREpgInfoTagPtr &epgTa
{
if (epgTag)
{
- // already a timer assigned to tag?
- const CPVRTimerInfoTagPtr timer(epgTag->Timer());
- if (timer)
- return timer;
+ CSingleLock lock(m_critSection);
- // try to find a matching timer for the tag.
- const CPVRChannelPtr channel(epgTag->Channel());
- if (channel)
+ for (const auto &tagsEntry : m_tags)
{
- CSingleLock lock(m_critSection);
-
- 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;
}
}
}
@@ -783,43 +722,6 @@ CPVRTimerInfoTagPtr CPVRTimers::GetTimerForEpgTag(const CPVREpgInfoTagPtr &epgTa
return CPVRTimerInfoTagPtr();
}
-bool CPVRTimers::HasRecordingTimerForRecording(const CPVRRecording &recording) const
-{
- return GetRecordingTimerForRecording(recording) != nullptr;
-}
-
-CPVRTimerInfoTagPtr CPVRTimers::GetRecordingTimerForRecording(const CPVRRecording &recording) const
-{
- CSingleLock lock(m_critSection);
-
- for (const auto &tagsEntry : m_tags)
- {
- for (const auto &timersEntry : tagsEntry.second)
- {
- if (timersEntry->IsRecording() &&
- !timersEntry->IsTimerRule() &&
- !timersEntry->IsBroken() &&
- timersEntry->m_iClientId == recording.ClientID() &&
- timersEntry->m_iClientChannelUid == recording.ChannelUid())
- {
- // first, match epg event uids, if available
- if (timersEntry->UniqueBroadcastID() == recording.BroadcastUid() &&
- timersEntry->UniqueBroadcastID() != EPG_TAG_INVALID_UID)
- return timersEntry;
-
- // alternatively, match start and end times
- const CDateTime timerStart = timersEntry->StartAsUTC() - CDateTimeSpan(0, 0, timersEntry->m_iMarginStart, 0);
- const CDateTime timerEnd = timersEntry->EndAsUTC() + CDateTimeSpan(0, 0, timersEntry->m_iMarginEnd, 0);
- if (timerStart <= recording.RecordingTimeAsUTC() &&
- timerEnd >= recording.EndTimeAsUTC())
- return timersEntry;
- }
- }
- }
-
- return CPVRTimerInfoTagPtr();
-}
-
CPVRTimerInfoTagPtr CPVRTimers::GetTimerRule(const CPVRTimerInfoTagPtr &timer) const
{
if (timer)
@@ -847,7 +749,7 @@ CFileItemPtr CPVRTimers::GetTimerRule(const CFileItemPtr &item) const
{
CPVRTimerInfoTagPtr timer;
if (item && item->HasEPGInfoTag())
- timer = item->GetEPGInfoTag()->Timer();
+ timer = GetTimerForEpgTag(item->GetEPGInfoTag());
else if (item && item->HasPVRTimerInfoTag())
timer = item->GetPVRTimerInfoTag();
@@ -876,11 +778,11 @@ CDateTime CPVRTimers::GetNextEventTime(void) const
CDateTime wakeuptime;
/* Check next active time */
- CFileItemPtr item = GetNextActiveTimer();
- if (item && item->HasPVRTimerInfoTag())
+ const std::shared_ptr<CPVRTimerInfoTag> timer = GetNextActiveTimer();
+ if (timer)
{
- const CDateTimeSpan prestart(0, 0, item->GetPVRTimerInfoTag()->MarginStart(), 0);
- const CDateTime start = item->GetPVRTimerInfoTag()->StartAsUTC();
+ const CDateTimeSpan prestart(0, 0, timer->MarginStart(), 0);
+ const CDateTime start = timer->StartAsUTC();
wakeuptime = ((start - prestart - prewakeup - idle) > now) ?
start - prestart - prewakeup :
now + idle;
@@ -949,73 +851,3 @@ CPVRTimerInfoTagPtr CPVRTimers::GetById(unsigned int iTimerId) const
}
return item;
}
-
-
-//= CPVRTimersPath ============================================================
-
-const std::string CPVRTimersPath::PATH_ADDTIMER = "pvr://timers/addtimer/";
-const std::string CPVRTimersPath::PATH_NEW = "pvr://timers/new/";
-
-CPVRTimersPath::CPVRTimersPath(const std::string &strPath)
-{
- Init(strPath);
-}
-
-CPVRTimersPath::CPVRTimersPath(const std::string &strPath, int iClientId, unsigned int iParentId)
-{
- if (Init(strPath))
- {
- /* set/replace client and parent id. */
- m_path = StringUtils::Format("pvr://timers/%s/%s/%d/%d",
- m_bRadio ? "radio" : "tv",
- m_bTimerRules ? "rules" : "timers",
- iClientId,
- iParentId);
- m_iClientId = iClientId;
- m_iParentId = iParentId;
- m_bRoot = false;
- }
-}
-
-CPVRTimersPath::CPVRTimersPath(bool bRadio, bool bTimerRules) :
- m_path(StringUtils::Format(
- "pvr://timers/%s/%s", bRadio ? "radio" : "tv", bTimerRules ? "rules" : "timers")),
- m_bValid(true),
- m_bRoot(true),
- m_bRadio(bRadio),
- m_bTimerRules(bTimerRules),
- m_iClientId(-1),
- m_iParentId(0)
-{
-}
-
-bool CPVRTimersPath::Init(const std::string &strPath)
-{
- std::string strVarPath(strPath);
- URIUtils::RemoveSlashAtEnd(strVarPath);
-
- m_path = strVarPath;
- const std::vector<std::string> segments = URIUtils::SplitPath(m_path);
-
- m_bValid = (((segments.size() == 4) || (segments.size() == 6)) &&
- (segments.at(1) == "timers") &&
- ((segments.at(2) == "radio") || (segments.at(2) == "tv"))&&
- ((segments.at(3) == "rules") || (segments.at(3) == "timers")));
- m_bRoot = (m_bValid && (segments.size() == 4));
- m_bRadio = (m_bValid && (segments.at(2) == "radio"));
- m_bTimerRules = (m_bValid && (segments.at(3) == "rules"));
-
- if (!m_bValid || m_bRoot)
- {
- m_iClientId = -1;
- m_iParentId = 0;
- }
- else
- {
- char *end;
- m_iClientId = std::strtol (segments.at(4).c_str(), &end, 10);
- m_iParentId = std::strtoul(segments.at(5).c_str(), &end, 10);
- }
-
- return m_bValid;
-}
diff --git a/xbmc/pvr/timers/PVRTimers.h b/xbmc/pvr/timers/PVRTimers.h
index 32231e6656..4664c37a1b 100644
--- a/xbmc/pvr/timers/PVRTimers.h
+++ b/xbmc/pvr/timers/PVRTimers.h
@@ -26,7 +26,6 @@ typedef std::shared_ptr<CFileItem> CFileItemPtr;
namespace PVR
{
- class CPVRRecording;
class CPVRTimersPath;
class CPVRTimersContainer
@@ -87,24 +86,24 @@ namespace PVR
bool Update(void);
/*!
- * @return The tv or radio timer that will be active next (state scheduled), or an empty fileitemptr if none.
+ * @return The tv or radio timer that will be active next (state scheduled), or nullptr if none.
*/
- CFileItemPtr GetNextActiveTimer(void) const;
+ std::shared_ptr<CPVRTimerInfoTag> GetNextActiveTimer(void) const;
/*!
- * @return The tv timer that will be active next (state scheduled), or an empty fileitemptr if none.
+ * @return The tv timer that will be active next (state scheduled), or nullptr if none.
*/
- CFileItemPtr GetNextActiveTVTimer(void) const;
+ std::shared_ptr<CPVRTimerInfoTag> GetNextActiveTVTimer(void) const;
/*!
- * @return The radio timer that will be active next (state scheduled), or an empty fileitemptr if none.
+ * @return The radio timer that will be active next (state scheduled), or nullptr if none.
*/
- CFileItemPtr GetNextActiveRadioTimer(void) const;
+ std::shared_ptr<CPVRTimerInfoTag> GetNextActiveRadioTimer(void) const;
/*!
* @return All timers that are active (states scheduled or recording)
*/
- std::vector<CFileItemPtr> GetActiveTimers(void) const;
+ std::vector<std::shared_ptr<CPVRTimerInfoTag>> GetActiveTimers(void) const;
/*!
* Get all timers
@@ -135,17 +134,17 @@ namespace PVR
/*!
* @return All tv and radio timers that are recording
*/
- std::vector<CFileItemPtr> GetActiveRecordings(void) const;
+ std::vector<std::shared_ptr<CPVRTimerInfoTag>> GetActiveRecordings() const;
/*!
* @return All tv timers that are recording
*/
- std::vector<CFileItemPtr> GetActiveTVRecordings(void) const;
+ std::vector<std::shared_ptr<CPVRTimerInfoTag>> GetActiveTVRecordings() const;
/*!
* @return All radio timers that are recording
*/
- std::vector<CFileItemPtr> GetActiveRadioRecordings(void) const;
+ std::vector<std::shared_ptr<CPVRTimerInfoTag>> GetActiveRadioRecordings() const;
/*!
* @return True when recording, false otherwise.
@@ -237,28 +236,14 @@ namespace PVR
/*!
* @brief Get the timer tag that matches the given epg tag.
* @param epgTag The epg tag.
- * @return The requested timer tag, or an empty fileitemptr if none was found.
+ * @return The requested timer tag, or nullptr if none was found.
*/
CPVRTimerInfoTagPtr GetTimerForEpgTag(const CPVREpgInfoTagPtr &epgTag) const;
/*!
- * @brief Check whether there is a timer currently recording the given recording.
- * @param recording The recording to check.
- * @return true if there is a timer currently recording the given recording, false otherwise.
- */
- bool HasRecordingTimerForRecording(const CPVRRecording &recording) const;
-
- /*!
- * @brief Get the timer currently recording the given recording, if any.
- * @param recording The recording to check.
- * @return The requested timer tag, or an null if none was found.
- */
- CPVRTimerInfoTagPtr GetRecordingTimerForRecording(const CPVRRecording &recording) const;
-
- /*!
* Get the timer rule for a given timer tag
* @param timer The timer to query the timer rule for
- * @return The timer rule, or null if none was found.
+ * @return The timer rule, or nullptr if none was found.
*/
CPVRTimerInfoTagPtr GetTimerRule(const CPVRTimerInfoTagPtr &timer) const;
@@ -287,8 +272,6 @@ namespace PVR
bool UpdateEntries(const CPVRTimersContainer &timers, const std::vector<int> &failedClients);
bool GetRootDirectory(const CPVRTimersPath &path, CFileItemList &items) const;
bool GetSubDirectory(const CPVRTimersPath &path, CFileItemList &items) const;
- bool SetEpgTagTimer(const CPVRTimerInfoTagPtr &timer);
- bool ClearEpgTagTimer(const CPVRTimerInfoTagPtr &timer);
enum TimerKind
{
@@ -299,44 +282,12 @@ namespace PVR
bool KindMatchesTag(const TimerKind &eKind, const CPVRTimerInfoTagPtr &tag) const;
- CFileItemPtr GetNextActiveTimer(const TimerKind &eKind) const;
+ std::shared_ptr<CPVRTimerInfoTag> GetNextActiveTimer(const TimerKind& eKind) const;
int AmountActiveTimers(const TimerKind &eKind) const;
- std::vector<CFileItemPtr> GetActiveRecordings(const TimerKind &eKind) const;
+ std::vector<std::shared_ptr<CPVRTimerInfoTag>> GetActiveRecordings(const TimerKind& eKind) const;
int AmountActiveRecordings(const TimerKind &eKind) const;
bool m_bIsUpdating = false;
CPVRSettings m_settings;
};
-
- class CPVRTimersPath
- {
- public:
- static const std::string PATH_ADDTIMER;
- static const std::string PATH_NEW;
-
- explicit CPVRTimersPath(const std::string &strPath);
- CPVRTimersPath(const std::string &strPath, int iClientId, unsigned int iParentId);
- CPVRTimersPath(bool bRadio, bool bTimerRules);
-
- bool IsValid() const { return m_bValid; }
-
- const std::string &GetPath() const { return m_path; }
- bool IsTimersRoot() const { return m_bRoot; }
- bool IsTimerRule() const { return !IsTimersRoot(); }
- bool IsRadio() const { return m_bRadio; }
- bool IsRules() const { return m_bTimerRules; }
- int GetClientId() const { return m_iClientId; }
- unsigned int GetParentId() const { return m_iParentId; }
-
- private:
- bool Init(const std::string &strPath);
-
- std::string m_path;
- bool m_bValid;
- bool m_bRoot;
- bool m_bRadio;
- bool m_bTimerRules;
- int m_iClientId;
- unsigned int m_iParentId;
- };
}
diff --git a/xbmc/pvr/timers/PVRTimersPath.cpp b/xbmc/pvr/timers/PVRTimersPath.cpp
new file mode 100644
index 0000000000..43c6ea03e7
--- /dev/null
+++ b/xbmc/pvr/timers/PVRTimersPath.cpp
@@ -0,0 +1,83 @@
+/*
+ * 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 "PVRTimersPath.h"
+
+#include <cstdlib>
+#include <vector>
+
+#include "utils/StringUtils.h"
+#include "utils/URIUtils.h"
+
+using namespace PVR;
+
+const std::string CPVRTimersPath::PATH_ADDTIMER = "pvr://timers/addtimer/";
+const std::string CPVRTimersPath::PATH_NEW = "pvr://timers/new/";
+
+CPVRTimersPath::CPVRTimersPath(const std::string& strPath)
+{
+ Init(strPath);
+}
+
+CPVRTimersPath::CPVRTimersPath(const std::string& strPath, int iClientId, unsigned int iParentId)
+{
+ if (Init(strPath))
+ {
+ // set/replace client and parent id.
+ m_path = StringUtils::Format("pvr://timers/%s/%s/%d/%d",
+ m_bRadio ? "radio" : "tv",
+ m_bTimerRules ? "rules" : "timers",
+ iClientId,
+ iParentId);
+ m_iClientId = iClientId;
+ m_iParentId = iParentId;
+ m_bRoot = false;
+ }
+}
+
+CPVRTimersPath::CPVRTimersPath(bool bRadio, bool bTimerRules) :
+ m_path(StringUtils::Format(
+ "pvr://timers/%s/%s", bRadio ? "radio" : "tv", bTimerRules ? "rules" : "timers")),
+ m_bValid(true),
+ m_bRoot(true),
+ m_bRadio(bRadio),
+ m_bTimerRules(bTimerRules),
+ m_iClientId(-1),
+ m_iParentId(0)
+{
+}
+
+bool CPVRTimersPath::Init(const std::string& strPath)
+{
+ std::string strVarPath(strPath);
+ URIUtils::RemoveSlashAtEnd(strVarPath);
+
+ m_path = strVarPath;
+ const std::vector<std::string> segments = URIUtils::SplitPath(m_path);
+
+ m_bValid = (((segments.size() == 4) || (segments.size() == 6)) &&
+ (segments.at(1) == "timers") &&
+ ((segments.at(2) == "radio") || (segments.at(2) == "tv"))&&
+ ((segments.at(3) == "rules") || (segments.at(3) == "timers")));
+ m_bRoot = (m_bValid && (segments.size() == 4));
+ m_bRadio = (m_bValid && (segments.at(2) == "radio"));
+ m_bTimerRules = (m_bValid && (segments.at(3) == "rules"));
+
+ if (!m_bValid || m_bRoot)
+ {
+ m_iClientId = -1;
+ m_iParentId = 0;
+ }
+ else
+ {
+ m_iClientId = std::stoi(segments.at(4));
+ m_iParentId = std::stoul(segments.at(5));
+ }
+
+ return m_bValid;
+}
diff --git a/xbmc/pvr/timers/PVRTimersPath.h b/xbmc/pvr/timers/PVRTimersPath.h
new file mode 100644
index 0000000000..f3e6584f61
--- /dev/null
+++ b/xbmc/pvr/timers/PVRTimersPath.h
@@ -0,0 +1,46 @@
+/*
+ * 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 <string>
+
+namespace PVR
+{
+ class CPVRTimersPath
+ {
+ public:
+ static const std::string PATH_ADDTIMER;
+ static const std::string PATH_NEW;
+
+ explicit CPVRTimersPath(const std::string& strPath);
+ CPVRTimersPath(const std::string& strPath, int iClientId, unsigned int iParentId);
+ CPVRTimersPath(bool bRadio, bool bTimerRules);
+
+ bool IsValid() const { return m_bValid; }
+
+ const std::string& GetPath() const { return m_path; }
+ bool IsTimersRoot() const { return m_bRoot; }
+ bool IsTimerRule() const { return !IsTimersRoot(); }
+ bool IsRadio() const { return m_bRadio; }
+ bool IsRules() const { return m_bTimerRules; }
+ int GetClientId() const { return m_iClientId; }
+ unsigned int GetParentId() const { return m_iParentId; }
+
+ private:
+ bool Init(const std::string &strPath);
+
+ std::string m_path;
+ bool m_bValid = false;
+ bool m_bRoot = false;
+ bool m_bRadio = false;
+ bool m_bTimerRules = false;
+ int m_iClientId = -1;
+ unsigned int m_iParentId = 0;
+ };
+}
diff --git a/xbmc/pvr/windows/GUIEPGGridContainer.cpp b/xbmc/pvr/windows/GUIEPGGridContainer.cpp
index bdff6f3dd5..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;
@@ -1314,13 +1312,13 @@ int CGUIEPGGridContainer::GetSelectedItem() const
return m_gridModel->GetGridItemIndex(m_channelCursor + m_channelOffset, m_blockCursor + m_blockOffset);
}
-CFileItemPtr CGUIEPGGridContainer::GetSelectedChannelItem() const
+CFileItemPtr CGUIEPGGridContainer::GetSelectedGridItem(int offset /*= 0*/) const
{
CFileItemPtr item;
if (m_gridModel->HasGridItems() &&
m_gridModel->ChannelItemsSize() > 0 &&
- m_channelCursor + m_channelOffset < m_gridModel->ChannelItemsSize() &&
+ m_channelCursor + m_channelOffset + offset < m_gridModel->ChannelItemsSize() &&
m_blockCursor + m_blockOffset < m_gridModel->GetBlockCount())
item = m_gridModel->GetGridItem(m_channelCursor + m_channelOffset, m_blockCursor + m_blockOffset);
diff --git a/xbmc/pvr/windows/GUIEPGGridContainer.h b/xbmc/pvr/windows/GUIEPGGridContainer.h
index db78ed711a..551fa2ac3e 100644
--- a/xbmc/pvr/windows/GUIEPGGridContainer.h
+++ b/xbmc/pvr/windows/GUIEPGGridContainer.h
@@ -58,7 +58,7 @@ namespace PVR
CGUIListItemPtr GetListItem(int offset, unsigned int flag = 0) const override;
std::string GetLabel(int info) const override;
- CFileItemPtr GetSelectedChannelItem() const;
+ CFileItemPtr GetSelectedGridItem(int offset = 0) const;
PVR::CPVRChannelPtr GetSelectedChannel() const;
CDateTime GetSelectedDate() const;
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/GUIViewStatePVR.cpp b/xbmc/pvr/windows/GUIViewStatePVR.cpp
index 5d39a04e18..fc755209bd 100644
--- a/xbmc/pvr/windows/GUIViewStatePVR.cpp
+++ b/xbmc/pvr/windows/GUIViewStatePVR.cpp
@@ -15,7 +15,7 @@
#include "view/ViewStateSettings.h"
#include "pvr/recordings/PVRRecordingsPath.h"
-#include "pvr/timers/PVRTimers.h"
+#include "pvr/timers/PVRTimersPath.h"
using namespace PVR;
diff --git a/xbmc/pvr/windows/GUIWindowPVRBase.cpp b/xbmc/pvr/windows/GUIWindowPVRBase.cpp
index 56433ef1df..6affc09428 100644
--- a/xbmc/pvr/windows/GUIWindowPVRBase.cpp
+++ b/xbmc/pvr/windows/GUIWindowPVRBase.cpp
@@ -179,9 +179,11 @@ bool CGUIWindowPVRBase::OnAction(const CAction &action)
case ACTION_NEXT_CHANNELGROUP:
{
// switch to next or previous group
- if (const CPVRChannelGroupPtr channelGroup = GetChannelGroup())
+ const std::shared_ptr<CPVRChannelGroup> channelGroup = GetChannelGroup();
+ if (channelGroup)
{
- SetChannelGroup(action.GetID() == ACTION_NEXT_CHANNELGROUP ? channelGroup->GetNextGroup() : channelGroup->GetPreviousGroup());
+ const CPVRChannelGroups* groups = CServiceBroker::GetPVRManager().ChannelGroups()->Get(channelGroup->IsRadio());
+ SetChannelGroup(action.GetID() == ACTION_NEXT_CHANNELGROUP ? groups->GetNextGroup(*channelGroup) : groups->GetPreviousGroup(*channelGroup));
}
return true;
}
diff --git a/xbmc/pvr/windows/GUIWindowPVRGuide.cpp b/xbmc/pvr/windows/GUIWindowPVRGuide.cpp
index 0473c5f9a9..580bcf4ed2 100644
--- a/xbmc/pvr/windows/GUIWindowPVRGuide.cpp
+++ b/xbmc/pvr/windows/GUIWindowPVRGuide.cpp
@@ -26,7 +26,10 @@
#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"
#include "pvr/windows/GUIEPGGridContainer.h"
using namespace KODI::MESSAGING;
@@ -34,7 +37,8 @@ using namespace PVR;
CGUIWindowPVRGuideBase::CGUIWindowPVRGuideBase(bool bRadio, int id, const std::string &xmlFile) :
CGUIWindowPVRBase(bRadio, id, xmlFile),
- m_bChannelSelectionRestored(false)
+ m_bChannelSelectionRestored(false),
+ m_bFirstOpen(true)
{
m_bRefreshTimelineItems = false;
m_bSyncRefreshTimelineItems = false;
@@ -223,7 +227,7 @@ bool CGUIWindowPVRGuideBase::GetDirectory(const std::string &strDirectory, CFile
// never call DoRefresh with locked mutex!
if (m_bSyncRefreshTimelineItems)
- m_refreshTimelineItemsThread->DoRefresh();
+ m_refreshTimelineItemsThread->DoRefresh(true);
{
CSingleLock lock(m_critSection);
@@ -250,6 +254,19 @@ void CGUIWindowPVRGuideBase::FormatAndSort(CFileItemList &items)
CGUIWindowPVRBase::FormatAndSort(items);
}
+CFileItemPtr CGUIWindowPVRGuideBase::GetCurrentListItem(int offset /*= 0*/)
+{
+ CFileItemPtr item = CGUIWindowPVRBase::GetCurrentListItem(offset);
+ if (!item)
+ {
+ // EPG "gap" item selected?
+ CGUIEPGGridContainer* epgGridContainer = GetGridControl();
+ if (epgGridContainer)
+ item = epgGridContainer->GetSelectedGridItem(offset);
+ }
+ return item;
+}
+
bool CGUIWindowPVRGuideBase::ShouldNavigateToGridContainer(int iAction)
{
CGUIEPGGridContainer *epgGridContainer = GetGridControl();
@@ -421,7 +438,7 @@ bool CGUIWindowPVRGuideBase::OnMessage(CGUIMessage& message)
else if (now < start)
{
// future event
- if (tag->HasTimer())
+ if (CServiceBroker::GetPVRManager().Timers()->GetTimerForEpgTag(tag))
CServiceBroker::GetPVRManager().GUIActions()->EditTimer(pItem);
else
{
@@ -439,7 +456,7 @@ bool CGUIWindowPVRGuideBase::OnMessage(CGUIMessage& message)
else
{
// past event
- if (tag->HasRecording())
+ if (CServiceBroker::GetPVRManager().Recordings()->GetRecordingForEpgTag(tag))
CServiceBroker::GetPVRManager().GUIActions()->PlayRecording(pItem, true);
else if (tag->IsPlayable())
CServiceBroker::GetPVRManager().GUIActions()->PlayEpgTag(pItem);
@@ -488,7 +505,7 @@ bool CGUIWindowPVRGuideBase::OnMessage(CGUIMessage& message)
CGUIEPGGridContainer *epgGridContainer = GetGridControl();
if (epgGridContainer)
{
- const CFileItemPtr item(epgGridContainer->GetSelectedChannelItem());
+ const CFileItemPtr item(epgGridContainer->GetSelectedGridItem());
if (item)
{
CServiceBroker::GetPVRManager().GUIActions()->SwitchToChannel(item, true);
@@ -603,8 +620,34 @@ bool CGUIWindowPVRGuideBase::RefreshTimelineItems()
std::unique_ptr<CFileItemList> timeline(new CFileItemList);
- // can be very expensive. never call with lock acquired.
- group->GetEPGAll(*timeline, true);
+ if (m_bFirstOpen)
+ {
+ m_bFirstOpen = false;
+
+ // very first open of the window. come up with some data very fast...
+ const std::vector<PVRChannelGroupMember> groupMembers = group->GetMembers();
+ for (const auto& groupMember : groupMembers)
+ {
+ // fake a channel without epg
+
+ const std::shared_ptr<CPVREpgInfoTag> gapTag
+ = std::make_shared<CPVREpgInfoTag>(std::make_shared<CPVREpgChannelData>(*(groupMember.channel)), -1);
+ timeline->Add(std::make_shared<CFileItem>(gapTag));
+ }
+
+ // next, fetch actual data.
+ m_bRefreshTimelineItems = true;
+ m_refreshTimelineItemsThread->DoRefresh(false);
+ }
+ else
+ {
+ // can be very expensive. never call with lock acquired.
+ const std::vector<std::shared_ptr<CPVREpgInfoTag>> tags = group->GetEPGAll(true);
+ for (const auto& tag : tags)
+ {
+ timeline->Add(std::make_shared<CFileItem>(tag));
+ }
+ }
CDateTime startDate(group->GetFirstEPGDate());
CDateTime endDate(group->GetLastEPGDate());
@@ -688,15 +731,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;
}
}
@@ -733,11 +776,15 @@ void CPVRRefreshTimelineItemsThread::Stop()
m_ready.Set(); // wake up the worker thread to let it exit
}
-void CPVRRefreshTimelineItemsThread::DoRefresh()
+void CPVRRefreshTimelineItemsThread::DoRefresh(bool bWait)
{
m_ready.Set(); // wake up the worker thread
- m_done.Reset();
- CGUIDialogBusy::WaitOnEvent(m_done, 100, false);
+
+ if (bWait)
+ {
+ m_done.Reset();
+ CGUIDialogBusy::WaitOnEvent(m_done, 100, false);
+ }
}
void CPVRRefreshTimelineItemsThread::Process()
diff --git a/xbmc/pvr/windows/GUIWindowPVRGuide.h b/xbmc/pvr/windows/GUIWindowPVRGuide.h
index 30583f30cb..868451c215 100644
--- a/xbmc/pvr/windows/GUIWindowPVRGuide.h
+++ b/xbmc/pvr/windows/GUIWindowPVRGuide.h
@@ -50,6 +50,7 @@ namespace PVR
std::string GetDirectoryPath(void) override { return ""; }
bool GetDirectory(const std::string &strDirectory, CFileItemList &items) override;
void FormatAndSort(CFileItemList &items) override;
+ CFileItemPtr GetCurrentListItem(int offset = 0) override;
void ClearData() override;
@@ -77,6 +78,7 @@ namespace PVR
std::unique_ptr<CFileItemList> m_newTimeline;
bool m_bChannelSelectionRestored;
+ std::atomic_bool m_bFirstOpen;
};
class CGUIWindowPVRTVGuide : public CGUIWindowPVRGuideBase
@@ -99,7 +101,7 @@ namespace PVR
void Process() override;
- void DoRefresh();
+ void DoRefresh(bool bWait);
void Stop();
private:
diff --git a/xbmc/pvr/windows/GUIWindowPVRSearch.cpp b/xbmc/pvr/windows/GUIWindowPVRSearch.cpp
index 05a88a0fae..4c21029ccc 100644
--- a/xbmc/pvr/windows/GUIWindowPVRSearch.cpp
+++ b/xbmc/pvr/windows/GUIWindowPVRSearch.cpp
@@ -23,6 +23,7 @@
#include "pvr/PVRItem.h"
#include "pvr/PVRManager.h"
#include "pvr/addons/PVRClients.h"
+#include "pvr/channels/PVRChannelGroupsContainer.h"
#include "pvr/dialogs/GUIDialogPVRGuideSearch.h"
#include "pvr/epg/EpgContainer.h"
#include "pvr/epg/EpgSearchFilter.h"
@@ -55,7 +56,25 @@ namespace
void AsyncSearchAction::Run()
{
- CServiceBroker::GetPVRManager().EpgContainer().GetEPGSearch(*m_items, *m_filter);
+ std::vector<std::shared_ptr<CPVREpgInfoTag>> results = CServiceBroker::GetPVRManager().EpgContainer().GetAllTags();
+ for (auto it = results.begin(); it != results.end();)
+ {
+ it = results.erase(std::remove_if(results.begin(),
+ results.end(),
+ [this](const std::shared_ptr<CPVREpgInfoTag>& entry)
+ {
+ return !m_filter->FilterEntry(entry);
+ }),
+ results.end());
+ }
+
+ if (m_filter->ShouldRemoveDuplicates())
+ m_filter->RemoveDuplicates(results);
+
+ for (const auto& tag : results)
+ {
+ m_items->Add(std::make_shared<CFileItem>(tag));
+ }
}
} // unnamed namespace
@@ -65,6 +84,10 @@ CGUIWindowPVRSearchBase::CGUIWindowPVRSearchBase(bool bRadio, int id, const std:
{
}
+CGUIWindowPVRSearchBase::~CGUIWindowPVRSearchBase()
+{
+}
+
void CGUIWindowPVRSearchBase::GetContextButtons(int itemNumber, CContextButtons &buttons)
{
if (itemNumber < 0 || itemNumber >= m_vecItems->Size())
@@ -96,7 +119,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());
}
diff --git a/xbmc/pvr/windows/GUIWindowPVRSearch.h b/xbmc/pvr/windows/GUIWindowPVRSearch.h
index d287941f11..8bca6bd18c 100644
--- a/xbmc/pvr/windows/GUIWindowPVRSearch.h
+++ b/xbmc/pvr/windows/GUIWindowPVRSearch.h
@@ -20,7 +20,7 @@ namespace PVR
{
public:
CGUIWindowPVRSearchBase(bool bRadio, int id, const std::string &xmlFile);
- ~CGUIWindowPVRSearchBase() override = default;
+ ~CGUIWindowPVRSearchBase() override;
bool OnMessage(CGUIMessage& message) override;
void GetContextButtons(int itemNumber, CContextButtons &buttons) override;
diff --git a/xbmc/pvr/windows/GUIWindowPVRTimerRules.cpp b/xbmc/pvr/windows/GUIWindowPVRTimerRules.cpp
index eea4ca1662..c494d9e833 100644
--- a/xbmc/pvr/windows/GUIWindowPVRTimerRules.cpp
+++ b/xbmc/pvr/windows/GUIWindowPVRTimerRules.cpp
@@ -11,7 +11,7 @@
#include "FileItem.h"
#include "utils/URIUtils.h"
-#include "pvr/timers/PVRTimers.h"
+#include "pvr/timers/PVRTimersPath.h"
using namespace PVR;
diff --git a/xbmc/pvr/windows/GUIWindowPVRTimers.cpp b/xbmc/pvr/windows/GUIWindowPVRTimers.cpp
index 29e82f5e1f..01d60a2278 100644
--- a/xbmc/pvr/windows/GUIWindowPVRTimers.cpp
+++ b/xbmc/pvr/windows/GUIWindowPVRTimers.cpp
@@ -11,7 +11,7 @@
#include "FileItem.h"
#include "utils/URIUtils.h"
-#include "pvr/timers/PVRTimers.h"
+#include "pvr/timers/PVRTimersPath.h"
using namespace PVR;
diff --git a/xbmc/pvr/windows/GUIWindowPVRTimersBase.cpp b/xbmc/pvr/windows/GUIWindowPVRTimersBase.cpp
index 80bf4e0e9a..5f7784c249 100644
--- a/xbmc/pvr/windows/GUIWindowPVRTimersBase.cpp
+++ b/xbmc/pvr/windows/GUIWindowPVRTimersBase.cpp
@@ -22,7 +22,8 @@
#include "pvr/PVRGUIActions.h"
#include "pvr/PVRManager.h"
#include "pvr/addons/PVRClients.h"
-#include "pvr/timers/PVRTimers.h"
+#include "pvr/timers/PVRTimerInfoTag.h"
+#include "pvr/timers/PVRTimersPath.h"
using namespace PVR;
using namespace KODI::MESSAGING;
diff --git a/xbmc/utils/Observer.h b/xbmc/utils/Observer.h
index 4c177a26fe..2d9de72ac4 100644
--- a/xbmc/utils/Observer.h
+++ b/xbmc/utils/Observer.h
@@ -24,6 +24,7 @@ typedef enum
ObservableMessageEpgContainer,
ObservableMessageEpgActiveItem,
ObservableMessageEpgItemUpdate,
+ ObservableMessageEpgUpdatePending,
ObservableMessageChannelGroup,
ObservableMessageChannelGroupReset,
ObservableMessageTimers,
diff --git a/xbmc/windowing/X11/GLContextEGL.cpp b/xbmc/windowing/X11/GLContextEGL.cpp
index 36ae4c0fb9..227ba4b16d 100644
--- a/xbmc/windowing/X11/GLContextEGL.cpp
+++ b/xbmc/windowing/X11/GLContextEGL.cpp
@@ -424,7 +424,7 @@ void CGLContextEGL::SwapBuffers()
eglSwapBuffers(m_eglDisplay, m_eglSurface);
clock_gettime(CLOCK_MONOTONIC, &nowTs);
- now = nowTs.tv_sec * 1000000000 + nowTs.tv_nsec;
+ now = static_cast<uint64_t>(nowTs.tv_sec) * 1000000000ULL + nowTs.tv_nsec;
eglGetSyncValuesCHROMIUM(m_eglDisplay, m_eglSurface, &ust2, &msc2, &sbc2);
@@ -499,7 +499,7 @@ uint64_t CGLContextEGL::GetVblankTiming(uint64_t &msc, uint64_t &interval)
struct timespec nowTs;
uint64_t now;
clock_gettime(CLOCK_MONOTONIC, &nowTs);
- now = nowTs.tv_sec * 1000000000 + nowTs.tv_nsec;
+ now = static_cast<uint64_t>(nowTs.tv_sec) * 1000000000ULL + nowTs.tv_nsec;
now /= 1000;
CSingleLock lock(m_syncLock);
diff --git a/xbmc/windowing/android/WinSystemAndroid.cpp b/xbmc/windowing/android/WinSystemAndroid.cpp
index def4ca4cdd..9c7807321b 100644
--- a/xbmc/windowing/android/WinSystemAndroid.cpp
+++ b/xbmc/windowing/android/WinSystemAndroid.cpp
@@ -201,29 +201,37 @@ void CWinSystemAndroid::OnTimeout()
SetHDMIState(true);
}
-void CWinSystemAndroid::SetHDMIState(bool connected, uint32_t timeoutMs)
+void CWinSystemAndroid::SetHDMIState(bool connected)
{
CSingleLock lock(m_resourceSection);
- if (connected && m_dispResetState == RESET_WAITEVENT)
+ CLog::Log(LOGDEBUG, "CWinSystemAndroid::SetHDMIState: connected: %d, dispResetState: %d", static_cast<int>(connected), m_dispResetState);
+ if (connected && m_dispResetState != RESET_NOTWAITING)
{
for (auto resource : m_resources)
resource->OnResetDisplay();
+ m_dispResetState = RESET_NOTWAITING;
+ m_dispResetTimer->Stop();
}
else if (!connected)
{
+ if (m_dispResetState == RESET_WAITTIMER)
+ {
+ //HDMI_AUDIOPLUG arrived, use this
+ m_dispResetTimer->Stop();
+ m_dispResetState = RESET_WAITEVENT;
+ return;
+ }
+ else if (m_dispResetState != RESET_NOTWAITING)
+ return;
+
int delay = CServiceBroker::GetSettingsComponent()->GetSettings()->GetInt("videoscreen.delayrefreshchange") * 100;
- if (timeoutMs > delay)
- delay = timeoutMs;
+ if (delay < 2000)
+ delay = 2000;
- if (delay > 0)
- {
- m_dispResetState = RESET_WAITTIMER;
- m_dispResetTimer->Stop();
- m_dispResetTimer->Start(delay);
- }
- else
- m_dispResetState = RESET_WAITEVENT;
+ m_dispResetState = RESET_WAITTIMER;
+ m_dispResetTimer->Stop();
+ m_dispResetTimer->Start(delay);
for (auto resource : m_resources)
resource->OnLostDisplay();
diff --git a/xbmc/windowing/android/WinSystemAndroid.h b/xbmc/windowing/android/WinSystemAndroid.h
index fec003c926..04a8f4a099 100644
--- a/xbmc/windowing/android/WinSystemAndroid.h
+++ b/xbmc/windowing/android/WinSystemAndroid.h
@@ -34,7 +34,7 @@ public:
bool DestroyWindow() override;
void UpdateResolutions() override;
- void SetHDMIState(bool connected, uint32_t timeoutMs = 0);
+ void SetHDMIState(bool connected);
bool HasCursor() override { return false; };