diff options
129 files changed, 852 insertions, 586 deletions
diff --git a/addons/resource.language.en_gb/resources/strings.po b/addons/resource.language.en_gb/resources/strings.po index 96fa299ac1..46d1d6174f 100644 --- a/addons/resource.language.en_gb/resources/strings.po +++ b/addons/resource.language.en_gb/resources/strings.po @@ -3704,6 +3704,7 @@ msgid "Any channel" msgstr "" #. Label of "Start any time" radio button in PVR timer settings dialog +#: addons/skin.estuary/xml/DialogPVRGuideSearch.xml #: xbmc/pvr/dialogs/GUIDialogPVRTimerSettings.cpp msgctxt "#810" msgid "Start any time" @@ -3750,6 +3751,7 @@ msgid "Record only new episodes" msgstr "" #. Label of "End any time" radio button in PVR timer settings dialog +#: addons/skin.estuary/xml/DialogPVRGuideSearch.xml #: xbmc/pvr/dialogs/GUIDialogPVRTimerSettings.cpp msgctxt "#817" msgid "End any time" @@ -11853,7 +11855,19 @@ msgctxt "#19354" msgid "Play only this programme" msgstr "" -#empty strings from id 19355 to 19498 +#. Label of a context menu entry to create a copy of an EPG saved saerch +#: xbmc/pvr/PVRContextMenus.cpp +msgctxt "#19355" +msgid "Duplicate" +msgstr "" + +#. Initial title of a duplicated EPG saved search. +#: xbmc/pvr/PVRContextMenus.cpp +msgctxt "#19356" +msgid "Copy of '{0:s}'" +msgstr "" + +#empty strings from id 19357 to 19498 #. label for epg genre value #: xbmc/pvr/epg/Epg.cpp diff --git a/addons/skin.estuary/media/flags/aspectratio/1.00.png b/addons/skin.estuary/media/flags/aspectratio/1.00.png Binary files differdeleted file mode 100644 index eb41c15f7f..0000000000 --- a/addons/skin.estuary/media/flags/aspectratio/1.00.png +++ /dev/null diff --git a/addons/skin.estuary/media/flags/aspectratio/1.19.png b/addons/skin.estuary/media/flags/aspectratio/1.19.png Binary files differdeleted file mode 100644 index 80289ae466..0000000000 --- a/addons/skin.estuary/media/flags/aspectratio/1.19.png +++ /dev/null diff --git a/addons/skin.estuary/media/flags/aspectratio/1.33.png b/addons/skin.estuary/media/flags/aspectratio/1.33.png Binary files differdeleted file mode 100644 index 43e079495a..0000000000 --- a/addons/skin.estuary/media/flags/aspectratio/1.33.png +++ /dev/null diff --git a/addons/skin.estuary/media/flags/aspectratio/1.37.png b/addons/skin.estuary/media/flags/aspectratio/1.37.png Binary files differdeleted file mode 100644 index e86c6f7a1d..0000000000 --- a/addons/skin.estuary/media/flags/aspectratio/1.37.png +++ /dev/null diff --git a/addons/skin.estuary/media/flags/aspectratio/1.66.png b/addons/skin.estuary/media/flags/aspectratio/1.66.png Binary files differdeleted file mode 100644 index 80ca726bcc..0000000000 --- a/addons/skin.estuary/media/flags/aspectratio/1.66.png +++ /dev/null diff --git a/addons/skin.estuary/media/flags/aspectratio/1.78.png b/addons/skin.estuary/media/flags/aspectratio/1.78.png Binary files differdeleted file mode 100644 index 01d70b832d..0000000000 --- a/addons/skin.estuary/media/flags/aspectratio/1.78.png +++ /dev/null diff --git a/addons/skin.estuary/media/flags/aspectratio/1.85.png b/addons/skin.estuary/media/flags/aspectratio/1.85.png Binary files differdeleted file mode 100644 index 479804fde6..0000000000 --- a/addons/skin.estuary/media/flags/aspectratio/1.85.png +++ /dev/null diff --git a/addons/skin.estuary/media/flags/aspectratio/2.00.png b/addons/skin.estuary/media/flags/aspectratio/2.00.png Binary files differdeleted file mode 100644 index cd8ff2569f..0000000000 --- a/addons/skin.estuary/media/flags/aspectratio/2.00.png +++ /dev/null diff --git a/addons/skin.estuary/media/flags/aspectratio/2.20.png b/addons/skin.estuary/media/flags/aspectratio/2.20.png Binary files differdeleted file mode 100644 index d0cebe276e..0000000000 --- a/addons/skin.estuary/media/flags/aspectratio/2.20.png +++ /dev/null diff --git a/addons/skin.estuary/media/flags/aspectratio/2.35.png b/addons/skin.estuary/media/flags/aspectratio/2.35.png Binary files differdeleted file mode 100644 index cacb088692..0000000000 --- a/addons/skin.estuary/media/flags/aspectratio/2.35.png +++ /dev/null diff --git a/addons/skin.estuary/media/flags/aspectratio/2.40.png b/addons/skin.estuary/media/flags/aspectratio/2.40.png Binary files differdeleted file mode 100644 index 35aff17350..0000000000 --- a/addons/skin.estuary/media/flags/aspectratio/2.40.png +++ /dev/null diff --git a/addons/skin.estuary/media/flags/aspectratio/2.55.png b/addons/skin.estuary/media/flags/aspectratio/2.55.png Binary files differdeleted file mode 100644 index a592e04fbe..0000000000 --- a/addons/skin.estuary/media/flags/aspectratio/2.55.png +++ /dev/null diff --git a/addons/skin.estuary/media/flags/aspectratio/2.76.png b/addons/skin.estuary/media/flags/aspectratio/2.76.png Binary files differdeleted file mode 100644 index 051e671b6a..0000000000 --- a/addons/skin.estuary/media/flags/aspectratio/2.76.png +++ /dev/null diff --git a/addons/skin.estuary/media/flags/audiochannel/0.png b/addons/skin.estuary/media/flags/audiochannel/0.png Binary files differdeleted file mode 100644 index a5be90821a..0000000000 --- a/addons/skin.estuary/media/flags/audiochannel/0.png +++ /dev/null diff --git a/addons/skin.estuary/media/flags/audiochannel/1.png b/addons/skin.estuary/media/flags/audiochannel/1.png Binary files differdeleted file mode 100644 index 87f541c99c..0000000000 --- a/addons/skin.estuary/media/flags/audiochannel/1.png +++ /dev/null diff --git a/addons/skin.estuary/media/flags/audiochannel/10.png b/addons/skin.estuary/media/flags/audiochannel/10.png Binary files differdeleted file mode 100644 index 49ed3ec3ab..0000000000 --- a/addons/skin.estuary/media/flags/audiochannel/10.png +++ /dev/null diff --git a/addons/skin.estuary/media/flags/audiochannel/2.png b/addons/skin.estuary/media/flags/audiochannel/2.png Binary files differdeleted file mode 100644 index c7102b6c22..0000000000 --- a/addons/skin.estuary/media/flags/audiochannel/2.png +++ /dev/null diff --git a/addons/skin.estuary/media/flags/audiochannel/3.png b/addons/skin.estuary/media/flags/audiochannel/3.png Binary files differdeleted file mode 100644 index 5f9b0cca6d..0000000000 --- a/addons/skin.estuary/media/flags/audiochannel/3.png +++ /dev/null diff --git a/addons/skin.estuary/media/flags/audiochannel/4.png b/addons/skin.estuary/media/flags/audiochannel/4.png Binary files differdeleted file mode 100644 index 67c04c0e03..0000000000 --- a/addons/skin.estuary/media/flags/audiochannel/4.png +++ /dev/null diff --git a/addons/skin.estuary/media/flags/audiochannel/5.png b/addons/skin.estuary/media/flags/audiochannel/5.png Binary files differdeleted file mode 100644 index a7f5f895ac..0000000000 --- a/addons/skin.estuary/media/flags/audiochannel/5.png +++ /dev/null diff --git a/addons/skin.estuary/media/flags/audiochannel/6.png b/addons/skin.estuary/media/flags/audiochannel/6.png Binary files differdeleted file mode 100644 index d35e28d8e4..0000000000 --- a/addons/skin.estuary/media/flags/audiochannel/6.png +++ /dev/null diff --git a/addons/skin.estuary/media/flags/audiochannel/7.png b/addons/skin.estuary/media/flags/audiochannel/7.png Binary files differdeleted file mode 100644 index e026a26753..0000000000 --- a/addons/skin.estuary/media/flags/audiochannel/7.png +++ /dev/null diff --git a/addons/skin.estuary/media/flags/audiochannel/8.png b/addons/skin.estuary/media/flags/audiochannel/8.png Binary files differdeleted file mode 100644 index b32fc36ab4..0000000000 --- a/addons/skin.estuary/media/flags/audiochannel/8.png +++ /dev/null diff --git a/addons/skin.estuary/media/flags/audiocodec/aac.png b/addons/skin.estuary/media/flags/audiocodec/aac.png Binary files differdeleted file mode 100644 index 55e81409b7..0000000000 --- a/addons/skin.estuary/media/flags/audiocodec/aac.png +++ /dev/null diff --git a/addons/skin.estuary/media/flags/audiocodec/aac_latm.png b/addons/skin.estuary/media/flags/audiocodec/aac_latm.png Binary files differdeleted file mode 100644 index 55e81409b7..0000000000 --- a/addons/skin.estuary/media/flags/audiocodec/aac_latm.png +++ /dev/null diff --git a/addons/skin.estuary/media/flags/audiocodec/ac3.png b/addons/skin.estuary/media/flags/audiocodec/ac3.png Binary files differdeleted file mode 100644 index d01a87739e..0000000000 --- a/addons/skin.estuary/media/flags/audiocodec/ac3.png +++ /dev/null diff --git a/addons/skin.estuary/media/flags/audiocodec/aif.png b/addons/skin.estuary/media/flags/audiocodec/aif.png Binary files differdeleted file mode 100644 index ce4677858b..0000000000 --- a/addons/skin.estuary/media/flags/audiocodec/aif.png +++ /dev/null diff --git a/addons/skin.estuary/media/flags/audiocodec/aifc.png b/addons/skin.estuary/media/flags/audiocodec/aifc.png Binary files differdeleted file mode 100644 index ed9a26c6bb..0000000000 --- a/addons/skin.estuary/media/flags/audiocodec/aifc.png +++ /dev/null diff --git a/addons/skin.estuary/media/flags/audiocodec/aiff.png b/addons/skin.estuary/media/flags/audiocodec/aiff.png Binary files differdeleted file mode 100644 index ce4677858b..0000000000 --- a/addons/skin.estuary/media/flags/audiocodec/aiff.png +++ /dev/null diff --git a/addons/skin.estuary/media/flags/audiocodec/alac.png b/addons/skin.estuary/media/flags/audiocodec/alac.png Binary files differdeleted file mode 100644 index a49527cf6a..0000000000 --- a/addons/skin.estuary/media/flags/audiocodec/alac.png +++ /dev/null diff --git a/addons/skin.estuary/media/flags/audiocodec/ape.png b/addons/skin.estuary/media/flags/audiocodec/ape.png Binary files differdeleted file mode 100644 index 94e01abf20..0000000000 --- a/addons/skin.estuary/media/flags/audiocodec/ape.png +++ /dev/null diff --git a/addons/skin.estuary/media/flags/audiocodec/avc.png b/addons/skin.estuary/media/flags/audiocodec/avc.png Binary files differdeleted file mode 100644 index 91aa179870..0000000000 --- a/addons/skin.estuary/media/flags/audiocodec/avc.png +++ /dev/null diff --git a/addons/skin.estuary/media/flags/audiocodec/cdda.png b/addons/skin.estuary/media/flags/audiocodec/cdda.png Binary files differdeleted file mode 100644 index 3f257dd567..0000000000 --- a/addons/skin.estuary/media/flags/audiocodec/cdda.png +++ /dev/null diff --git a/addons/skin.estuary/media/flags/audiocodec/dca.png b/addons/skin.estuary/media/flags/audiocodec/dca.png Binary files differdeleted file mode 100644 index 1dc52ec67f..0000000000 --- a/addons/skin.estuary/media/flags/audiocodec/dca.png +++ /dev/null diff --git a/addons/skin.estuary/media/flags/audiocodec/dolbydigital.png b/addons/skin.estuary/media/flags/audiocodec/dolbydigital.png Binary files differdeleted file mode 100644 index d01a87739e..0000000000 --- a/addons/skin.estuary/media/flags/audiocodec/dolbydigital.png +++ /dev/null diff --git a/addons/skin.estuary/media/flags/audiocodec/dts.png b/addons/skin.estuary/media/flags/audiocodec/dts.png Binary files differdeleted file mode 100644 index 1dc52ec67f..0000000000 --- a/addons/skin.estuary/media/flags/audiocodec/dts.png +++ /dev/null diff --git a/addons/skin.estuary/media/flags/audiocodec/dtshd_hra.png b/addons/skin.estuary/media/flags/audiocodec/dtshd_hra.png Binary files differdeleted file mode 100644 index 53ffb9002b..0000000000 --- a/addons/skin.estuary/media/flags/audiocodec/dtshd_hra.png +++ /dev/null diff --git a/addons/skin.estuary/media/flags/audiocodec/dtshd_ma.png b/addons/skin.estuary/media/flags/audiocodec/dtshd_ma.png Binary files differdeleted file mode 100644 index f20256e591..0000000000 --- a/addons/skin.estuary/media/flags/audiocodec/dtshd_ma.png +++ /dev/null diff --git a/addons/skin.estuary/media/flags/audiocodec/dtsma.png b/addons/skin.estuary/media/flags/audiocodec/dtsma.png Binary files differdeleted file mode 100644 index f20256e591..0000000000 --- a/addons/skin.estuary/media/flags/audiocodec/dtsma.png +++ /dev/null diff --git a/addons/skin.estuary/media/flags/audiocodec/eac3.png b/addons/skin.estuary/media/flags/audiocodec/eac3.png Binary files differdeleted file mode 100644 index d01a87739e..0000000000 --- a/addons/skin.estuary/media/flags/audiocodec/eac3.png +++ /dev/null diff --git a/addons/skin.estuary/media/flags/audiocodec/flac.png b/addons/skin.estuary/media/flags/audiocodec/flac.png Binary files differdeleted file mode 100644 index f173541ebd..0000000000 --- a/addons/skin.estuary/media/flags/audiocodec/flac.png +++ /dev/null diff --git a/addons/skin.estuary/media/flags/audiocodec/mp1.png b/addons/skin.estuary/media/flags/audiocodec/mp1.png Binary files differdeleted file mode 100644 index d3065f1b95..0000000000 --- a/addons/skin.estuary/media/flags/audiocodec/mp1.png +++ /dev/null diff --git a/addons/skin.estuary/media/flags/audiocodec/mp2.png b/addons/skin.estuary/media/flags/audiocodec/mp2.png Binary files differdeleted file mode 100644 index ed4e21eefe..0000000000 --- a/addons/skin.estuary/media/flags/audiocodec/mp2.png +++ /dev/null diff --git a/addons/skin.estuary/media/flags/audiocodec/mp3.png b/addons/skin.estuary/media/flags/audiocodec/mp3.png Binary files differdeleted file mode 100644 index 258d161f5a..0000000000 --- a/addons/skin.estuary/media/flags/audiocodec/mp3.png +++ /dev/null diff --git a/addons/skin.estuary/media/flags/audiocodec/mp3float.png b/addons/skin.estuary/media/flags/audiocodec/mp3float.png Binary files differdeleted file mode 100644 index 258d161f5a..0000000000 --- a/addons/skin.estuary/media/flags/audiocodec/mp3float.png +++ /dev/null diff --git a/addons/skin.estuary/media/flags/audiocodec/ogg.png b/addons/skin.estuary/media/flags/audiocodec/ogg.png Binary files differdeleted file mode 100644 index 208200a63e..0000000000 --- a/addons/skin.estuary/media/flags/audiocodec/ogg.png +++ /dev/null diff --git a/addons/skin.estuary/media/flags/audiocodec/opus.png b/addons/skin.estuary/media/flags/audiocodec/opus.png Binary files differdeleted file mode 100644 index df856a6d57..0000000000 --- a/addons/skin.estuary/media/flags/audiocodec/opus.png +++ /dev/null diff --git a/addons/skin.estuary/media/flags/audiocodec/pcm.png b/addons/skin.estuary/media/flags/audiocodec/pcm.png Binary files differdeleted file mode 100644 index 0c7a5bdeee..0000000000 --- a/addons/skin.estuary/media/flags/audiocodec/pcm.png +++ /dev/null diff --git a/addons/skin.estuary/media/flags/audiocodec/pcm_bluray.png b/addons/skin.estuary/media/flags/audiocodec/pcm_bluray.png Binary files differdeleted file mode 100644 index 30b4f8b138..0000000000 --- a/addons/skin.estuary/media/flags/audiocodec/pcm_bluray.png +++ /dev/null diff --git a/addons/skin.estuary/media/flags/audiocodec/pcm_s16le.png b/addons/skin.estuary/media/flags/audiocodec/pcm_s16le.png Binary files differdeleted file mode 100644 index dc514806e3..0000000000 --- a/addons/skin.estuary/media/flags/audiocodec/pcm_s16le.png +++ /dev/null diff --git a/addons/skin.estuary/media/flags/audiocodec/pcm_s24le.png b/addons/skin.estuary/media/flags/audiocodec/pcm_s24le.png Binary files differdeleted file mode 100644 index 81ceacc06d..0000000000 --- a/addons/skin.estuary/media/flags/audiocodec/pcm_s24le.png +++ /dev/null diff --git a/addons/skin.estuary/media/flags/audiocodec/truehd.png b/addons/skin.estuary/media/flags/audiocodec/truehd.png Binary files differdeleted file mode 100644 index 4bcf8c1fda..0000000000 --- a/addons/skin.estuary/media/flags/audiocodec/truehd.png +++ /dev/null diff --git a/addons/skin.estuary/media/flags/audiocodec/vorbis.png b/addons/skin.estuary/media/flags/audiocodec/vorbis.png Binary files differdeleted file mode 100644 index e7ec2c5361..0000000000 --- a/addons/skin.estuary/media/flags/audiocodec/vorbis.png +++ /dev/null diff --git a/addons/skin.estuary/media/flags/audiocodec/wav.png b/addons/skin.estuary/media/flags/audiocodec/wav.png Binary files differdeleted file mode 100644 index 76cd02d3fc..0000000000 --- a/addons/skin.estuary/media/flags/audiocodec/wav.png +++ /dev/null diff --git a/addons/skin.estuary/media/flags/audiocodec/wavpack.png b/addons/skin.estuary/media/flags/audiocodec/wavpack.png Binary files differdeleted file mode 100644 index 6501af9942..0000000000 --- a/addons/skin.estuary/media/flags/audiocodec/wavpack.png +++ /dev/null diff --git a/addons/skin.estuary/media/flags/audiocodec/wma.png b/addons/skin.estuary/media/flags/audiocodec/wma.png Binary files differdeleted file mode 100644 index 20093c15d5..0000000000 --- a/addons/skin.estuary/media/flags/audiocodec/wma.png +++ /dev/null diff --git a/addons/skin.estuary/media/flags/audiocodec/wmapro.png b/addons/skin.estuary/media/flags/audiocodec/wmapro.png Binary files differdeleted file mode 100644 index 20093c15d5..0000000000 --- a/addons/skin.estuary/media/flags/audiocodec/wmapro.png +++ /dev/null diff --git a/addons/skin.estuary/media/flags/audiocodec/wmav2.png b/addons/skin.estuary/media/flags/audiocodec/wmav2.png Binary files differdeleted file mode 100644 index 20093c15d5..0000000000 --- a/addons/skin.estuary/media/flags/audiocodec/wmav2.png +++ /dev/null diff --git a/addons/skin.estuary/media/flags/rds/rds.png b/addons/skin.estuary/media/flags/rds/rds.png Binary files differdeleted file mode 100644 index e5de4ccfcf..0000000000 --- a/addons/skin.estuary/media/flags/rds/rds.png +++ /dev/null diff --git a/addons/skin.estuary/media/flags/videocodec/av1.png b/addons/skin.estuary/media/flags/videocodec/av1.png Binary files differdeleted file mode 100644 index f594b9ea9c..0000000000 --- a/addons/skin.estuary/media/flags/videocodec/av1.png +++ /dev/null diff --git a/addons/skin.estuary/media/flags/videocodec/avc1.png b/addons/skin.estuary/media/flags/videocodec/avc1.png Binary files differdeleted file mode 100644 index 78da5d8936..0000000000 --- a/addons/skin.estuary/media/flags/videocodec/avc1.png +++ /dev/null diff --git a/addons/skin.estuary/media/flags/videocodec/bluray.png b/addons/skin.estuary/media/flags/videocodec/bluray.png Binary files differdeleted file mode 100644 index b8fe922c6d..0000000000 --- a/addons/skin.estuary/media/flags/videocodec/bluray.png +++ /dev/null diff --git a/addons/skin.estuary/media/flags/videocodec/div3.png b/addons/skin.estuary/media/flags/videocodec/div3.png Binary files differdeleted file mode 100644 index 65a9a6517c..0000000000 --- a/addons/skin.estuary/media/flags/videocodec/div3.png +++ /dev/null diff --git a/addons/skin.estuary/media/flags/videocodec/divx.png b/addons/skin.estuary/media/flags/videocodec/divx.png Binary files differdeleted file mode 100644 index 65a9a6517c..0000000000 --- a/addons/skin.estuary/media/flags/videocodec/divx.png +++ /dev/null diff --git a/addons/skin.estuary/media/flags/videocodec/dvd.png b/addons/skin.estuary/media/flags/videocodec/dvd.png Binary files differdeleted file mode 100644 index 9e9bd97ab0..0000000000 --- a/addons/skin.estuary/media/flags/videocodec/dvd.png +++ /dev/null diff --git a/addons/skin.estuary/media/flags/videocodec/dx50.png b/addons/skin.estuary/media/flags/videocodec/dx50.png Binary files differdeleted file mode 100644 index 65a9a6517c..0000000000 --- a/addons/skin.estuary/media/flags/videocodec/dx50.png +++ /dev/null diff --git a/addons/skin.estuary/media/flags/videocodec/flv.png b/addons/skin.estuary/media/flags/videocodec/flv.png Binary files differdeleted file mode 100644 index 8b1b5775d5..0000000000 --- a/addons/skin.estuary/media/flags/videocodec/flv.png +++ /dev/null diff --git a/addons/skin.estuary/media/flags/videocodec/h264.png b/addons/skin.estuary/media/flags/videocodec/h264.png Binary files differdeleted file mode 100644 index 64cfa04ec9..0000000000 --- a/addons/skin.estuary/media/flags/videocodec/h264.png +++ /dev/null diff --git a/addons/skin.estuary/media/flags/videocodec/hddvd.png b/addons/skin.estuary/media/flags/videocodec/hddvd.png Binary files differdeleted file mode 100644 index 4a170a91b6..0000000000 --- a/addons/skin.estuary/media/flags/videocodec/hddvd.png +++ /dev/null diff --git a/addons/skin.estuary/media/flags/videocodec/hdmv.png b/addons/skin.estuary/media/flags/videocodec/hdmv.png Binary files differdeleted file mode 100644 index b8fe922c6d..0000000000 --- a/addons/skin.estuary/media/flags/videocodec/hdmv.png +++ /dev/null diff --git a/addons/skin.estuary/media/flags/videocodec/hev1.png b/addons/skin.estuary/media/flags/videocodec/hev1.png Binary files differdeleted file mode 100644 index 1e1d3c186b..0000000000 --- a/addons/skin.estuary/media/flags/videocodec/hev1.png +++ /dev/null diff --git a/addons/skin.estuary/media/flags/videocodec/hevc.png b/addons/skin.estuary/media/flags/videocodec/hevc.png Binary files differdeleted file mode 100644 index 1e1d3c186b..0000000000 --- a/addons/skin.estuary/media/flags/videocodec/hevc.png +++ /dev/null diff --git a/addons/skin.estuary/media/flags/videocodec/hvc1.png b/addons/skin.estuary/media/flags/videocodec/hvc1.png Binary files differdeleted file mode 100644 index 1e1d3c186b..0000000000 --- a/addons/skin.estuary/media/flags/videocodec/hvc1.png +++ /dev/null diff --git a/addons/skin.estuary/media/flags/videocodec/mp4v.png b/addons/skin.estuary/media/flags/videocodec/mp4v.png Binary files differdeleted file mode 100644 index da9d967bb8..0000000000 --- a/addons/skin.estuary/media/flags/videocodec/mp4v.png +++ /dev/null diff --git a/addons/skin.estuary/media/flags/videocodec/mpeg1.png b/addons/skin.estuary/media/flags/videocodec/mpeg1.png Binary files differdeleted file mode 100644 index 8b210cf2d1..0000000000 --- a/addons/skin.estuary/media/flags/videocodec/mpeg1.png +++ /dev/null diff --git a/addons/skin.estuary/media/flags/videocodec/mpeg1video.png b/addons/skin.estuary/media/flags/videocodec/mpeg1video.png Binary files differdeleted file mode 100644 index 8b210cf2d1..0000000000 --- a/addons/skin.estuary/media/flags/videocodec/mpeg1video.png +++ /dev/null diff --git a/addons/skin.estuary/media/flags/videocodec/mpeg2.png b/addons/skin.estuary/media/flags/videocodec/mpeg2.png Binary files differdeleted file mode 100644 index f46483b765..0000000000 --- a/addons/skin.estuary/media/flags/videocodec/mpeg2.png +++ /dev/null diff --git a/addons/skin.estuary/media/flags/videocodec/mpeg2video.png b/addons/skin.estuary/media/flags/videocodec/mpeg2video.png Binary files differdeleted file mode 100644 index f46483b765..0000000000 --- a/addons/skin.estuary/media/flags/videocodec/mpeg2video.png +++ /dev/null diff --git a/addons/skin.estuary/media/flags/videocodec/mpeg4.png b/addons/skin.estuary/media/flags/videocodec/mpeg4.png Binary files differdeleted file mode 100644 index da9d967bb8..0000000000 --- a/addons/skin.estuary/media/flags/videocodec/mpeg4.png +++ /dev/null diff --git a/addons/skin.estuary/media/flags/videocodec/theora.png b/addons/skin.estuary/media/flags/videocodec/theora.png Binary files differdeleted file mode 100644 index 8f1af4bb94..0000000000 --- a/addons/skin.estuary/media/flags/videocodec/theora.png +++ /dev/null diff --git a/addons/skin.estuary/media/flags/videocodec/tv.png b/addons/skin.estuary/media/flags/videocodec/tv.png Binary files differdeleted file mode 100644 index b7cb357442..0000000000 --- a/addons/skin.estuary/media/flags/videocodec/tv.png +++ /dev/null diff --git a/addons/skin.estuary/media/flags/videocodec/vc-1.png b/addons/skin.estuary/media/flags/videocodec/vc-1.png Binary files differdeleted file mode 100644 index 843497f6a9..0000000000 --- a/addons/skin.estuary/media/flags/videocodec/vc-1.png +++ /dev/null diff --git a/addons/skin.estuary/media/flags/videocodec/vc1.png b/addons/skin.estuary/media/flags/videocodec/vc1.png Binary files differdeleted file mode 100644 index 843497f6a9..0000000000 --- a/addons/skin.estuary/media/flags/videocodec/vc1.png +++ /dev/null diff --git a/addons/skin.estuary/media/flags/videocodec/vhs.png b/addons/skin.estuary/media/flags/videocodec/vhs.png Binary files differdeleted file mode 100644 index a1a4ff3198..0000000000 --- a/addons/skin.estuary/media/flags/videocodec/vhs.png +++ /dev/null diff --git a/addons/skin.estuary/media/flags/videocodec/vp8.png b/addons/skin.estuary/media/flags/videocodec/vp8.png Binary files differdeleted file mode 100644 index d9ad357901..0000000000 --- a/addons/skin.estuary/media/flags/videocodec/vp8.png +++ /dev/null diff --git a/addons/skin.estuary/media/flags/videocodec/vp9.png b/addons/skin.estuary/media/flags/videocodec/vp9.png Binary files differdeleted file mode 100644 index c09a28cb10..0000000000 --- a/addons/skin.estuary/media/flags/videocodec/vp9.png +++ /dev/null diff --git a/addons/skin.estuary/media/flags/videocodec/wmv.png b/addons/skin.estuary/media/flags/videocodec/wmv.png Binary files differdeleted file mode 100644 index 34a7cedf3b..0000000000 --- a/addons/skin.estuary/media/flags/videocodec/wmv.png +++ /dev/null diff --git a/addons/skin.estuary/media/flags/videocodec/wmv3.png b/addons/skin.estuary/media/flags/videocodec/wmv3.png Binary files differdeleted file mode 100644 index 34a7cedf3b..0000000000 --- a/addons/skin.estuary/media/flags/videocodec/wmv3.png +++ /dev/null diff --git a/addons/skin.estuary/media/flags/videocodec/wvc1.png b/addons/skin.estuary/media/flags/videocodec/wvc1.png Binary files differdeleted file mode 100644 index 843497f6a9..0000000000 --- a/addons/skin.estuary/media/flags/videocodec/wvc1.png +++ /dev/null diff --git a/addons/skin.estuary/media/flags/videocodec/xvid.png b/addons/skin.estuary/media/flags/videocodec/xvid.png Binary files differdeleted file mode 100644 index b835bf6873..0000000000 --- a/addons/skin.estuary/media/flags/videocodec/xvid.png +++ /dev/null diff --git a/addons/skin.estuary/media/flags/videohdr/dolbyvision.png b/addons/skin.estuary/media/flags/videohdr/dolbyvision.png Binary files differdeleted file mode 100644 index 5875eb80e7..0000000000 --- a/addons/skin.estuary/media/flags/videohdr/dolbyvision.png +++ /dev/null diff --git a/addons/skin.estuary/media/flags/videohdr/hdr10.png b/addons/skin.estuary/media/flags/videohdr/hdr10.png Binary files differdeleted file mode 100644 index e4b671fe12..0000000000 --- a/addons/skin.estuary/media/flags/videohdr/hdr10.png +++ /dev/null diff --git a/addons/skin.estuary/media/flags/videohdr/hlg.png b/addons/skin.estuary/media/flags/videohdr/hlg.png Binary files differdeleted file mode 100644 index a8bc078d70..0000000000 --- a/addons/skin.estuary/media/flags/videohdr/hlg.png +++ /dev/null diff --git a/addons/skin.estuary/media/flags/videoresolution/1080.png b/addons/skin.estuary/media/flags/videoresolution/1080.png Binary files differdeleted file mode 100644 index fa076b8d2d..0000000000 --- a/addons/skin.estuary/media/flags/videoresolution/1080.png +++ /dev/null diff --git a/addons/skin.estuary/media/flags/videoresolution/3D.png b/addons/skin.estuary/media/flags/videoresolution/3D.png Binary files differdeleted file mode 100644 index 9b6c26254f..0000000000 --- a/addons/skin.estuary/media/flags/videoresolution/3D.png +++ /dev/null diff --git a/addons/skin.estuary/media/flags/videoresolution/480.png b/addons/skin.estuary/media/flags/videoresolution/480.png Binary files differdeleted file mode 100644 index 66deb31b80..0000000000 --- a/addons/skin.estuary/media/flags/videoresolution/480.png +++ /dev/null diff --git a/addons/skin.estuary/media/flags/videoresolution/4K.png b/addons/skin.estuary/media/flags/videoresolution/4K.png Binary files differdeleted file mode 100644 index f3d13bdccf..0000000000 --- a/addons/skin.estuary/media/flags/videoresolution/4K.png +++ /dev/null diff --git a/addons/skin.estuary/media/flags/videoresolution/540.png b/addons/skin.estuary/media/flags/videoresolution/540.png Binary files differdeleted file mode 100644 index dd6c3823d1..0000000000 --- a/addons/skin.estuary/media/flags/videoresolution/540.png +++ /dev/null diff --git a/addons/skin.estuary/media/flags/videoresolution/576.png b/addons/skin.estuary/media/flags/videoresolution/576.png Binary files differdeleted file mode 100644 index 8a96be926c..0000000000 --- a/addons/skin.estuary/media/flags/videoresolution/576.png +++ /dev/null diff --git a/addons/skin.estuary/media/flags/videoresolution/720.png b/addons/skin.estuary/media/flags/videoresolution/720.png Binary files differdeleted file mode 100644 index 0b6406004a..0000000000 --- a/addons/skin.estuary/media/flags/videoresolution/720.png +++ /dev/null diff --git a/addons/skin.estuary/media/flags/videoresolution/8K.png b/addons/skin.estuary/media/flags/videoresolution/8K.png Binary files differdeleted file mode 100644 index de46f91e9b..0000000000 --- a/addons/skin.estuary/media/flags/videoresolution/8K.png +++ /dev/null diff --git a/addons/skin.estuary/xml/DialogPVRGuideSearch.xml b/addons/skin.estuary/xml/DialogPVRGuideSearch.xml index e1e766025e..8ac09e05d0 100644 --- a/addons/skin.estuary/xml/DialogPVRGuideSearch.xml +++ b/addons/skin.estuary/xml/DialogPVRGuideSearch.xml @@ -5,12 +5,12 @@ <controls> <control type="group"> <centertop>50%</centertop> - <height>890</height> + <height>960</height> <centerleft>50%</centerleft> <width>1780</width> <include content="DialogBackgroundCommons"> <param name="width" value="1780" /> - <param name="height" value="890" /> + <param name="height" value="960" /> <param name="header_label" value="$LOCALIZE[19142]" /> <param name="header_id" value="2" /> </include> @@ -41,7 +41,7 @@ <left>10</left> <top>210</top> <width>1460</width> - <height>675</height> + <height>740</height> <texture border="40">buttons/dialogbutton-nofo.png</texture> </control> <control type="grouplist" id="5000"> @@ -69,16 +69,23 @@ <control type="edit" id="14"> <description>Start Date</description> <width>710</width> - <onright>16</onright> + <onright>15</onright> <include>DefaultSettingButton</include> <label>$LOCALIZE[19128]</label> </control> - <control type="edit" id="15"> - <description>Stop Date</description> + <control type="radiobutton" id="32"> + <description>Start any time</description> + <width>710</width> + <onright>33</onright> + <include>DefaultSettingButton</include> + <label>$LOCALIZE[810]</label> + </control> + <control type="edit" id="16"> + <description>Start time</description> <width>710</width> <onright>17</onright> <include>DefaultSettingButton</include> - <label>$LOCALIZE[19129]</label> + <label>$LOCALIZE[19126]</label> </control> <control type="radiobutton" id="30"> <description>Ignore finished broadcasts</description> @@ -138,17 +145,24 @@ <include>DefaultSettingButton</include> <label>$LOCALIZE[19131]</label> </control> - <control type="edit" id="16"> - <description>Start time</description> + <control type="edit" id="15"> + <description>Stop Date</description> <width>710</width> <onleft>14</onleft> <include>DefaultSettingButton</include> - <label>$LOCALIZE[19126]</label> + <label>$LOCALIZE[19129]</label> + </control> + <control type="radiobutton" id="33"> + <description>End any time</description> + <width>710</width> + <onleft>32</onleft> + <include>DefaultSettingButton</include> + <label>$LOCALIZE[817]</label> </control> <control type="edit" id="17"> <description>Stop time</description> <width>710</width> - <onleft>15</onleft> + <onleft>16</onleft> <include>DefaultSettingButton</include> <label>$LOCALIZE[19127]</label> </control> diff --git a/addons/skin.estuary/xml/DialogSeekBar.xml b/addons/skin.estuary/xml/DialogSeekBar.xml index 5e870977a5..958757d98b 100644 --- a/addons/skin.estuary/xml/DialogSeekBar.xml +++ b/addons/skin.estuary/xml/DialogSeekBar.xml @@ -49,115 +49,14 @@ <label>[COLOR red][B]$LOCALIZE[19158][/B][/COLOR]</label> </control> </control> - <control type="grouplist"> - <right>20</right> - <centertop>125</centertop> - <width>800</width> - <height>50</height> - <align>right</align> - <include>Animation_BottomSlide</include> - <orientation>horizontal</orientation> - <itemgap>5</itemgap> - <visible>[Player.ShowInfo | Window.IsActive(fullscreeninfo)] + !Player.ChannelPreviewActive + Window.IsActive(fullscreenvideo)</visible> - <animation effect="fade" start="0" end="100" time="200" delay="1000">Visible</animation> - <include content="MediaFlag"> - <param name="texture" value="$INFO[VideoPlayer.VideoCodec,flags/videocodec/,.png]" /> - <param name="visible" value="!String.IsEmpty(VideoPlayer.VideoCodec)" /> - </include> - <include content="MediaFlag"> - <param name="texture" value="$INFO[VideoPlayer.VideoResolution,flags/videoresolution/,.png]" /> - <param name="visible" value="!String.IsEmpty(VideoPlayer.VideoResolution)" /> - </include> - <include content="MediaFlag"> - <param name="texture" value="$INFO[VideoPlayer.HdrType,flags/videohdr/,.png]" /> - <param name="visible" value="!String.IsEmpty(VideoPlayer.HdrType)" /> - </include> - <include content="MediaFlag"> - <param name="texture" value="$INFO[VideoPlayer.VideoAspect,flags/aspectratio/,.png]" /> - <param name="visible" value="!String.IsEmpty(VideoPlayer.VideoAspect)" /> - </include> - <include content="MediaFlag"> - <param name="texture" value="$INFO[VideoPlayer.AudioCodec,flags/audiocodec/,.png]" /> - <param name="visible" value="!String.IsEmpty(VideoPlayer.AudioCodec)" /> - </include> - <include content="MediaFlag"> - <param name="texture" value="$INFO[VideoPlayer.AudioChannels,flags/audiochannel/,.png]" /> - <param name="visible" value="!String.IsEmpty(VideoPlayer.AudioChannels)" /> - </include> - </control> - <control type="grouplist"> - <right>20</right> - <centertop>125</centertop> - <width>800</width> - <height>50</height> - <align>right</align> - <include>Animation_BottomSlide</include> - <orientation>horizontal</orientation> - <itemgap>10</itemgap> - <visible>Player.ShowInfo + !Player.ChannelPreviewActive + Window.IsActive(visualisation)</visible> - <animation effect="fade" start="0" end="100" time="200" delay="1000">Visible</animation> - <include content="MediaFlag"> - <param name="texture" value="flags/rds/rds.png" /> - <param name="visible" value="RDS.HasRDS" /> - </include> - <include content="MediaFlag"> - <param name="texture" value="$INFO[MusicPlayer.Codec,flags/audiocodec/,.png]" /> - <param name="visible" value="!String.IsEmpty(MusicPlayer.Codec)" /> - </include> - <include content="MediaFlag"> - <param name="texture" value="$INFO[MusicPlayer.Channels,flags/audiochannel/,.png]" /> - <param name="visible" value="!String.IsEmpty(MusicPlayer.Channels)" /> - </include> - <control type="group"> - <visible>!String.IsEmpty(MusicPlayer.SampleRate)</visible> - <width>115</width> - <control type="label"> - <width>115</width> - <height>60</height> - <align>center</align> - <aligny>center</aligny> - <label>$INFO[MusicPlayer.SampleRate, ,kHz]</label> - <font>font_flag</font> - </control> - <include content="MediaFlag"> - <param name="texture" value="flags/flag.png" /> - </include> - </control> - <control type="group"> - <visible>!String.IsEmpty(MusicPlayer.BitRate)</visible> - <width>115</width> - <control type="label"> - <width>115</width> - <height>60</height> - <align>center</align> - <aligny>center</aligny> - <label>$INFO[MusicPlayer.BitRate, ,kbps ]</label> - <font>font_flag</font> - </control> - <include content="MediaFlag"> - <param name="texture" value="flags/flag.png" /> - </include> - </control> - <control type="group"> - <visible>!String.IsEmpty(MusicPlayer.BitsPerSample)</visible> - <width>115</width> - <control type="label"> - <width>115</width> - <height>60</height> - <align>center</align> - <aligny>center</aligny> - <label>$INFO[MusicPlayer.BitsPerSample, ,bit]</label> - <font>font_flag</font> - </control> - <include content="MediaFlag"> - <param name="texture" value="flags/flag.png" /> - </include> - </control> + <control type="group"> + <top>195</top> + <include condition="!Skin.HasSetting(hide_mediaflags)">MediaFlags</include> </control> </control> <control type="label"> <centerleft>50%</centerleft> - <centertop>125</centertop> + <centertop>120</centertop> <width>50%</width> <height>60</height> <align>center</align> @@ -170,8 +69,8 @@ <control type="label" id="40000"> <centerleft>50%</centerleft> <centertop>175</centertop> - <width>50%</width> - <height>50</height> + <width>380</width> + <height>60</height> <align>center</align> <aligny>top</aligny> <label>$VAR[SeekLabel]</label> diff --git a/addons/skin.estuary/xml/Home.xml b/addons/skin.estuary/xml/Home.xml index 24d032df23..5ac611a33f 100644 --- a/addons/skin.estuary/xml/Home.xml +++ b/addons/skin.estuary/xml/Home.xml @@ -1120,10 +1120,7 @@ <height>70</height> <animation effect="fade" start="0" end="100" time="300" delay="300">WindowOpen</animation> <animation effect="fade" start="100" end="0" time="200">WindowClose</animation> - <include condition="!Skin.HasSetting(hide_mediaflags)" content="MediaFlags"> - <param name="infolabel_prefix" value="Container." /> - <param name="resolution_var" value="$VAR[ContainerResolutionFlagVar]" /> - </include> + <include condition="!Skin.HasSetting(hide_mediaflags)">MediaFlags</include> <control type="rss"> <animation effect="slide" end="0,90" time="300" tween="sine" easing="inout" condition="$EXP[infodialog_active]">conditional</animation> <left>0</left> diff --git a/addons/skin.estuary/xml/Includes.xml b/addons/skin.estuary/xml/Includes.xml index 294f13e800..b649528a36 100644 --- a/addons/skin.estuary/xml/Includes.xml +++ b/addons/skin.estuary/xml/Includes.xml @@ -339,37 +339,47 @@ <include name="MediaFlag"> <param name="width">115</param> <param name="height">60</param> - <param name="visible">true</param> + <param name="flag_visible">true</param> + <param name="texture">flags/flag.png</param> <definition> - <control type="image"> + <control type="group"> <width>$PARAM[width]</width> <height>$PARAM[height]</height> - <fadetime>0</fadetime> - <aspectratio align="center" aligny="center">keep</aspectratio> - <texture>$PARAM[texture]</texture> - <visible>$PARAM[visible]</visible> + <visible>$PARAM[flag_visible]</visible> + <control type="image"> + <fadetime>0</fadetime> + <align>center</align> + <aligny>center</aligny> + <aspectratio>keep</aspectratio> + <texture>$PARAM[texture]</texture> + </control> + <control type="label"> + <align>center</align> + <aligny>center</aligny> + <label>$PARAM[flag_label]</label> + <font>font_flag</font> + </control> </control> </definition> </include> <include name="MediaFlags"> - <param name="infolabel_prefix"></param> - <param name="resolution_var">$VAR[ResolutionFlagVar]</param> + <param name="visible">true</param> <definition> <control type="grouplist"> <visible>Window.IsActive(Home) | Window.IsActive(10025)</visible> <orientation>horizontal</orientation> <right>20</right> - <top>0</top> - <height>70</height> + <bottom>0</bottom> + <height>60</height> <align>right</align> <itemgap>10</itemgap> <width>1900</width> <usecontrolcoords>true</usecontrolcoords> <control type="group"> <width>150</width> - <visible>System.AddonIsEnabled(resource.images.studios.white) + !String.IsEmpty($PARAM[infolabel_prefix]ListItem.Studio)</visible> + <visible>System.AddonIsEnabled(resource.images.studios.white) + !String.IsEmpty(ListItem.Studio)</visible> <include content="MediaFlag"> - <param name="texture" value="$INFO[$PARAM[infolabel_prefix]ListItem.Studio,resource://resource.images.studios.white/,.png]" /> + <param name="texture" value="$INFO[ListItem.Studio,resource://resource.images.studios.white/,.png]" /> </include> </control> <control type="group"> @@ -378,154 +388,158 @@ <visible>!String.IsEmpty($PARAM[infolabel_prefix]ListItem.Premiered)</visible> <include content="InfoFlag"> <param name="icon" value="lists/year.png" /> - <param name="label" value="$INFO[$PARAM[infolabel_prefix]ListItem.Premiered]" /> - </include> - </control> - <control type="group"> - <width>115</width> - <visible>!String.IsEmpty($PARAM[infolabel_prefix]ListItem.Duration)</visible> - <control type="label"> - <width>115</width> - <height>60</height> - <align>center</align> - <aligny>center</aligny> - <label>$INFO[$PARAM[infolabel_prefix]ListItem.Duration]</label> - <font>font_flag</font> - </control> - <include content="MediaFlag"> - <param name="texture" value="flags/flag.png" /> + <param name="label" value="$INFO[ListItem.Premiered]" /> </include> </control> <include content="MediaFlag"> - <param name="texture" value="$INFO[ListItem.VideoCodec,flags/videocodec/,.png]" /> - <param name="visible" value="!String.IsEmpty($PARAM[infolabel_prefix]ListItem.VideoCodec)" /> + <param name="flag_visible" value="!String.IsEmpty(ListItem.Duration)" /> + <param name="flag_label" value="$INFO[ListItem.Duration]" /> </include> <include content="MediaFlag"> - <param name="texture" value="$PARAM[resolution_var]" /> - <param name="visible" value="!String.IsEmpty($PARAM[infolabel_prefix]ListItem.VideoResolution)" /> + <param name="flag_visible" value="ListItem.IsStereoscopic" /> + <param name="flag_label" value="3D" /> </include> <include content="MediaFlag"> - <param name="texture" value="$INFO[ListItem.HdrType,flags/videohdr/,.png]" /> - <param name="visible" value="!String.IsEmpty($PARAM[infolabel_prefix]ListItem.HdrType)" /> + <param name="flag_visible" value="!String.IsEmpty(ListItem.VideoCodec)" /> + <param name="flag_label" value="$VAR[VideoListCodecVar]" /> </include> <include content="MediaFlag"> - <param name="texture" value="$INFO[ListItem.VideoAspect,flags/aspectratio/,.png]" /> - <param name="visible" value="!String.IsEmpty($PARAM[infolabel_prefix]ListItem.VideoAspect)" /> + <param name="flag_visible" value="!String.IsEmpty(ListItem.VideoResolution)" /> + <param name="flag_label" value="$INFO[ListItem.VideoResolution]$VAR[VideoListResolutionTypeVar, ]" /> </include> <include content="MediaFlag"> - <param name="texture" value="$INFO[$PARAM[infolabel_prefix]ListItem.AudioCodec,flags/audiocodec/,.png]" /> - <param name="visible" value="!String.IsEmpty($PARAM[infolabel_prefix]ListItem.AudioCodec)" /> + <param name="flag_visible" value="!String.IsEmpty(ListItem.HdrType)" /> + <param name="flag_label" value="$VAR[VideoListHDRVar]" /> </include> <include content="MediaFlag"> - <param name="texture" value="$INFO[$PARAM[infolabel_prefix]ListItem.AudioChannels,flags/audiochannel/,.png]" /> - <param name="visible" value="!String.IsEmpty($PARAM[infolabel_prefix]ListItem.AudioChannels)" /> + <param name="flag_visible" value="!String.IsEmpty(ListItem.VideoAspect)" /> + <param name="flag_label" value="$INFO[ListItem.VideoAspect,,:1]" /> + </include> + <include content="MediaFlag"> + <param name="flag_visible" value="!String.IsEmpty(ListItem.AudioCodec)" /> + <param name="flag_label" value="$VAR[AudioListCodecVar]" /> + </include> + <include content="MediaFlag"> + <param name="flag_visible" value="!String.IsEmpty(ListItem.AudioChannels)" /> + <param name="flag_label" value="$VAR[AudioListChannelsVar]" /> + </include> + </control> + <control type="grouplist"> + <visible>[Player.ShowInfo | Window.IsActive(fullscreeninfo)] + !Player.ChannelPreviewActive + Window.IsActive(fullscreenvideo)</visible> + <orientation>horizontal</orientation> + <right>20</right> + <bottom>0</bottom> + <height>60</height> + <align>right</align> + <itemgap>10</itemgap> + <width>1900</width> + <usecontrolcoords>true</usecontrolcoords> + <include content="MediaFlag"> + <param name="flag_visible" value="VideoPlayer.IsStereoscopic" /> + <param name="flag_label" value="3D" /> + </include> + <include content="MediaFlag"> + <param name="flag_visible" value="!String.IsEmpty(VideoPlayer.VideoCodec)" /> + <param name="flag_label" value="$VAR[VideoPlayerCodecVar]" /> + </include> + <include content="MediaFlag"> + <param name="flag_visible" value="!String.IsEmpty(VideoPlayer.VideoResolution)" /> + <param name="flag_label" value="$INFO[VideoPlayer.VideoResolution]$VAR[VideoPlayerResolutionTypeVar, ]" /> + </include> + <include content="MediaFlag"> + <param name="flag_visible" value="!String.IsEmpty(VideoPlayer.HdrType)" /> + <param name="flag_label" value="$VAR[VideoPlayerHDRVar]" /> + </include> + <include content="MediaFlag"> + <param name="flag_visible" value="!String.IsEmpty(VideoPlayer.VideoAspect)" /> + <param name="flag_label" value="$INFO[VideoPlayer.VideoAspect,,:1]" /> + </include> + <include content="MediaFlag"> + <param name="flag_visible" value="!String.IsEmpty(VideoPlayer.AudioCodec)" /> + <param name="flag_label" value="$VAR[VideoPlayerAudioCodecVar]" /> + </include> + <include content="MediaFlag"> + <param name="flag_visible" value="!String.IsEmpty(VideoPlayer.AudioChannels)" /> + <param name="flag_label" value="$VAR[VideoPlayerAudioChannelsVar]" /> </include> </control> <control type="grouplist"> <visible>Container.Content(albums) | Window.IsActive(10502)</visible> <orientation>horizontal</orientation> <right>20</right> - <top>0</top> - <height>70</height> + <bottom>10</bottom> + <height>60</height> <align>right</align> <itemgap>10</itemgap> <width>1900</width> <usecontrolcoords>true</usecontrolcoords> - <control type="group"> - <width>115</width> - <visible>!String.IsEmpty($PARAM[infolabel_prefix]ListItem.Duration)</visible> - <visible>Container.Content(albums) + ![Window.IsVisible(songinformation) | Window.IsVisible(musicinformation)]</visible> - <control type="label"> - <width>110</width> - <height>60</height> - <align>center</align> - <aligny>center</aligny> - <label>$INFO[$PARAM[infolabel_prefix]ListItem.Duration]</label> - <font>font_flag</font> - </control> - <include content="MediaFlag"> - <param name="texture" value="flags/flag.png" /> - </include> - </control> - <control type="group"> - <width>115</width> - <visible>!String.IsEmpty($PARAM[infolabel_prefix]ListItem.FileExtension)</visible> - <control type="label"> - <width>110</width> - <height>60</height> - <align>center</align> - <aligny>center</aligny> - <label>$INFO[$PARAM[infolabel_prefix]ListItem.FileExtension]</label> - <font>font_flag</font> - </control> - <include content="MediaFlag"> - <param name="texture" value="flags/flag.png" /> - </include> - </control> <include content="MediaFlag"> - <param name="texture" value="$INFO[$PARAM[infolabel_prefix]ListItem.MusicChannels,flags/audiochannel/,.png]" /> - <param name="visible" value="!String.IsEmpty($PARAM[infolabel_prefix]ListItem.MusicChannels)" /> + <param name="flag_visible" value="!String.IsEmpty(ListItem.Duration) + Container.Content(albums) + ![Window.IsVisible(songinformation) | Window.IsVisible(musicinformation)]" /> + <param name="flag_label" value="$INFO[ListItem.Duration]" /> + </include> + <include content="MediaFlag"> + <param name="flag_visible" value="!String.IsEmpty(ListItem.FileExtension)" /> + <param name="flag_label" value="$INFO[ListItem.FileExtension]" /> + </include> + <include content="MediaFlag"> + <param name="flag_visible" value="!String.IsEmpty(ListItem.MusicChannels)" /> + <param name="flag_label" value="$VAR[MusicListChannelsVar]" /> + </include> + <include content="MediaFlag"> + <param name="flag_visible" value="!String.IsEmpty(ListItem.Samplerate)" /> + <param name="flag_label" value="$INFO[ListItem.Samplerate, ,kHz]" /> + </include> + <include content="MediaFlag"> + <param name="flag_visible" value="!String.IsEmpty(ListItem.BitRate)" /> + <param name="flag_label" value="$INFO[ListItem.BitRate, ,kbps]" /> + </include> + <include content="MediaFlag"> + <param name="flag_visible" value="!String.IsEmpty(ListItem.MusicBitsPerSample)" /> + <param name="flag_label" value="$INFO[ListItem.MusicBitsPerSample, ,bit]" /> + </include> + <include content="MediaFlag"> + <param name="flag_visible" value="!String.IsEmpty(ListItem.BMP)" /> + <param name="flag_label" value="$INFO[ListItem.BMP, ,bpm]" /> + </include> + </control> + <control type="grouplist"> + <visible>Player.ShowInfo + !Player.ChannelPreviewActive + Window.IsActive(visualisation)</visible>) + <orientation>horizontal</orientation> + <right>20</right> + <bottom>10</bottom> + <height>60</height> + <align>right</align> + <itemgap>10</itemgap> + <width>1900</width> + <usecontrolcoords>true</usecontrolcoords> + <include content="MediaFlag"> + <param name="flag_visible" value="RDS.HasRDS" /> + <param name="flag_label" value="RDS" /> + </include> + <include content="MediaFlag"> + <param name="flag_visible" value="!String.IsEmpty(MusicPlayer.Codec)" /> + <param name="flag_label" value="$VAR[MusicPlayerCodecVar]" /> + </include> + <include content="MediaFlag"> + <param name="flag_visible" value="!String.IsEmpty(MusicPlayer.Channels)" /> + <param name="flag_label" value="$VAR[MusicPlayerAudioChannelsVar]" /> + </include> + <include content="MediaFlag"> + <param name="flag_visible" value="!String.IsEmpty(MusicPlayer.SampleRate)" /> + <param name="flag_label" value="$INFO[MusicPlayer.SampleRate, ,kHz]" /> + </include> + <include content="MediaFlag"> + <param name="flag_visible" value="!String.IsEmpty(MusicPlayer.BitRate)" /> + <param name="flag_label" value="$INFO[MusicPlayer.BitRate, ,kbps]" /> + </include> + <include content="MediaFlag"> + <param name="flag_visible" value="!String.IsEmpty(MusicPlayer.BitsPerSample)" /> + <param name="flag_label" value="$INFO[MusicPlayer.BitsPerSample, ,bit]" /> + </include> + <include content="MediaFlag"> + <param name="flag_visible" value="!String.IsEmpty(MusicPlayer.BMP)" /> + <param name="flag_label" value="$INFO[MusicPlayer.BMP, ,bpm]" /> </include> - <control type="group"> - <visible>!String.IsEmpty(ListItem.Samplerate)</visible> - <width>115</width> - <control type="label"> - <width>110</width> - <height>60</height> - <align>center</align> - <aligny>center</aligny> - <label>$INFO[ListItem.Samplerate, ,kHz]</label> - <font>font_flag</font> - </control> - <include content="MediaFlag"> - <param name="texture" value="flags/flag.png" /> - </include> - </control> - <control type="group"> - <visible>!String.IsEmpty(ListItem.BitRate)</visible> - <width>115</width> - <control type="label"> - <width>110</width> - <height>60</height> - <align>center</align> - <aligny>center</aligny> - <label>$INFO[ListItem.BitRate, ,kbps]</label> - <font>font_flag</font> - </control> - <include content="MediaFlag"> - <param name="texture" value="flags/flag.png" /> - </include> - </control> - <control type="group"> - <visible>!String.IsEmpty(ListItem.MusicBitsPerSample)</visible> - <width>115</width> - <control type="label"> - <width>110</width> - <height>60</height> - <align>center</align> - <aligny>center</aligny> - <label>$INFO[ListItem.MusicBitsPerSample, ,bit]</label> - <font>font_flag</font> - </control> - <include content="MediaFlag"> - <param name="texture" value="flags/flag.png" /> - </include> - </control> - <control type="group"> - <visible>!String.IsEmpty(ListItem.BMP)</visible> - <width>115</width> - <control type="label"> - <width>110</width> - <height>60</height> - <align>center</align> - <aligny>center</aligny> - <label>$INFO[ListItem.BMP, ,bpm]</label> - <font>font_flag</font> - </control> - <include content="MediaFlag"> - <param name="texture" value="flags/flag.png" /> - </include> - </control> </control> </definition> </include> diff --git a/addons/skin.estuary/xml/Variables.xml b/addons/skin.estuary/xml/Variables.xml index e5fd8b989b..48d31556df 100644 --- a/addons/skin.estuary/xml/Variables.xml +++ b/addons/skin.estuary/xml/Variables.xml @@ -708,7 +708,7 @@ <value condition="!String.IsEmpty(Container(50).ListItem.Art(thumb))">$INFO[Container(50).ListItem.Art(thumb)]</value> <value>$INFO[ListItem.Art(thumb)]</value> </variable> - <variable name="VideoResolutionTypeVar"> + <variable name="VideoListResolutionTypeVar"> <value condition="String.IsEqual(ListItem.VideoResolution,480)">SD</value> <value condition="String.IsEqual(ListItem.VideoResolution,540)">SD</value> <value condition="String.IsEqual(ListItem.VideoResolution,576)">SD</value> @@ -716,8 +716,19 @@ <value condition="String.IsEqual(ListItem.VideoResolution,1080)">HD</value> <value condition="String.IsEqual(ListItem.VideoResolution,4K)">UHD</value> <value condition="String.IsEqual(ListItem.VideoResolution,8K)">UHD</value> - </variable> - <variable name="VideoCodecVar"> + <value>$INFO[ListItem.VideoResolution]</value> + </variable> + <variable name="VideoPlayerResolutionTypeVar"> + <value condition="String.IsEqual(VideoPlayer.VideoResolution,480)">SD</value> + <value condition="String.IsEqual(VideoPlayer.VideoResolution,540)">SD</value> + <value condition="String.IsEqual(VideoPlayer.VideoResolution,576)">SD</value> + <value condition="String.IsEqual(VideoPlayer.VideoResolution,720)">HD</value> + <value condition="String.IsEqual(VideoPlayer.VideoResolution,1080)">HD</value> + <value condition="String.IsEqual(VideoPlayer.VideoResolution,4K)">UHD</value> + <value condition="String.IsEqual(VideoPlayer.VideoResolution,8K)">UHD</value> + <value>$INFO[VideoPlayer.VideoResolution]</value> + </variable> + <variable name="VideoListCodecVar"> <value condition="String.IsEqual(ListItem.VideoCodec,av1)">AV1</value> <value condition="String.IsEqual(ListItem.VideoCodec,avc1)">AVC-1</value> <value condition="String.IsEqual(ListItem.VideoCodec,div3)">DivX</value> @@ -744,13 +755,46 @@ <value condition="String.IsEqual(ListItem.VideoCodec,xvid)">XviD</value> <value>$INFO[ListItem.VideoCodec]</value> </variable> - <variable name="VideoHDRVar"> - <value condition="String.IsEqual(ListItem.HdrType,dolbyvision)">Dolby Vision</value> + <variable name="VideoPlayerCodecVar"> + <value condition="String.IsEqual(VideoPlayer.VideoCodec,av1)">AV1</value> + <value condition="String.IsEqual(VideoPlayer.VideoCodec,avc1)">AVC-1</value> + <value condition="String.IsEqual(VideoPlayer.VideoCodec,div3)">DivX</value> + <value condition="String.IsEqual(VideoPlayer.VideoCodec,divx)">DivX</value> + <value condition="String.IsEqual(VideoPlayer.VideoCodec,dx50)">DivX</value> + <value condition="String.IsEqual(VideoPlayer.VideoCodec,flv)">FLV</value> + <value condition="String.IsEqual(VideoPlayer.VideoCodec,h264)">H.264</value> + <value condition="String.IsEqual(VideoPlayer.VideoCodec,hev1)">H.265</value> + <value condition="String.IsEqual(VideoPlayer.VideoCodec,hevc)">H.265</value> + <value condition="String.IsEqual(VideoPlayer.VideoCodec,hvc1)">H.265</value> + <value condition="String.IsEqual(VideoPlayer.VideoCodec,mpeg1)">MPEG-1</value> + <value condition="String.IsEqual(VideoPlayer.VideoCodec,mpeg2)">MPEG-2</value> + <value condition="String.IsEqual(VideoPlayer.VideoCodec,mpeg2video)">MPEG-2</value> + <value condition="String.IsEqual(VideoPlayer.VideoCodec,mp4v)">MPEG-4</value> + <value condition="String.IsEqual(VideoPlayer.VideoCodec,mpeg4)">MPEG-4</value> + <value condition="String.IsEqual(VideoPlayer.VideoCodec,theora)">Theora</value> + <value condition="String.IsEqual(VideoPlayer.VideoCodec,vc1)">VC-1</value> + <value condition="String.IsEqual(VideoPlayer.VideoCodec,vc-1)">VC-1</value> + <value condition="String.IsEqual(VideoPlayer.VideoCodec,vp8)">VP8</value> + <value condition="String.IsEqual(VideoPlayer.VideoCodec,vp9)">VP9</value> + <value condition="String.IsEqual(VideoPlayer.VideoCodec,wmv)">WMV</value> + <value condition="String.IsEqual(VideoPlayer.VideoCodec,wmv3)">WMV</value> + <value condition="String.IsEqual(VideoPlayer.VideoCodec,wvc1)">VC-1</value> + <value condition="String.IsEqual(VideoPlayer.VideoCodec,xvid)">XviD</value> + <value>$INFO[VideoPlayer.VideoCodec]</value> + </variable> + <variable name="VideoListHDRVar"> + <value condition="String.IsEqual(ListItem.HdrType,dolbyvision)">DoVi</value> <value condition="String.IsEqual(ListItem.HdrType,hdr10)">HDR10</value> <value condition="String.IsEqual(ListItem.HdrType,hlg)">HLG</value> <value>$INFO[ListItem.HdrType]</value> </variable> - <variable name="AudioCodecVar"> + <variable name="VideoPlayerHDRVar"> + <value condition="String.IsEqual(VideoPlayer.HdrType,dolbyvision)">DoVi</value> + <value condition="String.IsEqual(VideoPlayer.HdrType,hdr10)">HDR10</value> + <value condition="String.IsEqual(VideoPlayer.HdrType,hlg)">HLG</value> + <value>$INFO[VideoPlayer.HdrType]</value> + </variable> + <variable name="AudioListCodecVar"> <value condition="String.IsEqual(ListItem.AudioCodec,aac)">AAC</value> <value condition="String.IsEqual(ListItem.AudioCodec,aac_latm)">AAC</value> <value condition="String.IsEqual(ListItem.AudioCodec,ac3)">Dolby D</value> @@ -786,7 +830,43 @@ <value condition="String.IsEqual(ListItem.AudioCodec,wmav2)">WMA</value> <value>$INFO[ListItem.AudioCodec]</value> </variable> - <variable name="AudioChannelsVar"> + <variable name="VideoPlayerAudioCodecVar"> + <value condition="String.IsEqual(VideoPlayer.AudioCodec,aac)">AAC</value> + <value condition="String.IsEqual(VideoPlayer.AudioCodec,aac_latm)">AAC</value> + <value condition="String.IsEqual(VideoPlayer.AudioCodec,ac3)">Dolby D</value> + <value condition="String.IsEqual(VideoPlayer.AudioCodec,aif)">AIFF</value> + <value condition="String.IsEqual(VideoPlayer.AudioCodec,aifc)">AIFF</value> + <value condition="String.IsEqual(VideoPlayer.AudioCodec,aiff)">AIFF</value> + <value condition="String.IsEqual(VideoPlayer.AudioCodec,alac)">ALAC</value> + <value condition="String.IsEqual(VideoPlayer.AudioCodec,ape)">APE</value> + <value condition="String.IsEqual(VideoPlayer.AudioCodec,avc)">AVC</value> + <value condition="String.IsEqual(VideoPlayer.AudioCodec,cdda)">CDDA</value> + <value condition="String.IsEqual(VideoPlayer.AudioCodec,dca)">DTS</value> + <value condition="String.IsEqual(VideoPlayer.AudioCodec,dolbydigital)">Dolby D</value> + <value condition="String.IsEqual(VideoPlayer.AudioCodec,dts)">DTS</value> + <value condition="String.IsEqual(VideoPlayer.AudioCodec,dtshd_hra)">DTSHD-HRA</value> + <value condition="String.IsEqual(VideoPlayer.AudioCodec,dtshd_ma)">DTSHD-MA</value> + <value condition="String.IsEqual(VideoPlayer.AudioCodec,dtsma)">DTSHD-MA</value> + <value condition="String.IsEqual(VideoPlayer.AudioCodec,eac3)">Dolby D+</value> + <value condition="String.IsEqual(VideoPlayer.AudioCodec,flac)">FLAC</value> + <value condition="String.IsEqual(VideoPlayer.AudioCodec,mp1)">MP1</value> + <value condition="String.IsEqual(VideoPlayer.AudioCodec,mp3)">MP3</value> + <value condition="String.IsEqual(VideoPlayer.AudioCodec,mp3float)">MP3</value> + <value condition="String.IsEqual(VideoPlayer.AudioCodec,ogg)">OGG</value> + <value condition="String.IsEqual(VideoPlayer.AudioCodec,opus)">OPUS</value> + <value condition="String.IsEqual(VideoPlayer.AudioCodec,pcm)">PCM</value> + <value condition="String.IsEqual(VideoPlayer.AudioCodec,pcm_bluray)">PCM</value> + <value condition="String.IsEqual(VideoPlayer.AudioCodec,pcm_s16le)">PCM</value> + <value condition="String.IsEqual(VideoPlayer.AudioCodec,pcm_s24le)">PCM</value> + <value condition="String.IsEqual(VideoPlayer.AudioCodec,truehd)">TrueHD</value> + <value condition="String.IsEqual(VideoPlayer.AudioCodec,vorbis)">Vorbis</value> + <value condition="String.IsEqual(VideoPlayer.AudioCodec,wav)">WAV</value> + <value condition="String.IsEqual(VideoPlayer.AudioCodec,wavpack)">WAVP</value> + <value condition="String.IsEqual(VideoPlayer.AudioCodec,wmapro)">WMA-PRO</value> + <value condition="String.IsEqual(VideoPlayer.AudioCodec,wmav2)">WMA</value> + <value>$INFO[VideoPlayer.AudioCodec]</value> + </variable> + <variable name="AudioListChannelsVar"> <value condition="String.IsEqual(ListItem.AudioChannels,0)">0.0</value> <value condition="String.IsEqual(ListItem.AudioChannels,1)">1.0</value> <value condition="String.IsEqual(ListItem.AudioChannels,2)">2.0</value> @@ -799,13 +879,88 @@ <value condition="String.IsEqual(ListItem.AudioChannels,10)">9.1</value> <value>$INFO[ListItem.AudioChannels]</value> </variable> + <variable name="VideoPlayerAudioChannelsVar"> + <value condition="String.IsEqual(VideoPlayer.AudioChannels,0)">0.0</value> + <value condition="String.IsEqual(VideoPlayer.AudioChannels,1)">1.0</value> + <value condition="String.IsEqual(VideoPlayer.AudioChannels,2)">2.0</value> + <value condition="String.IsEqual(VideoPlayer.AudioChannels,3)">2.1</value> + <value condition="String.IsEqual(VideoPlayer.AudioChannels,4)">4.0</value> + <value condition="String.IsEqual(VideoPlayer.AudioChannels,5)">4.1</value> + <value condition="String.IsEqual(VideoPlayer.AudioChannels,6)">5.1</value> + <value condition="String.IsEqual(VideoPlayer.AudioChannels,7)">6.1</value> + <value condition="String.IsEqual(VideoPlayer.AudioChannels,8)">7.1</value> + <value condition="String.IsEqual(VideoPlayer.AudioChannels,10)">9.1</value> + <value>$INFO[VideoPlayer.AudioChannels]</value> + </variable> + <variable name="MusicPlayerCodecVar"> + <value condition="String.IsEqual(MusicPlayer.Codec,aac)">AAC</value> + <value condition="String.IsEqual(MusicPlayer.Codec,aac_latm)">AAC</value> + <value condition="String.IsEqual(MusicPlayer.Codec,ac3)">Dolby D</value> + <value condition="String.IsEqual(LMusicPlayer.Codec,aif)">AIFF</value> + <value condition="String.IsEqual(MusicPlayer.Codec,aifc)">AIFF</value> + <value condition="String.IsEqual(MusicPlayer.Codec,aiff)">AIFF</value> + <value condition="String.IsEqual(MusicPlayer.Codec,alac)">ALAC</value> + <value condition="String.IsEqual(LMusicPlayer.Codec,ape)">APE</value> + <value condition="String.IsEqual(MusicPlayer.Codec,avc)">AVC</value> + <value condition="String.IsEqual(MusicPlayer.Codec,cdda)">CDDA</value> + <value condition="String.IsEqual(MusicPlayer.Codec,dca)">DTS</value> + <value condition="String.IsEqual(MusicPlayer.Codec,dolbydigital)">Dolby D</value> + <value condition="String.IsEqual(MusicPlayer.Codec,dts)">DTS</value> + <value condition="String.IsEqual(MusicPlayer.Codec,dtshd_hra)">DTSHD-HRA</value> + <value condition="String.IsEqual(MusicPlayer.Codec,dtshd_ma)">DTSHD-MA</value> + <value condition="String.IsEqual(MusicPlayer.Codec,dtsma)">DTSHD-MA</value> + <value condition="String.IsEqual(MusicPlayer.Codec,eac3)">Dolby D+</value> + <value condition="String.IsEqual(MusicPlayer.Codec,flac)">FLAC</value> + <value condition="String.IsEqual(MusicPlayer.Codec,mp1)">MP1</value> + <value condition="String.IsEqual(MusicPlayer.Codec,mp3)">MP3</value> + <value condition="String.IsEqual(MusicPlayer.Codec,mp3float)">MP3</value> + <value condition="String.IsEqual(MusicPlayer.Codec,ogg)">OGG</value> + <value condition="String.IsEqual(MusicPlayer.Codec,opus)">OPUS</value> + <value condition="String.IsEqual(MusicPlayer.Codec,pcm)">PCM</value> + <value condition="String.IsEqual(MusicPlayer.Codec,pcm_bluray)">PCM</value> + <value condition="String.IsEqual(MusicPlayer.Codec,pcm_s16le)">PCM</value> + <value condition="String.IsEqual(MusicPlayer.Codec,pcm_s24le)">PCM</value> + <value condition="String.IsEqual(MusicPlayer.Codec,truehd)">TrueHD</value> + <value condition="String.IsEqual(MusicPlayer.Codec,vorbis)">Vorbis</value> + <value condition="String.IsEqual(MusicPlayer.Codec,wav)">WAV</value> + <value condition="String.IsEqual(MusicPlayer.Codec,wavpack)">WAVP</value> + <value condition="String.IsEqual(MusicPlayer.Codec,wmapro)">WMA-PRO</value> + <value condition="String.IsEqual(MusicPlayer.Codec,wmav2)">WMA</value> + <value>$INFO[MusicPlayer.Codec]</value> + </variable> + <variable name="MusicListChannelsVar"> + <value condition="String.IsEqual(ListItem.MusicChannels,0)">0.0</value> + <value condition="String.IsEqual(ListItem.MusicChannels,1)">1.0</value> + <value condition="String.IsEqual(ListItem.MusicChannels,2)">2.0</value> + <value condition="String.IsEqual(ListItem.MusicChannels,3)">2.1</value> + <value condition="String.IsEqual(ListItem.MusicChannels,4)">4.0</value> + <value condition="String.IsEqual(ListItem.MusicChannels,5)">4.1</value> + <value condition="String.IsEqual(ListItem.MusicChannels,6)">5.1</value> + <value condition="String.IsEqual(ListItem.MusicChannels,7)">6.1</value> + <value condition="String.IsEqual(ListItem.MusicChannels,8)">7.1</value> + <value condition="String.IsEqual(ListItem.MusicChannels,10)">9.1</value> + <value>$INFO[ListItem.MusicChannels]</value> + </variable> + <variable name="MusicPlayerAudioChannelsVar"> + <value condition="String.IsEqual(MusicPlayer.Channels,0)">0.0</value> + <value condition="String.IsEqual(MusicPlayer.Channels,1)">1.0</value> + <value condition="String.IsEqual(MusicPlayer.Channels,2)">2.0</value> + <value condition="String.IsEqual(MusicPlayer.Channels,3)">2.1</value> + <value condition="String.IsEqual(MusicPlayer.Channels,4)">4.0</value> + <value condition="String.IsEqual(MusicPlayer.Channels,5)">4.1</value> + <value condition="String.IsEqual(MusicPlayer.Channels,6)">5.1</value> + <value condition="String.IsEqual(MusicPlayer.Channels,7)">6.1</value> + <value condition="String.IsEqual(MusicPlayer.Channels,8)">7.1</value> + <value condition="String.IsEqual(MusicPlayer.Channels,10)">9.1</value> + <value>$INFO[MusicPlayer.Channels]</value> + </variable> <variable name="MediaInfoListLabelVar"> <value condition="Window.IsVisible(selectvideoversion)">$INFO[ListItem.VideoVersionName]</value> <value>$INFO[ListItem.Label]</value> </variable> <variable name="MediaInfoListLabel2Var"> - <value condition="ListItem.IsStereoscopic">$INFO[ListItem.Duration,$LOCALIZE[180]: ][CR]$VAR[VideoCodecVar,, ]$INFO[ListItem.VideoResolution,| , ]$VAR[VideoResolutionTypeVar,, ]$VAR[VideoHDRVar,| , ]| 3D $INFO[ListItem.VideoAspect,| ,:1 ]$VAR[AudioCodecVar,| , ]$VAR[AudioChannelsVar]</value> - <value>$INFO[ListItem.Duration,$LOCALIZE[180]: ][CR]$VAR[VideoCodecVar,, ]$INFO[ListItem.VideoResolution,| , ]$VAR[VideoResolutionTypeVar,, ]$VAR[VideoHDRVar,| , ]$INFO[ListItem.VideoAspect,| ,:1 ]$VAR[AudioCodecVar,| , ]$VAR[AudioChannelsVar]</value> + <value condition="ListItem.IsStereoscopic">$INFO[ListItem.Duration,$LOCALIZE[180]: ][CR]3D | $VAR[VideoListCodecVar]$INFO[ListItem.VideoResolution, | ]$VAR[VideoListResolutionTypeVar, ]$VAR[VideoListHDRVar, | ]$VAR[VideoListAspectVar, | ]$VAR[AudioListCodecVar, | ]$VAR[AudioListChannelsVar, ]</value> + <value>$INFO[ListItem.Duration,$LOCALIZE[180]: ][CR]$VAR[VideoListCodecVar]$INFO[ListItem.VideoResolution, | ]$VAR[VideoListResolutionTypeVar, ]$VAR[VideoListHDRVar, | ]$VAR[VideoListAspectVar, | ]$VAR[AudioListCodecVar, | ]$VAR[AudioListChannelsVar, ]</value> </variable> <variable name="PVRInstanceName"> <value condition="Integer.IsGreater(PVR.ClientCount,1)">$INFO[ListItem.PVRClientName,[COLOR grey]$LOCALIZE[31137]:[/COLOR] ,]$INFO[ListItem.PVRInstanceName, (,)]</value> diff --git a/cmake/modules/FindCurl.cmake b/cmake/modules/FindCurl.cmake index a26682395c..3ce4ed5829 100644 --- a/cmake/modules/FindCurl.cmake +++ b/cmake/modules/FindCurl.cmake @@ -34,10 +34,6 @@ if(NOT TARGET ${APP_NAME_LC}::${CMAKE_FIND_PACKAGE_NAME}) set(PLATFORM_LINK_LIBS crypt32.lib) endif() - set(patches "${CORE_SOURCE_DIR}/tools/depends/target/${MODULE_LC}/01-win-nghttp2-add-name.patch") - - generate_patchcommand("${patches}") - set(CMAKE_ARGS -DBUILD_CURL_EXE=OFF -DBUILD_SHARED_LIBS=OFF -DBUILD_STATIC_LIBS=ON diff --git a/tools/depends/target/curl/01-win-nghttp2-add-name.patch b/tools/depends/target/curl/01-win-nghttp2-add-name.patch deleted file mode 100644 index e07843010a..0000000000 --- a/tools/depends/target/curl/01-win-nghttp2-add-name.patch +++ /dev/null @@ -1,11 +0,0 @@ ---- a/CMake/FindNGHTTP2.cmake -+++ b/CMake/FindNGHTTP2.cmake -@@ -25,7 +25,7 @@ - - find_path(NGHTTP2_INCLUDE_DIR "nghttp2/nghttp2.h") - --find_library(NGHTTP2_LIBRARY NAMES nghttp2) -+find_library(NGHTTP2_LIBRARY NAMES nghttp2 nghttp2_static) - - find_package_handle_standard_args(NGHTTP2 - FOUND_VAR diff --git a/tools/depends/target/curl/CURL-VERSION b/tools/depends/target/curl/CURL-VERSION index f9a42c2939..50facb2358 100644 --- a/tools/depends/target/curl/CURL-VERSION +++ b/tools/depends/target/curl/CURL-VERSION @@ -1,6 +1,6 @@ LIBNAME=curl -VERSION=8.7.1 +VERSION=8.10.0 ARCHIVE=$(LIBNAME)-$(VERSION).tar.xz -SHA512=5bbde9d5648e9226f5490fa951690aaf159149345f3a315df2ba58b2468f3e59ca32e8a49734338afc861803a4f81caac6d642a4699b72c6310ebfb1f618aad2 +SHA512=055277695ea242fcb0bf26ca6c4867a385cd578cd73ed4c5c4a020233248044c1ecaebcbaeaac47d3ffe07a41300ea5fc86396d7e812137cf75ed3e1b54ca5b2 BYPRODUCT=libcurl.a BYPRODUCT_WIN=libcurl.lib diff --git a/xbmc/FileItem.cpp b/xbmc/FileItem.cpp index 9efa598f82..dcc28288e4 100644 --- a/xbmc/FileItem.cpp +++ b/xbmc/FileItem.cpp @@ -1944,90 +1944,19 @@ std::string CFileItem::FindLocalArt(const std::string &artFile, bool useFolder) std::string thumb; if (!m_bIsFolder) { - thumb = GetLocalArt(artFile, false); + thumb = ART::GetLocalArt(*this, artFile, false); if (!thumb.empty() && CFile::Exists(thumb)) return thumb; } if ((useFolder || (m_bIsFolder && !IsFileFolder())) && !artFile.empty()) { - std::string thumb2 = GetLocalArt(artFile, true); + std::string thumb2 = ART::GetLocalArt(*this, artFile, true); if (!thumb2.empty() && thumb2 != thumb && CFile::Exists(thumb2)) return thumb2; } return ""; } -std::string CFileItem::GetLocalArtBaseFilename() const -{ - bool useFolder = false; - return GetLocalArtBaseFilename(useFolder); -} - -std::string CFileItem::GetLocalArtBaseFilename(bool& useFolder) const -{ - std::string strFile; - if (IsStack()) - { - std::string strPath; - URIUtils::GetParentPath(m_strPath,strPath); - strFile = URIUtils::AddFileToFolder( - strPath, URIUtils::GetFileName(CStackDirectory::GetStackedTitlePath(m_strPath))); - } - - std::string file = strFile.empty() ? m_strPath : strFile; - if (URIUtils::IsInRAR(file) || URIUtils::IsInZIP(file)) - { - std::string strPath = URIUtils::GetDirectory(file); - std::string strParent; - URIUtils::GetParentPath(strPath,strParent); - strFile = URIUtils::AddFileToFolder(strParent, URIUtils::GetFileName(file)); - } - - if (IsMultiPath()) - strFile = CMultiPathDirectory::GetFirstPath(m_strPath); - - if (IsOpticalMediaFile()) - { // optical media files should be treated like folders - useFolder = true; - strFile = GetLocalMetadataPath(); - } - else if (useFolder && !(m_bIsFolder && !IsFileFolder())) - { - file = strFile.empty() ? m_strPath : strFile; - strFile = URIUtils::GetDirectory(file); - } - - if (strFile.empty()) - strFile = GetDynPath(); - - return strFile; -} - -std::string CFileItem::GetLocalArt(const std::string& artFile, bool useFolder) const -{ - // no retrieving of empty art files from folders - if (useFolder && artFile.empty()) - return ""; - - std::string strFile = GetLocalArtBaseFilename(useFolder); - if (strFile.empty()) // empty filepath -> nothing to find - return ""; - - if (useFolder) - { - if (!artFile.empty()) - return URIUtils::AddFileToFolder(strFile, artFile); - } - else - { - if (artFile.empty()) // old thumbnail matching - return URIUtils::ReplaceExtension(strFile, ".tbn"); - else - return URIUtils::ReplaceExtension(strFile, "-" + artFile); - } - return ""; -} - std::string CFileItem::GetMovieName(bool bUseFolderNames /* = false */) const { if (IsPlugin() && HasVideoInfoTag() && !GetVideoInfoTag()->m_strTitle.empty()) diff --git a/xbmc/FileItem.h b/xbmc/FileItem.h index afaaf47c6a..635c964d8d 100644 --- a/xbmc/FileItem.h +++ b/xbmc/FileItem.h @@ -397,32 +397,6 @@ public: CPictureInfoTag* GetPictureInfoTag(); - /*! - \brief Assemble the base filename of local artwork for an item, - accounting for archives, stacks and multi-paths, and BDMV/VIDEO_TS folders. - `useFolder` is set to false - \return the path to the base filename for artwork lookup. - \sa GetLocalArt - */ - std::string GetLocalArtBaseFilename() const; - /*! - \brief Assemble the base filename of local artwork for an item, - accounting for archives, stacks and multi-paths, and BDMV/VIDEO_TS folders. - \param useFolder whether to look in the folder for the art file. Defaults to false. - \return the path to the base filename for artwork lookup. - \sa GetLocalArt - */ - std::string GetLocalArtBaseFilename(bool& useFolder) const; - - /*! \brief Assemble the filename of a particular piece of local artwork for an item. - No file existence check is typically performed. - \param artFile the art file to search for. - \param useFolder whether to look in the folder for the art file. Defaults to false. - \return the path to the local artwork. - \sa FindLocalArt - */ - std::string GetLocalArt(const std::string& artFile, bool useFolder = false) const; - /*! \brief Assemble the filename of a particular piece of local artwork for an item, and check for file existence. \param artFile the art file to search for. diff --git a/xbmc/pvr/PVRContextMenus.cpp b/xbmc/pvr/PVRContextMenus.cpp index 9ab47757f7..f882c9e624 100644 --- a/xbmc/pvr/PVRContextMenus.cpp +++ b/xbmc/pvr/PVRContextMenus.cpp @@ -81,6 +81,7 @@ DECL_STATICCONTEXTMENUITEM(ExecuteSearch); DECL_STATICCONTEXTMENUITEM(EditSearch); DECL_STATICCONTEXTMENUITEM(RenameSearch); DECL_STATICCONTEXTMENUITEM(ChooseIconForSearch); +DECL_STATICCONTEXTMENUITEM(DuplicateSearch); DECL_STATICCONTEXTMENUITEM(DeleteSearch); class PVRClientMenuHook : public IContextMenuItem @@ -749,6 +750,19 @@ bool ChooseIconForSearch::Execute(const std::shared_ptr<CFileItem>& item) const } /////////////////////////////////////////////////////////////////////////////// +// Duplicate a saved search + +bool DuplicateSearch::IsVisible(const CFileItem& item) const +{ + return item.HasEPGSearchFilter(); +} + +bool DuplicateSearch::Execute(const std::shared_ptr<CFileItem>& item) const +{ + return CServiceBroker::GetPVRManager().Get<PVR::GUI::EPG>().DuplicateSavedSearch(*item); +} + +/////////////////////////////////////////////////////////////////////////////// // Delete saved search bool DeleteSearch::IsVisible(const CFileItem& item) const @@ -794,6 +808,7 @@ CPVRContextMenuManager::CPVRContextMenuManager() std::make_shared<CONTEXTMENUITEM::EditSearch>(21450), /* Edit */ std::make_shared<CONTEXTMENUITEM::RenameSearch>(118), /* Rename */ std::make_shared<CONTEXTMENUITEM::ChooseIconForSearch>(19284), /* Choose icon */ + std::make_shared<CONTEXTMENUITEM::DuplicateSearch>(19355), /* Duplicate */ std::make_shared<CONTEXTMENUITEM::DeleteSearch>(117), /* Delete */ }) { diff --git a/xbmc/pvr/PVRDatabase.cpp b/xbmc/pvr/PVRDatabase.cpp index ec4428384c..84e7eb99c9 100644 --- a/xbmc/pvr/PVRDatabase.cpp +++ b/xbmc/pvr/PVRDatabase.cpp @@ -590,7 +590,7 @@ int CPVRDatabase::GetClientID(const std::string& addonID, unsigned int instanceI if (ExecuteQuery(sql)) return static_cast<int>(m_pDS->lastinsertid()); - return -1; + return PVR_CLIENT_INVALID_UID; } /********** Channel provider methods **********/ @@ -1306,7 +1306,8 @@ std::vector<std::shared_ptr<CPVRTimerInfoTag>> CPVRDatabase::GetTimers( newTag->m_iClientIndex = -m_pDS->fv("iClientIndex").get_asInt(); newTag->m_iParentClientIndex = m_pDS->fv("iParentClientIndex").get_asInt(); newTag->m_iClientId = m_pDS->fv("iClientId").get_asInt(); - newTag->SetTimerType(CPVRTimerType::CreateFromIds(m_pDS->fv("iTimerType").get_asInt(), -1)); + newTag->SetTimerType(CPVRTimerType::CreateFromIds(m_pDS->fv("iTimerType").get_asInt(), + PVR_CLIENT_INVALID_UID)); newTag->m_state = static_cast<PVR_TIMER_STATE>(m_pDS->fv("iState").get_asInt()); newTag->m_strTitle = m_pDS->fv("sTitle").get_asString().c_str(); newTag->m_iClientChannelUid = m_pDS->fv("iClientChannelUid").get_asInt(); diff --git a/xbmc/pvr/dialogs/GUIDialogPVRGuideSearch.cpp b/xbmc/pvr/dialogs/GUIDialogPVRGuideSearch.cpp index 90faa68af2..b5cb4cf64a 100644 --- a/xbmc/pvr/dialogs/GUIDialogPVRGuideSearch.cpp +++ b/xbmc/pvr/dialogs/GUIDialogPVRGuideSearch.cpp @@ -51,6 +51,8 @@ using namespace PVR; static constexpr int CONTROL_BTN_SAVE = 29; static constexpr int CONTROL_BTN_IGNORE_FINISHED = 30; static constexpr int CONTROL_BTN_IGNORE_FUTURE = 31; +static constexpr int CONTROL_BTN_START_ANY_TIME = 32; +static constexpr int CONTROL_BTN_END_ANY_TIME = 33; CGUIDialogPVRGuideSearch::CGUIDialogPVRGuideSearch() : CGUIDialog(WINDOW_DIALOG_PVR_GUIDE_SEARCH, "DialogPVRGuideSearch.xml") @@ -225,6 +227,12 @@ bool CGUIDialogPVRGuideSearch::OnMessage(CGUIMessage& message) UpdateChannelSpin(); return true; } + else if (iControl == CONTROL_BTN_START_ANY_TIME || iControl == CONTROL_BTN_END_ANY_TIME) + { + UpdateSearchFilter(); + Update(); + return true; + } } break; } @@ -316,6 +324,9 @@ void CGUIDialogPVRGuideSearch::UpdateSearchFilter() m_searchFilter->SetEndDateTime(end); m_endDateTime = end; } + + m_searchFilter->SetStartAnyTime(IsRadioSelected(CONTROL_BTN_START_ANY_TIME)); + m_searchFilter->SetEndAnyTime(IsRadioSelected(CONTROL_BTN_END_ANY_TIME)); } void CGUIDialogPVRGuideSearch::Update() @@ -340,6 +351,10 @@ void CGUIDialogPVRGuideSearch::Update() m_searchFilter->ShouldIgnoreFinishedBroadcasts()); SET_CONTROL_SELECTED(GetID(), CONTROL_BTN_IGNORE_FUTURE, m_searchFilter->ShouldIgnoreFutureBroadcasts()); + SET_CONTROL_SELECTED(GetID(), CONTROL_BTN_START_ANY_TIME, m_searchFilter->IsStartAnyTime()); + SET_CONTROL_SELECTED(GetID(), CONTROL_BTN_END_ANY_TIME, m_searchFilter->IsEndAnyTime()); + CONTROL_ENABLE_ON_CONDITION(CONTROL_EDIT_START_TIME, !m_searchFilter->IsStartAnyTime()); + CONTROL_ENABLE_ON_CONDITION(CONTROL_EDIT_STOP_TIME, !m_searchFilter->IsEndAnyTime()); // Set start/end datetime fields m_startDateTime = m_searchFilter->GetStartDateTime(); diff --git a/xbmc/pvr/epg/EpgDatabase.cpp b/xbmc/pvr/epg/EpgDatabase.cpp index 7c17c03909..17c4d4354d 100644 --- a/xbmc/pvr/epg/EpgDatabase.cpp +++ b/xbmc/pvr/epg/EpgDatabase.cpp @@ -130,7 +130,9 @@ void CPVREpgDatabase::CreateTables() "bIgnorePresentTimers bool, " "bIgnorePresentRecordings bool, " "iChannelGroup integer, " - "sIconPath varchar(255)" + "sIconPath varchar(255), " + "bStartAnyTime bool, " + "bEndAnyTime bool" ")"); } @@ -337,6 +339,14 @@ void CPVREpgDatabase::UpdateTables(int iVersion) m_pDS->exec("ALTER TABLE epgtags ADD sParentalRatingIcon varchar(512);"); m_pDS->exec("ALTER TABLE epgtags ADD sParentalRatingSource varchar(128);"); } + + if (iVersion < 19) + { + m_pDS->exec("ALTER TABLE savedsearches ADD bStartAnyTime bool;"); + m_pDS->exec("ALTER TABLE savedsearches ADD bEndAnyTime bool;"); + m_pDS->exec("UPDATE savedsearches SET bStartAnyTime = 1;"); + m_pDS->exec("UPDATE savedsearches SET bEndAnyTime = 1;"); + } } bool CPVREpgDatabase::DeleteEpg() @@ -694,11 +704,25 @@ std::vector<std::shared_ptr<CPVREpgInfoTag>> CPVREpgDatabase::GetEpgTags( // min start datetime ///////////////////////////////////////////////////////////////////////////////////////////// + static constexpr unsigned int ONE_DAY{60 * 60 * 24}; + if (searchData.m_startDateTime.IsValid()) { time_t minStart; searchData.m_startDateTime.GetAsTime(minStart); - filter.AppendWhere(PrepareSQL("iStartTime >= %u", static_cast<unsigned int>(minStart))); + + if (searchData.m_startAnyTime) + { + filter.AppendWhere(PrepareSQL("iStartTime >= %u", static_cast<unsigned int>(minStart))); + } + else + { + const unsigned int startDate{static_cast<unsigned int>(minStart) / ONE_DAY}; + filter.AppendWhere(PrepareSQL("(iStartTime / %u) >= %u", ONE_DAY, startDate)); + + const unsigned int startTime{static_cast<unsigned int>(minStart) % ONE_DAY}; + filter.AppendWhere(PrepareSQL("(iStartTime %% %u) >= %u", ONE_DAY, startTime)); + } } ///////////////////////////////////////////////////////////////////////////////////////////// @@ -709,7 +733,19 @@ std::vector<std::shared_ptr<CPVREpgInfoTag>> CPVREpgDatabase::GetEpgTags( { time_t maxEnd; searchData.m_endDateTime.GetAsTime(maxEnd); - filter.AppendWhere(PrepareSQL("iEndTime <= %u", static_cast<unsigned int>(maxEnd))); + + if (searchData.m_endAnyTime) + { + filter.AppendWhere(PrepareSQL("iEndTime <= %u", static_cast<unsigned int>(maxEnd))); + } + else + { + const unsigned int endDate{static_cast<unsigned int>(maxEnd) / ONE_DAY}; + filter.AppendWhere(PrepareSQL("(iEndTime / %u) <= %u", ONE_DAY, endDate)); + + const unsigned int endTime{static_cast<unsigned int>(maxEnd) % ONE_DAY}; + filter.AppendWhere(PrepareSQL("(iEndTime %% %u) <= %u", ONE_DAY, endTime)); + } } ///////////////////////////////////////////////////////////////////////////////////////////// @@ -1340,6 +1376,8 @@ std::shared_ptr<CPVREpgSearchFilter> CPVREpgDatabase::CreateEpgSearchFilter( newSearch->SetIgnorePresentRecordings(m_pDS->fv("bIgnorePresentRecordings").get_asBool()); newSearch->SetChannelGroupID(m_pDS->fv("iChannelGroup").get_asInt()); newSearch->SetIconPath(m_pDS->fv("sIconPath").get_asString()); + newSearch->SetStartAnyTime(m_pDS->fv("bStartAnyTime").get_asBool()); + newSearch->SetEndAnyTime(m_pDS->fv("bEndAnyTime").get_asBool()); newSearch->SetChanged(false); @@ -1404,16 +1442,16 @@ bool CPVREpgDatabase::Persist(CPVREpgSearchFilter& epgSearch) // Insert a new entry if this is a new search, replace the existing otherwise std::string strQuery; - if (epgSearch.GetDatabaseId() == -1) + if (epgSearch.GetDatabaseId() == PVR_EPG_SEARCH_INVALID_DATABASE_ID) strQuery = PrepareSQL( "INSERT INTO savedsearches " "(sTitle, sLastExecutedDateTime, sSearchTerm, bSearchInDescription, bIsCaseSensitive, " "iGenreType, bIncludeUnknownGenres, sStartDateTime, sEndDateTime, iMinimumDuration, " "iMaximumDuration, bIsRadio, iClientId, iChannelUid, bRemoveDuplicates, " "bIgnoreFinishedBroadcasts, bIgnoreFutureBroadcasts, bFreeToAirOnly, bIgnorePresentTimers, " - "bIgnorePresentRecordings, iChannelGroup, sIconPath) " + "bIgnorePresentRecordings, iChannelGroup, sIconPath, bStartAnyTime, bEndAnyTime) " "VALUES ('%s', '%s', '%s', %i, %i, %i, %i, '%s', '%s', %i, %i, %i, %i, %i, %i, %i, %i, " - "%i, %i, %i, %i, '%s');", + "%i, %i, %i, %i, '%s', %i, %i);", epgSearch.GetTitle().c_str(), epgSearch.GetLastExecutedDateTime().IsValid() ? epgSearch.GetLastExecutedDateTime().GetAsDBDateTime().c_str() @@ -1433,7 +1471,8 @@ bool CPVREpgDatabase::Persist(CPVREpgSearchFilter& epgSearch) epgSearch.ShouldIgnoreFutureBroadcasts() ? 1 : 0, epgSearch.IsFreeToAirOnly() ? 1 : 0, epgSearch.ShouldIgnorePresentTimers() ? 1 : 0, epgSearch.ShouldIgnorePresentRecordings() ? 1 : 0, epgSearch.GetChannelGroupID(), - epgSearch.GetIconPath().c_str()); + epgSearch.GetIconPath().c_str(), epgSearch.IsStartAnyTime() ? 1 : 0, + epgSearch.IsEndAnyTime() ? 1 : 0); else strQuery = PrepareSQL( "REPLACE INTO savedsearches " @@ -1441,9 +1480,9 @@ bool CPVREpgDatabase::Persist(CPVREpgSearchFilter& epgSearch) "bIsCaseSensitive, iGenreType, bIncludeUnknownGenres, sStartDateTime, sEndDateTime, " "iMinimumDuration, iMaximumDuration, bIsRadio, iClientId, iChannelUid, bRemoveDuplicates, " "bIgnoreFinishedBroadcasts, bIgnoreFutureBroadcasts, bFreeToAirOnly, bIgnorePresentTimers, " - "bIgnorePresentRecordings, iChannelGroup, sIconPath) " + "bIgnorePresentRecordings, iChannelGroup, sIconPath, bStartAnyTime, bEndAnyTime) " "VALUES (%i, '%s', '%s', '%s', %i, %i, %i, %i, '%s', '%s', %i, %i, %i, %i, %i, %i, %i, %i, " - "%i, %i, %i, %i, '%s');", + "%i, %i, %i, %i, '%s', %i, %i);", epgSearch.GetDatabaseId(), epgSearch.GetTitle().c_str(), epgSearch.GetLastExecutedDateTime().IsValid() ? epgSearch.GetLastExecutedDateTime().GetAsDBDateTime().c_str() @@ -1463,14 +1502,15 @@ bool CPVREpgDatabase::Persist(CPVREpgSearchFilter& epgSearch) epgSearch.ShouldIgnoreFutureBroadcasts() ? 1 : 0, epgSearch.IsFreeToAirOnly() ? 1 : 0, epgSearch.ShouldIgnorePresentTimers() ? 1 : 0, epgSearch.ShouldIgnorePresentRecordings() ? 1 : 0, epgSearch.GetChannelGroupID(), - epgSearch.GetIconPath().c_str()); + epgSearch.GetIconPath().c_str(), epgSearch.IsStartAnyTime() ? 1 : 0, + epgSearch.IsEndAnyTime() ? 1 : 0); bool bReturn = ExecuteQuery(strQuery); if (bReturn) { // Set the database id for searches persisted for the first time - if (epgSearch.GetDatabaseId() == -1) + if (epgSearch.GetDatabaseId() == PVR_EPG_SEARCH_INVALID_DATABASE_ID) epgSearch.SetDatabaseId(static_cast<int>(m_pDS->lastinsertid())); epgSearch.SetChanged(false); @@ -1481,7 +1521,7 @@ bool CPVREpgDatabase::Persist(CPVREpgSearchFilter& epgSearch) bool CPVREpgDatabase::UpdateSavedSearchLastExecuted(const CPVREpgSearchFilter& epgSearch) { - if (epgSearch.GetDatabaseId() == -1) + if (epgSearch.GetDatabaseId() == PVR_EPG_SEARCH_INVALID_DATABASE_ID) return false; std::unique_lock<CCriticalSection> lock(m_critSection); @@ -1494,7 +1534,7 @@ bool CPVREpgDatabase::UpdateSavedSearchLastExecuted(const CPVREpgSearchFilter& e bool CPVREpgDatabase::Delete(const CPVREpgSearchFilter& epgSearch) { - if (epgSearch.GetDatabaseId() == -1) + if (epgSearch.GetDatabaseId() == PVR_EPG_SEARCH_INVALID_DATABASE_ID) return false; CLog::LogFC(LOGDEBUG, LOGEPG, "Deleting saved search '{}' from the database", diff --git a/xbmc/pvr/epg/EpgDatabase.h b/xbmc/pvr/epg/EpgDatabase.h index cf114a1050..8ea846bf42 100644 --- a/xbmc/pvr/epg/EpgDatabase.h +++ b/xbmc/pvr/epg/EpgDatabase.h @@ -66,7 +66,7 @@ namespace PVR * @brief Get the minimal database version that is required to operate correctly. * @return The minimal database version. */ - int GetSchemaVersion() const override { return 18; } + int GetSchemaVersion() const override { return 19; } /*! * @brief Get the default sqlite database filename. diff --git a/xbmc/pvr/epg/EpgSearchData.h b/xbmc/pvr/epg/EpgSearchData.h index e5e6ef7057..c0ab72069a 100644 --- a/xbmc/pvr/epg/EpgSearchData.h +++ b/xbmc/pvr/epg/EpgSearchData.h @@ -25,8 +25,10 @@ struct PVREpgSearchData int m_iGenreType = EPG_SEARCH_UNSET; /*!< The genre type for an entry */ bool m_bIgnoreFinishedBroadcasts; /*!< True to ignore finished broadcasts, false if not */ bool m_bIgnoreFutureBroadcasts; /*!< True to ignore future broadcasts, false if not */ - CDateTime m_startDateTime; /*!< The minimum start time for an entry */ - CDateTime m_endDateTime; /*!< The maximum end time for an entry */ + CDateTime m_startDateTime; /*!< The minimum start date and time for an entry */ + CDateTime m_endDateTime; /*!< The maximum end date and time for an entry */ + bool m_startAnyTime{true}; /*!< Match any start time */ + bool m_endAnyTime{true}; /*!< Match any end time */ void Reset() { @@ -38,6 +40,8 @@ struct PVREpgSearchData m_bIgnoreFutureBroadcasts = false; m_startDateTime.SetValid(false); m_endDateTime.SetValid(false); + m_startAnyTime = true; + m_endAnyTime = true; } }; diff --git a/xbmc/pvr/epg/EpgSearchFilter.cpp b/xbmc/pvr/epg/EpgSearchFilter.cpp index 2425c0a1c5..b7533ce4c5 100644 --- a/xbmc/pvr/epg/EpgSearchFilter.cpp +++ b/xbmc/pvr/epg/EpgSearchFilter.cpp @@ -28,8 +28,7 @@ using namespace PVR; -CPVREpgSearchFilter::CPVREpgSearchFilter(bool bRadio) -: m_bIsRadio(bRadio) +CPVREpgSearchFilter::CPVREpgSearchFilter(bool bRadio) : m_bIsRadio(bRadio) { Reset(); } @@ -149,6 +148,15 @@ void CPVREpgSearchFilter::SetStartDateTime(const CDateTime& startDateTime) } } +void CPVREpgSearchFilter::SetStartAnyTime(bool startAnyTime) +{ + if (m_searchData.m_startAnyTime != startAnyTime) + { + m_searchData.m_startAnyTime = startAnyTime; + m_bChanged = true; + } +} + void CPVREpgSearchFilter::SetEndDateTime(const CDateTime& endDateTime) { if (m_searchData.m_endDateTime != endDateTime) @@ -158,6 +166,15 @@ void CPVREpgSearchFilter::SetEndDateTime(const CDateTime& endDateTime) } } +void CPVREpgSearchFilter::SetEndAnyTime(bool endAnyTime) +{ + if (m_searchData.m_endAnyTime != endAnyTime) + { + m_searchData.m_endAnyTime = endAnyTime; + m_bChanged = true; + } +} + void CPVREpgSearchFilter::SetIncludeUnknownGenres(bool bIncludeUnknownGenres) { if (m_searchData.m_bIncludeUnknownGenres != bIncludeUnknownGenres) @@ -348,7 +365,8 @@ void CPVREpgSearchFilter::RemoveDuplicates(std::vector<std::shared_ptr<CPVREpgIn for (auto it = results.begin(); it != results.end();) { it = results.erase(std::remove_if(results.begin(), results.end(), - [&it](const std::shared_ptr<const CPVREpgInfoTag>& entry) { + [&it](const std::shared_ptr<const CPVREpgInfoTag>& entry) + { return *it != entry && (*it)->Title() == entry->Title() && (*it)->Plot() == entry->Plot() && (*it)->PlotOutline() == entry->PlotOutline(); @@ -396,10 +414,12 @@ bool CPVREpgSearchFilter::MatchFreeToAir(const std::shared_ptr<const CPVREpgInfo bool CPVREpgSearchFilter::MatchTimers(const std::shared_ptr<const CPVREpgInfoTag>& tag) const { - return (!m_bIgnorePresentTimers || !CServiceBroker::GetPVRManager().Timers()->GetTimerForEpgTag(tag)); + return (!m_bIgnorePresentTimers || + !CServiceBroker::GetPVRManager().Timers()->GetTimerForEpgTag(tag)); } bool CPVREpgSearchFilter::MatchRecordings(const std::shared_ptr<const CPVREpgInfoTag>& tag) const { - return (!m_bIgnorePresentRecordings || !CServiceBroker::GetPVRManager().Recordings()->GetRecordingForEpgTag(tag)); + return (!m_bIgnorePresentRecordings || + !CServiceBroker::GetPVRManager().Recordings()->GetRecordingForEpgTag(tag)); } diff --git a/xbmc/pvr/epg/EpgSearchFilter.h b/xbmc/pvr/epg/EpgSearchFilter.h index f6cca5cf0c..960d89f472 100644 --- a/xbmc/pvr/epg/EpgSearchFilter.h +++ b/xbmc/pvr/epg/EpgSearchFilter.h @@ -18,156 +18,164 @@ namespace PVR { - class CPVREpgInfoTag; +static constexpr int PVR_EPG_SEARCH_INVALID_DATABASE_ID{-1}; - class CPVREpgSearchFilter - { - public: - CPVREpgSearchFilter() = delete; +class CPVREpgInfoTag; - /*! - * @brief ctor. - * @param bRadio the type of channels to search - if true, 'radio'. 'tv', otherwise. - */ - explicit CPVREpgSearchFilter(bool bRadio); +class CPVREpgSearchFilter +{ +public: + CPVREpgSearchFilter() = delete; + + /*! + * @brief ctor. + * @param bRadio the type of channels to search - if true, 'radio'. 'tv', otherwise. + */ + explicit CPVREpgSearchFilter(bool bRadio); + + /*! + * @brief Clear this filter. + */ + void Reset(); + + /*! + * @brief Return the path for this filter. + * @return the path. + */ + std::string GetPath() const; - /*! - * @brief Clear this filter. - */ - void Reset(); + /*! + * @brief Check if a tag will be filtered or not. + * @param tag The tag to check. + * @return True if this tag matches the filter, false if not. + */ + bool FilterEntry(const std::shared_ptr<const CPVREpgInfoTag>& tag) const; - /*! - * @brief Return the path for this filter. - * @return the path. - */ - std::string GetPath() const; + /*! + * @brief remove duplicates from a list of epg tags. + * @param results The list of epg tags. + */ + static void RemoveDuplicates(std::vector<std::shared_ptr<CPVREpgInfoTag>>& results); - /*! - * @brief Check if a tag will be filtered or not. - * @param tag The tag to check. - * @return True if this tag matches the filter, false if not. - */ - bool FilterEntry(const std::shared_ptr<const CPVREpgInfoTag>& tag) const; + /*! + * @brief Get the type of channels to search. + * @return true, if 'radio'. false, otherwise. + */ + bool IsRadio() const { return m_bIsRadio; } - /*! - * @brief remove duplicates from a list of epg tags. - * @param results The list of epg tags. - */ - static void RemoveDuplicates(std::vector<std::shared_ptr<CPVREpgInfoTag>>& results); + const std::string& GetSearchTerm() const { return m_searchData.m_strSearchTerm; } + void SetSearchTerm(const std::string& strSearchTerm); - /*! - * @brief Get the type of channels to search. - * @return true, if 'radio'. false, otherwise. - */ - bool IsRadio() const { return m_bIsRadio; } + void SetSearchPhrase(const std::string& strSearchPhrase); - const std::string& GetSearchTerm() const { return m_searchData.m_strSearchTerm; } - void SetSearchTerm(const std::string& strSearchTerm); + bool IsCaseSensitive() const { return m_bIsCaseSensitive; } + void SetCaseSensitive(bool bIsCaseSensitive); - void SetSearchPhrase(const std::string& strSearchPhrase); + bool ShouldSearchInDescription() const { return m_searchData.m_bSearchInDescription; } + void SetSearchInDescription(bool bSearchInDescription); - bool IsCaseSensitive() const { return m_bIsCaseSensitive; } - void SetCaseSensitive(bool bIsCaseSensitive); + int GetGenreType() const { return m_searchData.m_iGenreType; } + void SetGenreType(int iGenreType); - bool ShouldSearchInDescription() const { return m_searchData.m_bSearchInDescription; } - void SetSearchInDescription(bool bSearchInDescription); + int GetMinimumDuration() const { return m_iMinimumDuration; } + void SetMinimumDuration(int iMinimumDuration); - int GetGenreType() const { return m_searchData.m_iGenreType; } - void SetGenreType(int iGenreType); + int GetMaximumDuration() const { return m_iMaximumDuration; } + void SetMaximumDuration(int iMaximumDuration); - int GetMinimumDuration() const { return m_iMinimumDuration; } - void SetMinimumDuration(int iMinimumDuration); + bool ShouldIgnoreFinishedBroadcasts() const { return m_searchData.m_bIgnoreFinishedBroadcasts; } + void SetIgnoreFinishedBroadcasts(bool bIgnoreFinishedBroadcasts); - int GetMaximumDuration() const { return m_iMaximumDuration; } - void SetMaximumDuration(int iMaximumDuration); + bool ShouldIgnoreFutureBroadcasts() const { return m_searchData.m_bIgnoreFutureBroadcasts; } + void SetIgnoreFutureBroadcasts(bool bIgnoreFutureBroadcasts); - bool ShouldIgnoreFinishedBroadcasts() const { return m_searchData.m_bIgnoreFinishedBroadcasts; } - void SetIgnoreFinishedBroadcasts(bool bIgnoreFinishedBroadcasts); + const CDateTime& GetStartDateTime() const { return m_searchData.m_startDateTime; } + void SetStartDateTime(const CDateTime& startDateTime); - bool ShouldIgnoreFutureBroadcasts() const { return m_searchData.m_bIgnoreFutureBroadcasts; } - void SetIgnoreFutureBroadcasts(bool bIgnoreFutureBroadcasts); + bool IsStartAnyTime() const { return m_searchData.m_startAnyTime; } + void SetStartAnyTime(bool startAnyTime); - const CDateTime& GetStartDateTime() const { return m_searchData.m_startDateTime; } - void SetStartDateTime(const CDateTime& startDateTime); + const CDateTime& GetEndDateTime() const { return m_searchData.m_endDateTime; } + void SetEndDateTime(const CDateTime& endDateTime); - const CDateTime& GetEndDateTime() const { return m_searchData.m_endDateTime; } - void SetEndDateTime(const CDateTime& endDateTime); + bool IsEndAnyTime() const { return m_searchData.m_endAnyTime; } + void SetEndAnyTime(bool endAnyTime); - bool ShouldIncludeUnknownGenres() const { return m_searchData.m_bIncludeUnknownGenres; } - void SetIncludeUnknownGenres(bool bIncludeUnknownGenres); + bool ShouldIncludeUnknownGenres() const { return m_searchData.m_bIncludeUnknownGenres; } + void SetIncludeUnknownGenres(bool bIncludeUnknownGenres); - bool ShouldRemoveDuplicates() const { return m_bRemoveDuplicates; } - void SetRemoveDuplicates(bool bRemoveDuplicates); + bool ShouldRemoveDuplicates() const { return m_bRemoveDuplicates; } + void SetRemoveDuplicates(bool bRemoveDuplicates); - int GetClientID() const { return m_iClientID; } - void SetClientID(int iClientID); + int GetClientID() const { return m_iClientID; } + void SetClientID(int iClientID); - int GetChannelGroupID() const { return m_iChannelGroupID; } - void SetChannelGroupID(int iChannelGroupID); + int GetChannelGroupID() const { return m_iChannelGroupID; } + void SetChannelGroupID(int iChannelGroupID); - int GetChannelUID() const { return m_iChannelUID; } - void SetChannelUID(int iChannelUID); + int GetChannelUID() const { return m_iChannelUID; } + void SetChannelUID(int iChannelUID); - bool IsFreeToAirOnly() const { return m_bFreeToAirOnly; } - void SetFreeToAirOnly(bool bFreeToAirOnly); + bool IsFreeToAirOnly() const { return m_bFreeToAirOnly; } + void SetFreeToAirOnly(bool bFreeToAirOnly); - bool ShouldIgnorePresentTimers() const { return m_bIgnorePresentTimers; } - void SetIgnorePresentTimers(bool bIgnorePresentTimers); + bool ShouldIgnorePresentTimers() const { return m_bIgnorePresentTimers; } + void SetIgnorePresentTimers(bool bIgnorePresentTimers); - bool ShouldIgnorePresentRecordings() const { return m_bIgnorePresentRecordings; } - void SetIgnorePresentRecordings(bool bIgnorePresentRecordings); + bool ShouldIgnorePresentRecordings() const { return m_bIgnorePresentRecordings; } + void SetIgnorePresentRecordings(bool bIgnorePresentRecordings); - int GetDatabaseId() const { return m_iDatabaseId; } - void SetDatabaseId(int iDatabaseId); + int GetDatabaseId() const { return m_iDatabaseId; } + void SetDatabaseId(int iDatabaseId); - const std::string& GetTitle() const { return m_title; } - void SetTitle(const std::string& title); + const std::string& GetTitle() const { return m_title; } + void SetTitle(const std::string& title); - const std::string& GetIconPath() const { return m_iconPath; } - void SetIconPath(const std::string& iconPath); + const std::string& GetIconPath() const { return m_iconPath; } + void SetIconPath(const std::string& iconPath); - const CDateTime& GetLastExecutedDateTime() const { return m_lastExecutedDateTime; } - void SetLastExecutedDateTime(const CDateTime& lastExecutedDateTime); + const CDateTime& GetLastExecutedDateTime() const { return m_lastExecutedDateTime; } + void SetLastExecutedDateTime(const CDateTime& lastExecutedDateTime); - const PVREpgSearchData& GetEpgSearchData() const { return m_searchData; } - void SetEpgSearchDataFiltered() { m_bEpgSearchDataFiltered = true; } + const PVREpgSearchData& GetEpgSearchData() const { return m_searchData; } + void SetEpgSearchDataFiltered() { m_bEpgSearchDataFiltered = true; } - bool IsChanged() const { return m_bChanged; } - void SetChanged(bool bChanged) { m_bChanged = bChanged; } + bool IsChanged() const { return m_bChanged; } + void SetChanged(bool bChanged) { m_bChanged = bChanged; } - private: - bool MatchGenre(const std::shared_ptr<const CPVREpgInfoTag>& tag) const; - bool MatchDuration(const std::shared_ptr<const CPVREpgInfoTag>& tag) const; - bool MatchStartAndEndTimes(const std::shared_ptr<const CPVREpgInfoTag>& tag) const; - bool MatchSearchTerm(const std::shared_ptr<const CPVREpgInfoTag>& tag) const; - bool MatchChannel(const std::shared_ptr<const CPVREpgInfoTag>& tag) const; - bool MatchChannelGroup(const std::shared_ptr<const CPVREpgInfoTag>& tag) const; - bool MatchFreeToAir(const std::shared_ptr<const CPVREpgInfoTag>& tag) const; - bool MatchTimers(const std::shared_ptr<const CPVREpgInfoTag>& tag) const; - bool MatchRecordings(const std::shared_ptr<const CPVREpgInfoTag>& tag) const; +private: + bool MatchGenre(const std::shared_ptr<const CPVREpgInfoTag>& tag) const; + bool MatchDuration(const std::shared_ptr<const CPVREpgInfoTag>& tag) const; + bool MatchStartAndEndTimes(const std::shared_ptr<const CPVREpgInfoTag>& tag) const; + bool MatchSearchTerm(const std::shared_ptr<const CPVREpgInfoTag>& tag) const; + bool MatchChannel(const std::shared_ptr<const CPVREpgInfoTag>& tag) const; + bool MatchChannelGroup(const std::shared_ptr<const CPVREpgInfoTag>& tag) const; + bool MatchFreeToAir(const std::shared_ptr<const CPVREpgInfoTag>& tag) const; + bool MatchTimers(const std::shared_ptr<const CPVREpgInfoTag>& tag) const; + bool MatchRecordings(const std::shared_ptr<const CPVREpgInfoTag>& tag) const; - bool m_bChanged = false; + bool m_bChanged = false; - PVREpgSearchData m_searchData; - bool m_bEpgSearchDataFiltered = false; + PVREpgSearchData m_searchData; + bool m_bEpgSearchDataFiltered = false; - bool m_bIsCaseSensitive; /*!< Do a case sensitive search */ - int m_iMinimumDuration; /*!< The minimum duration for an entry */ - int m_iMaximumDuration; /*!< The maximum duration for an entry */ - bool m_bRemoveDuplicates; /*!< True to remove duplicate events, false if not */ + bool m_bIsCaseSensitive; /*!< Do a case sensitive search */ + int m_iMinimumDuration; /*!< The minimum duration for an entry */ + int m_iMaximumDuration; /*!< The maximum duration for an entry */ + bool m_bRemoveDuplicates; /*!< True to remove duplicate events, false if not */ - // PVR specific filters - bool m_bIsRadio; /*!< True to filter radio channels only, false to tv only */ - int m_iClientID = PVR_CLIENT_INVALID_UID; /*!< The client id */ - int m_iChannelGroupID{-1}; /*! The channel group id */ - int m_iChannelUID = -1; /*!< The channel uid */ - bool m_bFreeToAirOnly; /*!< Include free to air channels only */ - bool m_bIgnorePresentTimers; /*!< True to ignore currently present timers (future recordings), false if not */ - bool m_bIgnorePresentRecordings; /*!< True to ignore currently active recordings, false if not */ + // PVR specific filters + bool m_bIsRadio; /*!< True to filter radio channels only, false to tv only */ + int m_iClientID = PVR_CLIENT_INVALID_UID; /*!< The client id */ + int m_iChannelGroupID{-1}; /*!< The channel group id */ + int m_iChannelUID = -1; /*!< The channel uid */ + bool m_bFreeToAirOnly; /*!< Include free to air channels only */ + bool m_bIgnorePresentTimers; /*!< True to ignore currently present timers, false if not */ + bool m_bIgnorePresentRecordings; /*!< True to ignore currently active recordings, false if not */ - int m_iDatabaseId = -1; - std::string m_title; - std::string m_iconPath; - CDateTime m_lastExecutedDateTime; - }; -} + int m_iDatabaseId{PVR_EPG_SEARCH_INVALID_DATABASE_ID}; + std::string m_title; + std::string m_iconPath; + CDateTime m_lastExecutedDateTime; +}; +} // namespace PVR diff --git a/xbmc/pvr/guilib/PVRGUIActionsEPG.cpp b/xbmc/pvr/guilib/PVRGUIActionsEPG.cpp index 9b76bb7672..866c3987e8 100644 --- a/xbmc/pvr/guilib/PVRGUIActionsEPG.cpp +++ b/xbmc/pvr/guilib/PVRGUIActionsEPG.cpp @@ -30,6 +30,7 @@ #include "settings/Settings.h" #include "settings/SettingsComponent.h" #include "storage/MediaManager.h" +#include "utils/StringUtils.h" #include "utils/Variant.h" #include "utils/log.h" @@ -248,6 +249,24 @@ bool CPVRGUIActionsEPG::ChooseIconForSavedSearch(const CFileItem& item) return true; } +bool CPVRGUIActionsEPG::DuplicateSavedSearch(const CFileItem& item) +{ + const auto searchFilter{item.GetEPGSearchFilter()}; + + if (!searchFilter) + { + CLog::LogF(LOGERROR, "Wrong item type. No EPG search filter present."); + return false; + } + + const auto dupedSearchFilter{std::make_shared<CPVREpgSearchFilter>(*searchFilter)}; + dupedSearchFilter->SetDatabaseId(PVR_EPG_SEARCH_INVALID_DATABASE_ID); // force new db entry + dupedSearchFilter->SetTitle(StringUtils::Format(g_localizeStrings.Get(19356), // Copy of '<title>' + searchFilter->GetTitle())); + CServiceBroker::GetPVRManager().EpgContainer().PersistSavedSearch(*dupedSearchFilter); + return true; +} + bool CPVRGUIActionsEPG::DeleteSavedSearch(const CFileItem& item) { const auto searchFilter = item.GetEPGSearchFilter(); diff --git a/xbmc/pvr/guilib/PVRGUIActionsEPG.h b/xbmc/pvr/guilib/PVRGUIActionsEPG.h index 5041b1adc3..3f2ce6a1b5 100644 --- a/xbmc/pvr/guilib/PVRGUIActionsEPG.h +++ b/xbmc/pvr/guilib/PVRGUIActionsEPG.h @@ -76,6 +76,13 @@ public: bool ChooseIconForSavedSearch(const CFileItem& item); /*! + * @brief Duplicate a saved search. + * @param item The item containing a search filter. + * @return True on success, false otherwise. + */ + bool DuplicateSavedSearch(const CFileItem& item); + + /*! * @brief Delete a saved search. Opens confirmation dialog before deleting. * @param item The item containing a search filter. * @return True on success, false otherwise. diff --git a/xbmc/pvr/windows/GUIWindowPVRSearch.cpp b/xbmc/pvr/windows/GUIWindowPVRSearch.cpp index 356e65dcc0..50504e4628 100644 --- a/xbmc/pvr/windows/GUIWindowPVRSearch.cpp +++ b/xbmc/pvr/windows/GUIWindowPVRSearch.cpp @@ -455,7 +455,7 @@ void CGUIWindowPVRSearchBase::ExecuteSearch() } // Save if not a transient search - if (m_searchfilter->GetDatabaseId() != -1) + if (m_searchfilter->GetDatabaseId() != PVR_EPG_SEARCH_INVALID_DATABASE_ID) CServiceBroker::GetPVRManager().EpgContainer().UpdateSavedSearchLastExecuted(*m_searchfilter); } diff --git a/xbmc/test/TestFileItem.cpp b/xbmc/test/TestFileItem.cpp index e78ba27676..e5ca906ab8 100644 --- a/xbmc/test/TestFileItem.cpp +++ b/xbmc/test/TestFileItem.cpp @@ -42,63 +42,6 @@ AdvancedSettingsResetBase::AdvancedSettingsResetBase() settings->GetAdvancedSettings()->Initialize(*settingsMgr); } -class TestFileItemSpecifiedArtJpg : public AdvancedSettingsResetBase, - public WithParamInterface<TestFileData> -{ -}; - - -TEST_P(TestFileItemSpecifiedArtJpg, GetLocalArt) -{ - CFileItem item; - item.SetPath(GetParam().file); - std::string path = CURL(item.GetLocalArt("art.jpg", GetParam().use_folder)).Get(); - std::string compare = CURL(GetParam().base).Get(); - EXPECT_EQ(compare, path); -} - -const TestFileData MovieFiles[] = {{ "c:\\dir\\filename.avi", false, "c:\\dir\\filename-art.jpg" }, - { "c:\\dir\\filename.avi", true, "c:\\dir\\art.jpg" }, - { "/dir/filename.avi", false, "/dir/filename-art.jpg" }, - { "/dir/filename.avi", true, "/dir/art.jpg" }, - { "smb://somepath/file.avi", false, "smb://somepath/file-art.jpg" }, - { "smb://somepath/file.avi", true, "smb://somepath/art.jpg" }, - { "stack:///path/to/movie-cd1.avi , /path/to/movie-cd2.avi", false, "/path/to/movie-art.jpg" }, - { "stack:///path/to/movie-cd1.avi , /path/to/movie-cd2.avi", true, "/path/to/art.jpg" }, - { "stack:///path/to/movie_name/cd1/some_file1.avi , /path/to/movie_name/cd2/some_file2.avi", true, "/path/to/movie_name/art.jpg" }, - { "/home/user/TV Shows/Dexter/S1/1x01.avi", false, "/home/user/TV Shows/Dexter/S1/1x01-art.jpg" }, - { "/home/user/TV Shows/Dexter/S1/1x01.avi", true, "/home/user/TV Shows/Dexter/S1/art.jpg" }, - { "zip://g%3a%5cmultimedia%5cmovies%5cSphere%2ezip/Sphere.avi", false, "g:\\multimedia\\movies\\Sphere-art.jpg" }, - { "zip://g%3a%5cmultimedia%5cmovies%5cSphere%2ezip/Sphere.avi", true, "g:\\multimedia\\movies\\art.jpg" }, - { "/home/user/movies/movie_name/video_ts/VIDEO_TS.IFO", false, "/home/user/movies/movie_name/art.jpg" }, - { "/home/user/movies/movie_name/video_ts/VIDEO_TS.IFO", true, "/home/user/movies/movie_name/art.jpg" }, - { "/home/user/movies/movie_name/BDMV/index.bdmv", false, "/home/user/movies/movie_name/art.jpg" }, - { "/home/user/movies/movie_name/BDMV/index.bdmv", true, "/home/user/movies/movie_name/art.jpg" }}; - -INSTANTIATE_TEST_SUITE_P(MovieFiles, TestFileItemSpecifiedArtJpg, ValuesIn(MovieFiles)); - -class TestFileItemFallbackArt : public AdvancedSettingsResetBase, - public WithParamInterface<TestFileData> -{ -}; - -TEST_P(TestFileItemFallbackArt, GetLocalArt) -{ - CFileItem item; - item.SetPath(GetParam().file); - std::string path = CURL(item.GetLocalArt("", GetParam().use_folder)).Get(); - std::string compare = CURL(GetParam().base).Get(); - EXPECT_EQ(compare, path); -} - -const TestFileData NoArtFiles[] = {{ "c:\\dir\\filename.avi", false, "c:\\dir\\filename.tbn" }, - { "/dir/filename.avi", false, "/dir/filename.tbn" }, - { "smb://somepath/file.avi", false, "smb://somepath/file.tbn" }, - { "/home/user/TV Shows/Dexter/S1/1x01.avi", false, "/home/user/TV Shows/Dexter/S1/1x01.tbn" }, - { "zip://g%3a%5cmultimedia%5cmovies%5cSphere%2ezip/Sphere.avi", false, "g:\\multimedia\\movies\\Sphere.tbn" }}; - -INSTANTIATE_TEST_SUITE_P(NoArt, TestFileItemFallbackArt, ValuesIn(NoArtFiles)); - class TestFileItemBasePath : public AdvancedSettingsResetBase, public WithParamInterface<TestFileData> { diff --git a/xbmc/utils/ArtUtils.cpp b/xbmc/utils/ArtUtils.cpp index b1e90855fd..6394f6c7c8 100644 --- a/xbmc/utils/ArtUtils.cpp +++ b/xbmc/utils/ArtUtils.cpp @@ -178,6 +178,71 @@ std::string GetFolderThumb(const CFileItem& item, const std::string& folderJPG / return URIUtils::AddFileToFolder(strFolder, folderJPG); } +std::string GetLocalArt(const CFileItem& item, const std::string& artFile, bool useFolder) +{ + // no retrieving of empty art files from folders + if (useFolder && artFile.empty()) + return ""; + + std::string strFile = GetLocalArtBaseFilename(item, useFolder); + if (strFile.empty()) // empty filepath -> nothing to find + return ""; + + if (useFolder) + { + if (!artFile.empty()) + return URIUtils::AddFileToFolder(strFile, artFile); + } + else + { + if (artFile.empty()) // old thumbnail matching + return URIUtils::ReplaceExtension(strFile, ".tbn"); + else + return URIUtils::ReplaceExtension(strFile, "-" + artFile); + } + return ""; +} + +std::string GetLocalArtBaseFilename(const CFileItem& item, bool& useFolder) +{ + std::string strFile; + if (item.IsStack()) + { + std::string strPath; + URIUtils::GetParentPath(item.GetPath(), strPath); + strFile = URIUtils::AddFileToFolder( + strPath, URIUtils::GetFileName(CStackDirectory::GetStackedTitlePath(item.GetPath()))); + } + + std::string file = strFile.empty() ? item.GetPath() : strFile; + if (URIUtils::IsInRAR(file) || URIUtils::IsInZIP(file)) + { + std::string strPath = URIUtils::GetDirectory(file); + std::string strParent; + URIUtils::GetParentPath(strPath, strParent); + strFile = URIUtils::AddFileToFolder(strParent, URIUtils::GetFileName(file)); + } + + if (item.IsMultiPath()) + strFile = CMultiPathDirectory::GetFirstPath(item.GetPath()); + + if (item.IsOpticalMediaFile()) + { // optical media files should be treated like folders + useFolder = true; + strFile = item.GetLocalMetadataPath(); + } + else if (useFolder && !(item.m_bIsFolder && !item.IsFileFolder())) + { + file = strFile.empty() ? item.GetPath() : strFile; + strFile = URIUtils::GetDirectory(file); + } + + if (strFile.empty()) + strFile = item.GetDynPath(); + + return strFile; +} + std::string GetLocalFanart(const CFileItem& item) { if (VIDEO::IsVideoDb(item)) diff --git a/xbmc/utils/ArtUtils.h b/xbmc/utils/ArtUtils.h index 07671d28dd..99848308b2 100644 --- a/xbmc/utils/ArtUtils.h +++ b/xbmc/utils/ArtUtils.h @@ -26,6 +26,24 @@ void FillInDefaultIcon(CFileItem& item); */ std::string GetFolderThumb(const CFileItem& item, const std::string& folderJPG = "folder.jpg"); +/*! \brief Assemble the filename of a particular piece of local artwork for an item. + No file existence check is typically performed. + \param artFile the art file to search for. + \param useFolder whether to look in the folder for the art file. Defaults to false. + \return the path to the local artwork. + \sa FindLocalArt + */ +std::string GetLocalArt(const CFileItem& item, const std::string& artFile, bool useFolder = false); + +/*! + \brief Assemble the base filename of local artwork for an item, + accounting for archives, stacks and multi-paths, and BDMV/VIDEO_TS folders. + \param useFolder whether to look in the folder for the art file. Defaults to false. + \return the path to the base filename for artwork lookup. + \sa GetLocalArt + */ +std::string GetLocalArtBaseFilename(const CFileItem& item, bool& useFolder); + /*! \brief Get the local fanart for item if it exists \return path to the local fanart for this item, or empty if none exists diff --git a/xbmc/utils/test/TestArtUtils.cpp b/xbmc/utils/test/TestArtUtils.cpp index f373634e55..6f9f1967db 100644 --- a/xbmc/utils/test/TestArtUtils.cpp +++ b/xbmc/utils/test/TestArtUtils.cpp @@ -7,9 +7,14 @@ */ #include "FileItem.h" +#include "ServiceBroker.h" #include "URL.h" #include "filesystem/Directory.h" #include "platform/Filesystem.h" +#include "settings/AdvancedSettings.h" +#include "settings/Settings.h" +#include "settings/SettingsComponent.h" +#include "settings/lib/SettingsManager.h" #include "utils/ArtUtils.h" #include "utils/FileUtils.h" #include "utils/StringUtils.h" @@ -47,6 +52,47 @@ std::string unique_path(const std::string& input) return ret; } +class AdvancedSettingsResetBase : public testing::Test +{ +public: + AdvancedSettingsResetBase(); +}; + +AdvancedSettingsResetBase::AdvancedSettingsResetBase() +{ + // Force all advanced settings to be reset to defaults + const auto settings = CServiceBroker::GetSettingsComponent(); + CSettingsManager* settingsMgr = settings->GetSettings()->GetSettingsManager(); + settings->GetAdvancedSettings()->Uninitialize(*settingsMgr); + settings->GetAdvancedSettings()->Initialize(*settingsMgr); +} + +struct ArtFilenameTest +{ + std::string path; + std::string result; + bool isFolder = false; + bool result_folder = false; + bool force_use_folder = false; +}; + +class GetLocalArtBaseFilenameTest : public testing::WithParamInterface<ArtFilenameTest>, + public testing::Test +{ +}; + +const auto local_art_filename_tests = std::array{ + ArtFilenameTest{"/home/user/foo.avi", "/home/user/foo.avi"}, + ArtFilenameTest{"stack:///home/user/foo-cd1.avi , /home/user/foo-cd2.avi", + "/home/user/foo.avi"}, + ArtFilenameTest{"zip://%2fhome%2fuser%2fbar.zip/foo.avi", "/home/user/foo.avi"}, + ArtFilenameTest{"multipath://%2fhome%2fuser%2fbar%2f/%2fhome%2fuser%2ffoo%2f", + "/home/user/bar/", true, true}, + ArtFilenameTest{"/home/user/VIDEO_TS/VIDEO_TS.IFO", "/home/user/", false, true}, + ArtFilenameTest{"/home/user/BDMV/index.bdmv", "/home/user/", false, true}, + ArtFilenameTest{"/home/user/foo.avi", "/home/user/", false, true, true}, +}; + struct FanartTest { std::string path; @@ -147,6 +193,58 @@ class FolderThumbTest : public testing::WithParamInterface<FolderTest>, public t { }; +struct LocalArtTest +{ + std::string file; + std::string art; + bool use_folder; + std::string base; +}; + +const auto local_art_tests = std::array{ + LocalArtTest{"c:\\dir\\filename.avi", "art.jpg", false, "c:\\dir\\filename-art.jpg"}, + LocalArtTest{"c:\\dir\\filename.avi", "art.jpg", true, "c:\\dir\\art.jpg"}, + LocalArtTest{"/dir/filename.avi", "art.jpg", false, "/dir/filename-art.jpg"}, + LocalArtTest{"/dir/filename.avi", "art.jpg", true, "/dir/art.jpg"}, + LocalArtTest{"smb://somepath/file.avi", "art.jpg", false, "smb://somepath/file-art.jpg"}, + LocalArtTest{"smb://somepath/file.avi", "art.jpg", true, "smb://somepath/art.jpg"}, + LocalArtTest{"stack:///path/to/movie-cd1.avi , /path/to/movie-cd2.avi", "art.jpg", false, + "/path/to/movie-art.jpg"}, + LocalArtTest{"stack:///path/to/movie-cd1.avi , /path/to/movie-cd2.avi", "art.jpg", true, + "/path/to/art.jpg"}, + LocalArtTest{ + "stack:///path/to/movie_name/cd1/some_file1.avi , /path/to/movie_name/cd2/some_file2.avi", + "art.jpg", true, "/path/to/movie_name/art.jpg"}, + LocalArtTest{"/home/user/TV Shows/Dexter/S1/1x01.avi", "art.jpg", false, + "/home/user/TV Shows/Dexter/S1/1x01-art.jpg"}, + LocalArtTest{"/home/user/TV Shows/Dexter/S1/1x01.avi", "art.jpg", true, + "/home/user/TV Shows/Dexter/S1/art.jpg"}, + LocalArtTest{"zip://g%3a%5cmultimedia%5cmovies%5cSphere%2ezip/Sphere.avi", "art.jpg", false, + "g:\\multimedia\\movies\\Sphere-art.jpg"}, + LocalArtTest{"zip://g%3a%5cmultimedia%5cmovies%5cSphere%2ezip/Sphere.avi", "art.jpg", true, + "g:\\multimedia\\movies\\art.jpg"}, + LocalArtTest{"/home/user/movies/movie_name/video_ts/VIDEO_TS.IFO", "art.jpg", false, + "/home/user/movies/movie_name/art.jpg"}, + LocalArtTest{"/home/user/movies/movie_name/video_ts/VIDEO_TS.IFO", "art.jpg", true, + "/home/user/movies/movie_name/art.jpg"}, + LocalArtTest{"/home/user/movies/movie_name/BDMV/index.bdmv", "art.jpg", false, + "/home/user/movies/movie_name/art.jpg"}, + LocalArtTest{"/home/user/movies/movie_name/BDMV/index.bdmv", "art.jpg", true, + "/home/user/movies/movie_name/art.jpg"}, + LocalArtTest{"c:\\dir\\filename.avi", "", false, "c:\\dir\\filename.tbn"}, + LocalArtTest{"/dir/filename.avi", "", false, "/dir/filename.tbn"}, + LocalArtTest{"smb://somepath/file.avi", "", false, "smb://somepath/file.tbn"}, + LocalArtTest{"/home/user/TV Shows/Dexter/S1/1x01.avi", "", false, + "/home/user/TV Shows/Dexter/S1/1x01.tbn"}, + LocalArtTest{"zip://g%3a%5cmultimedia%5cmovies%5cSphere%2ezip/Sphere.avi", "", false, + "g:\\multimedia\\movies\\Sphere.tbn"}, +}; + +class TestLocalArt : public AdvancedSettingsResetBase, + public testing::WithParamInterface<LocalArtTest> +{ +}; + } // namespace TEST_P(FillInDefaultIconTest, FillInDefaultIcon) @@ -173,6 +271,30 @@ TEST_P(FolderThumbTest, GetFolderThumb) INSTANTIATE_TEST_SUITE_P(TestArtUtils, FolderThumbTest, testing::ValuesIn(folder_thumb_tests)); +TEST_P(TestLocalArt, GetLocalArt) +{ + CFileItem item; + item.SetPath(GetParam().file); + std::string path = CURL(ART::GetLocalArt(item, GetParam().art, GetParam().use_folder)).Get(); + std::string compare = CURL(GetParam().base).Get(); + EXPECT_EQ(compare, path); +} + +INSTANTIATE_TEST_SUITE_P(TestArtUtils, TestLocalArt, testing::ValuesIn(local_art_tests)); + +TEST_P(GetLocalArtBaseFilenameTest, GetLocalArtBaseFilename) +{ + CFileItem item(GetParam().path, GetParam().isFolder); + bool useFolder = GetParam().force_use_folder ? true : GetParam().isFolder; + const std::string res = ART::GetLocalArtBaseFilename(item, useFolder); + EXPECT_EQ(res, GetParam().result); + EXPECT_EQ(useFolder, GetParam().result_folder); +} + +INSTANTIATE_TEST_SUITE_P(TestArtUtils, + GetLocalArtBaseFilenameTest, + testing::ValuesIn(local_art_filename_tests)); + TEST_P(GetLocalFanartTest, GetLocalFanart) { std::string path, file_path, uniq; diff --git a/xbmc/video/VideoDatabase.cpp b/xbmc/video/VideoDatabase.cpp index e4e51a7f86..f333bb334b 100644 --- a/xbmc/video/VideoDatabase.cpp +++ b/xbmc/video/VideoDatabase.cpp @@ -10748,7 +10748,7 @@ void CVideoDatabase::ExportToXML(const std::string &path, bool singleFile /* = t } for (const auto &i : artwork) { - std::string savedThumb = item.GetLocalArt(i.first, false); + std::string savedThumb = ART::GetLocalArt(item, i.first, false); CServiceBroker::GetTextureCache()->Export(i.second, savedThumb, overwrite); } if (actorThumbs) @@ -10894,7 +10894,7 @@ void CVideoDatabase::ExportToXML(const std::string &path, bool singleFile /* = t } for (const auto &i : artwork) { - std::string savedThumb = item.GetLocalArt(i.first, false); + std::string savedThumb = ART::GetLocalArt(item, i.first, false); CServiceBroker::GetTextureCache()->Export(i.second, savedThumb, overwrite); } } @@ -10992,7 +10992,7 @@ void CVideoDatabase::ExportToXML(const std::string &path, bool singleFile /* = t for (const auto &i : artwork) { - std::string savedThumb = item.GetLocalArt(i.first, true); + std::string savedThumb = ART::GetLocalArt(item, i.first, true); CServiceBroker::GetTextureCache()->Export(i.second, savedThumb, overwrite); } @@ -11011,7 +11011,7 @@ void CVideoDatabase::ExportToXML(const std::string &path, bool singleFile /* = t seasonThumb = StringUtils::Format("season{:02}", i.first); for (const auto &j : i.second) { - std::string savedThumb(item.GetLocalArt(seasonThumb + "-" + j.first, true)); + std::string savedThumb(ART::GetLocalArt(item, seasonThumb + "-" + j.first, true)); if (!i.second.empty()) CServiceBroker::GetTextureCache()->Export(j.second, savedThumb, overwrite); } @@ -11094,7 +11094,7 @@ void CVideoDatabase::ExportToXML(const std::string &path, bool singleFile /* = t } for (const auto &i : artwork) { - std::string savedThumb = item.GetLocalArt(i.first, false); + std::string savedThumb = ART::GetLocalArt(item, i.first, false); CServiceBroker::GetTextureCache()->Export(i.second, savedThumb, overwrite); } if (actorThumbs) diff --git a/xbmc/video/VideoInfoScanner.cpp b/xbmc/video/VideoInfoScanner.cpp index 9dc3588a5c..c02ee60282 100644 --- a/xbmc/video/VideoInfoScanner.cpp +++ b/xbmc/video/VideoInfoScanner.cpp @@ -38,6 +38,7 @@ #include "settings/Settings.h" #include "settings/SettingsComponent.h" #include "tags/VideoInfoTagLoaderFactory.h" +#include "utils/ArtUtils.h" #include "utils/Digest.h" #include "utils/FileExtensionProvider.h" #include "utils/RegExp.h" @@ -1792,14 +1793,21 @@ namespace KODI::VIDEO { if (!pItem->SkipLocalArt()) { + bool useFolder = false; if (bApplyToDir && (content == CONTENT_MOVIES || content == CONTENT_MUSICVIDEOS)) { - std::string filename = pItem->GetLocalArtBaseFilename(); + std::string filename = ART::GetLocalArtBaseFilename(*pItem, useFolder); std::string directory = URIUtils::GetDirectory(filename); if (filename != directory) AddLocalItemArtwork(art, artTypes, directory, addAll, exactName); } - AddLocalItemArtwork(art, artTypes, pItem->GetLocalArtBaseFilename(), addAll, exactName); + + // Reset useFolder to false as GetLocalArtBaseFilename may modify it in + // the previous call. + useFolder = false; + + AddLocalItemArtwork(art, artTypes, ART::GetLocalArtBaseFilename(*pItem, useFolder), addAll, + exactName); } if (moviePartOfSet) |