aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--addons/resource.language.en_gb/resources/strings.po22
-rw-r--r--addons/skin.estuary/xml/DialogVideoVersion.xml4
-rw-r--r--addons/skin.estuary/xml/Includes_DialogVideoVersion.xml6
-rw-r--r--cmake/modules/FindPCRE.cmake59
-rwxr-xr-xsystem/settings/settings.xml10
-rw-r--r--tools/depends/native/python3/PYTHON3-VERSION4
-rw-r--r--tools/depends/target/curl/CURL-VERSION4
-rw-r--r--tools/depends/target/pcre/004-win-pdb.patch4
-rw-r--r--tools/depends/target/python3/PYTHON3-VERSION4
-rw-r--r--xbmc/ContextMenuManager.cpp1
-rw-r--r--xbmc/Util.cpp46
-rw-r--r--xbmc/Util.h7
-rw-r--r--xbmc/addons/Scraper.cpp60
-rw-r--r--xbmc/addons/Scraper.h7
-rw-r--r--xbmc/favourites/GUIWindowFavourites.cpp42
-rw-r--r--xbmc/filesystem/FTPParse.cpp521
-rw-r--r--xbmc/filesystem/FTPParse.h1
-rw-r--r--xbmc/games/controllers/ControllerTranslator.cpp4
-rw-r--r--xbmc/guilib/GUIWindowManager.cpp4
-rw-r--r--xbmc/guilib/WindowIDs.h2
-rw-r--r--xbmc/input/WindowTranslator.cpp2
-rw-r--r--xbmc/input/XBMC_keysym.h5
-rw-r--r--xbmc/interfaces/builtins/PlayerBuiltins.cpp6
-rw-r--r--xbmc/listproviders/DirectoryProvider.cpp56
-rw-r--r--xbmc/network/DNSNameCache.cpp15
-rw-r--r--xbmc/pvr/dialogs/GUIDialogPVRGuideInfo.cpp5
-rw-r--r--xbmc/pvr/dialogs/GUIDialogPVRRecordingInfo.cpp4
-rw-r--r--xbmc/pvr/guilib/PVRGUIActionsPlayback.cpp6
-rw-r--r--xbmc/pvr/guilib/PVRGUIRecordingsPlayActionProcessor.h6
-rw-r--r--xbmc/pvr/windows/GUIWindowPVRRecordings.cpp42
-rw-r--r--xbmc/settings/AdvancedSettings.cpp2
-rw-r--r--xbmc/settings/AdvancedSettings.h1
-rw-r--r--xbmc/settings/Settings.h2
-rw-r--r--xbmc/test/TestUtil.cpp17
-rw-r--r--xbmc/utils/LangCodeExpander.cpp3
-rw-r--r--xbmc/utils/LangCodeExpander.h2
-rw-r--r--xbmc/video/ContextMenus.cpp179
-rw-r--r--xbmc/video/ContextMenus.h7
-rw-r--r--xbmc/video/VideoDatabase.cpp3
-rw-r--r--xbmc/video/VideoInfoDownloader.cpp14
-rw-r--r--xbmc/video/VideoInfoDownloader.h6
-rw-r--r--xbmc/video/VideoInfoScanner.cpp94
-rw-r--r--xbmc/video/VideoInfoScanner.h7
-rw-r--r--xbmc/video/dialogs/GUIDialogVideoInfo.cpp38
-rw-r--r--xbmc/video/dialogs/GUIDialogVideoVersion.cpp193
-rw-r--r--xbmc/video/dialogs/GUIDialogVideoVersion.h34
-rw-r--r--xbmc/video/guilib/CMakeLists.txt9
-rw-r--r--xbmc/video/guilib/VideoAction.h29
-rw-r--r--xbmc/video/guilib/VideoActionProcessorHelper.cpp161
-rw-r--r--xbmc/video/guilib/VideoActionProcessorHelper.h44
-rw-r--r--xbmc/video/guilib/VideoPlayAction.h24
-rw-r--r--xbmc/video/guilib/VideoPlayActionProcessor.cpp54
-rw-r--r--xbmc/video/guilib/VideoPlayActionProcessor.h27
-rw-r--r--xbmc/video/guilib/VideoSelectAction.h29
-rw-r--r--xbmc/video/guilib/VideoSelectActionProcessor.cpp88
-rw-r--r--xbmc/video/guilib/VideoSelectActionProcessor.h32
-rw-r--r--xbmc/video/windows/GUIWindowVideoBase.cpp48
-rw-r--r--xbmc/video/windows/GUIWindowVideoBase.h4
58 files changed, 1223 insertions, 887 deletions
diff --git a/addons/resource.language.en_gb/resources/strings.po b/addons/resource.language.en_gb/resources/strings.po
index 05e898b52d..296c4039e1 100644
--- a/addons/resource.language.en_gb/resources/strings.po
+++ b/addons/resource.language.en_gb/resources/strings.po
@@ -23868,22 +23868,22 @@ msgctxt "#40022"
msgid "Manage {0:s}"
msgstr ""
-#. Play video version dialog title
+#. Choose video version dialog title
#: xbmc/video/dialogs/GUIDialogVideoVersion.cpp
msgctxt "#40023"
-msgid "Play {0:s}"
+msgid "Choose {0:s}"
msgstr ""
-#. Play default video version setting
+#. Select default video version setting
#: system/settings/settings.xml
msgctxt "#40200"
-msgid "Play default video version"
+msgid "Select default video version"
msgstr ""
-#. Help for play default video version setting
+#. Help for select default video version setting
#: system/settings/settings.xml
msgctxt "#40201"
-msgid "Select player action for video with multiple versions.[CR][Enabled] Automatically play the default video version without prompting.[CR][Disabled] Always display a dialogue to select the preferred video version."
+msgid "Defines how to handle selection of videos with multiple versions.[CR][Enabled] Automatically select the default video version without prompting.[CR][Disabled] Display a dialogue to select a version of the video."
msgstr ""
#. Ignore different video versions settting
@@ -23919,9 +23919,17 @@ msgstr ""
#. Help for show video versions as folder settting
#: system/settings/settings.xml
msgctxt "#40207"
-msgid "When enabled, video with multiple versions will be shown as folder in library, this folder can then be opened to display the individual video versions. When disabled, a video version dialog will be opened for the video."
+msgid "When enabled, a video with multiple versions will be shown as a folder in the video library. This folder can then be opened to display the individual video versions. When disabled, the configured select action will be applied."
msgstr ""
+#. Choose video version context menu item label
+#: xbmc/video/ContextMenus.h
+msgctxt "#40208"
+msgid "Choose version"
+msgstr ""
+
+#empty strings from id 40209 to 40399
+
# Video versions
#. Name of a video version, like "Director's Cut"
diff --git a/addons/skin.estuary/xml/DialogVideoVersion.xml b/addons/skin.estuary/xml/DialogVideoVersion.xml
index 2c50812913..9a109ca028 100644
--- a/addons/skin.estuary/xml/DialogVideoVersion.xml
+++ b/addons/skin.estuary/xml/DialogVideoVersion.xml
@@ -1,10 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<window>
<defaultcontrol always="true">200</defaultcontrol>
- <onload condition="Window.IsActive(videoversionplay)">Control.SetFocus(50)</onload>
+ <onload condition="Window.IsActive(videoversionselect)">Control.SetFocus(50)</onload>
<include>Animation_DialogPopupOpenClose</include>
<controls>
<include condition="Window.IsActive(videoversion)">DialogVideoVersionLayout</include>
- <include condition="Window.IsActive(videoversionplay)">DialogVideoVersionPlayLayout</include>
+ <include condition="Window.IsActive(videoversionselect)">DialogVideoVersionSelectLayout</include>
</controls>
</window>
diff --git a/addons/skin.estuary/xml/Includes_DialogVideoVersion.xml b/addons/skin.estuary/xml/Includes_DialogVideoVersion.xml
index d6180c8f1b..4f7163c048 100644
--- a/addons/skin.estuary/xml/Includes_DialogVideoVersion.xml
+++ b/addons/skin.estuary/xml/Includes_DialogVideoVersion.xml
@@ -57,7 +57,7 @@
</control>
</control>
</include>
- <include name="DialogVideoVersionPlayLayout">
+ <include name="DialogVideoVersionSelectLayout">
<control type="group">
<centertop>50%</centertop>
<centerleft>50%</centerleft>
@@ -85,13 +85,13 @@
<param name="id" value="201" />
<param name="label" value="$LOCALIZE[40000]" />
<param name="usealttexture" value="Control.IsVisible(50)" />
- <param name="visible">Window.IsActive(videoversion)| Window.IsActive(videoversionplay) + Integer.IsGreater(Container(50).NumItems,0)</param>
+ <param name="visible">Window.IsActive(videoversion)| Window.IsActive(videoversionselect) + Integer.IsGreater(Container(50).NumItems,0)</param>
</include>
<include content="DialogToggleButton">
<param name="id" value="202" />
<param name="label" value="$LOCALIZE[31615]" />
<param name="usealttexture" value="Control.IsVisible(51)" />
- <param name="visible">Window.IsActive(videoversion) | Window.IsActive(videoversionplay) + Integer.IsGreater(Container(51).NumItems,0)</param>
+ <param name="visible">Window.IsActive(videoversion) | Window.IsActive(videoversionselect) + Integer.IsGreater(Container(51).NumItems,0)</param>
</include>
</control>
<control type="image">
diff --git a/cmake/modules/FindPCRE.cmake b/cmake/modules/FindPCRE.cmake
index 3ef52a2f25..811aa3fcb2 100644
--- a/cmake/modules/FindPCRE.cmake
+++ b/cmake/modules/FindPCRE.cmake
@@ -1,11 +1,10 @@
#.rst:
# FindPCRE
# --------
-# Finds the PCRECPP library
+# Finds the PCRE library
#
# This will define the following targets:
#
-# PCRE::PCRECPP - The PCRECPP library
# PCRE::PCRE - The PCRE library
macro(buildPCRE)
@@ -44,15 +43,11 @@ macro(buildPCRE)
list(APPEND CMAKE_ARGS -DHAVE_STRTOQ=0)
endif()
- # populate PCRECPP lib without a separate module
+ # populate PCRE lib without a separate module
if(NOT CORE_SYSTEM_NAME MATCHES windows)
# Non windows platforms have a lib prefix for the lib artifact
set(_libprefix "lib")
endif()
- # regex used to get platform extension (eg lib for windows, .a for unix)
- string(REGEX REPLACE "^.*\\." "" _LIBEXT ${${MODULE}_BYPRODUCT})
- set(PCRECPP_LIBRARY_DEBUG ${DEP_LOCATION}/lib/${_libprefix}pcrecpp${${MODULE}_DEBUG_POSTFIX}.${_LIBEXT})
- set(PCRECPP_LIBRARY_RELEASE ${DEP_LOCATION}/lib/${_libprefix}pcrecpp.${_LIBEXT})
BUILD_DEP_TARGET()
endmacro()
@@ -78,25 +73,17 @@ if(NOT PCRE::pcre)
else()
if(NOT TARGET PCRE::pcre)
if(PKG_CONFIG_FOUND)
- pkg_check_modules(PC_PCRE pcre pcrecpp QUIET)
+ pkg_check_modules(PC_PCRE pcre QUIET)
endif()
- find_path(PCRE_INCLUDE_DIR pcrecpp.h
+ find_path(PCRE_INCLUDE_DIR pcre.h
HINTS ${DEPENDS_PATH}/include ${PC_PCRE_INCLUDEDIR}
${${CORE_PLATFORM_NAME_LC}_SEARCH_CONFIG}
NO_CACHE)
- find_library(PCRECPP_LIBRARY_RELEASE NAMES pcrecpp
- HINTS ${DEPENDS_PATH}/lib ${PC_PCRE_LIBDIR}
- ${${CORE_PLATFORM_NAME_LC}_SEARCH_CONFIG}
- NO_CACHE)
find_library(PCRE_LIBRARY_RELEASE NAMES pcre
HINTS ${DEPENDS_PATH}/lib ${PC_PCRE_LIBDIR}
${${CORE_PLATFORM_NAME_LC}_SEARCH_CONFIG}
NO_CACHE)
- find_library(PCRECPP_LIBRARY_DEBUG NAMES pcrecppd
- HINTS ${DEPENDS_PATH}/lib ${PC_PCRE_LIBDIR}
- ${${CORE_PLATFORM_NAME_LC}_SEARCH_CONFIG}
- NO_CACHE)
find_library(PCRE_LIBRARY_DEBUG NAMES pcred
HINTS ${DEPENDS_PATH}/lib ${PC_PCRE_LIBDIR}
${${CORE_PLATFORM_NAME_LC}_SEARCH_CONFIG}
@@ -116,27 +103,14 @@ if(NOT PCRE::pcre)
endif()
endforeach()
- get_target_property(_PCRECPP_CONFIGURATIONS PCRE::pcrecpp IMPORTED_CONFIGURATIONS)
- foreach(_pcrecpp_config IN LISTS _PCRECPP_CONFIGURATIONS)
- # Just set to RELEASE var so select_library_configurations can continue to work its magic
- if((NOT ${_pcrecpp_config} STREQUAL "RELEASE") AND
- (NOT ${_pcrecpp_config} STREQUAL "DEBUG"))
- get_target_property(PCRECPP_LIBRARY_RELEASE PCRE::pcrecpp IMPORTED_LOCATION_${_pcrecpp_config})
- else()
- get_target_property(PCRECPP_LIBRARY_${_pcrecpp_config} PCRE::pcrecpp IMPORTED_LOCATION_${_pcrecpp_config})
- endif()
- endforeach()
-
# ToDo: patch PCRE cmake to include includedir in config file
- find_path(PCRE_INCLUDE_DIR pcrecpp.h
+ find_path(PCRE_INCLUDE_DIR pcre.h
HINTS ${DEPENDS_PATH}/include ${PC_PCRE_INCLUDEDIR}
${${CORE_PLATFORM_NAME_LC}_SEARCH_CONFIG}
NO_CACHE)
set_target_properties(PCRE::pcre PROPERTIES
INTERFACE_INCLUDE_DIRECTORIES "${PCRE_INCLUDE_DIR}")
- set_target_properties(PCRE::pcrecpp PROPERTIES
- INTERFACE_INCLUDE_DIRECTORIES "${PCRE_INCLUDE_DIR}")
endif()
endif()
@@ -145,14 +119,12 @@ if(NOT PCRE::pcre)
endif()
include(SelectLibraryConfigurations)
- select_library_configurations(PCRECPP)
select_library_configurations(PCRE)
- unset(PCRECPP_LIBRARIES)
unset(PCRE_LIBRARIES)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(PCRE
- REQUIRED_VARS PCRECPP_LIBRARY PCRE_LIBRARY PCRE_INCLUDE_DIR
+ REQUIRED_VARS PCRE_LIBRARY PCRE_INCLUDE_DIR
VERSION_VAR PCRE_VERSION)
if(PCRE_FOUND)
@@ -171,33 +143,15 @@ if(NOT PCRE::pcre)
set_target_properties(PCRE::pcre PROPERTIES
INTERFACE_INCLUDE_DIRECTORIES "${PCRE_INCLUDE_DIR}")
endif()
- if(NOT TARGET PCRE::pcrecpp)
- add_library(PCRE::pcrecpp UNKNOWN IMPORTED)
- if(PCRECPP_LIBRARY_RELEASE)
- set_target_properties(PCRE::pcrecpp PROPERTIES
- IMPORTED_CONFIGURATIONS RELEASE
- IMPORTED_LOCATION_RELEASE "${PCRECPP_LIBRARY_RELEASE}")
- endif()
- if(PCRECPP_LIBRARY_DEBUG)
- set_target_properties(PCRE::pcrecpp PROPERTIES
- IMPORTED_CONFIGURATIONS DEBUG
- IMPORTED_LOCATION_DEBUG "${PCRECPP_LIBRARY_DEBUG}")
- endif()
- set_target_properties(PCRE::pcrecpp PROPERTIES
- INTERFACE_INCLUDE_DIRECTORIES "${PCRE_INCLUDE_DIR}")
- endif()
# Wee need to explicitly add this define. The cmake config does not propagate this info
if(WIN32)
set_property(TARGET PCRE::pcre APPEND PROPERTY
INTERFACE_COMPILE_DEFINITIONS "PCRE_STATIC=1")
- set_property(TARGET PCRE::pcrecpp APPEND PROPERTY
- INTERFACE_COMPILE_DEFINITIONS "PCRE_STATIC=1")
endif()
if(TARGET pcre)
add_dependencies(PCRE::pcre pcre)
- add_dependencies(PCRE::pcrecpp pcre)
endif()
# Add internal build target when a Multi Config Generator is used
@@ -217,7 +171,6 @@ if(NOT PCRE::pcre)
endif()
set_property(GLOBAL APPEND PROPERTY INTERNAL_DEPS_PROP PCRE::pcre)
- set_property(GLOBAL APPEND PROPERTY INTERNAL_DEPS_PROP PCRE::pcrecpp)
endif()
endif()
diff --git a/system/settings/settings.xml b/system/settings/settings.xml
index 826f1ea708..6330fafad4 100755
--- a/system/settings/settings.xml
+++ b/system/settings/settings.xml
@@ -21,11 +21,6 @@
<hidevalue>false</hidevalue>
</control>
</setting>
- <setting id="videoplayer.playdefaultversion" type="boolean" label="40200" help="40201">
- <level>0</level>
- <default>false</default>
- <control type="toggle" />
- </setting>
<setting id="videoplayer.seeksteps" type="list[integer]" label="13556" help="37042">
<level>1</level>
<default>-600,-300,-180,-60,-30,-10,10,30,60,180,300,600</default>
@@ -1030,6 +1025,11 @@
</constraints>
<control type="list" format="string" />
</setting>
+ <setting id="myvideos.selectdefaultversion" type="boolean" label="40200" help="40201">
+ <level>0</level>
+ <default>false</default>
+ <control type="toggle" />
+ </setting>
<setting id="myvideos.playaction" type="integer" label="22076" help="36204">
<level>0</level>
<default>1</default> <!-- PLAY_ACTION_PLAY_OR_RESUME -->
diff --git a/tools/depends/native/python3/PYTHON3-VERSION b/tools/depends/native/python3/PYTHON3-VERSION
index 877902c5ef..c5e1760fb2 100644
--- a/tools/depends/native/python3/PYTHON3-VERSION
+++ b/tools/depends/native/python3/PYTHON3-VERSION
@@ -1,4 +1,4 @@
LIBNAME=Python
-VERSION=3.11.6
+VERSION=3.11.7
ARCHIVE=$(LIBNAME)-$(VERSION).tar.xz
-SHA512=94b1038f6f53de0c44f99f72ed0f2e0791fd9d2a325ae00ba145b2b2c332c27b300b3ea3473017518089478f15e01867b1bb203c16610039cce36f8366de341a
+SHA512=11e06f2ffe1f66888cb5b4e9f607de815294d6863a77eda6ec6d7c724ef158df9f51881f4a956d4a6fa973c2fb6fd031d495e3496e9b0bb53793fb1cc8434c63
diff --git a/tools/depends/target/curl/CURL-VERSION b/tools/depends/target/curl/CURL-VERSION
index 10caf28174..42bdd1d64f 100644
--- a/tools/depends/target/curl/CURL-VERSION
+++ b/tools/depends/target/curl/CURL-VERSION
@@ -1,5 +1,5 @@
LIBNAME=curl
-VERSION=8.1.2
+VERSION=8.4.0
ARCHIVE=$(LIBNAME)-$(VERSION).tar.xz
-SHA512=532ab96eba6dea66d272f3be56f5af5c5da922480f9a10e203de98037c311f12f8145ba6bf813831e42815e068874ccfd108f84f7650743f5dbb3ebc3bc9c4f4
+SHA512=7027dbf3b759b39d6ec9c4da58fadd254e84bb93bff599541b3bc3135bad4c2955c6237d7ddd60973f9f1a6948bc32d7e312985fb50658bc958b9f22fee74f2b
BYPRODUCT=libcurl.a
diff --git a/tools/depends/target/pcre/004-win-pdb.patch b/tools/depends/target/pcre/004-win-pdb.patch
index 2815ca2559..7c1fb26c74 100644
--- a/tools/depends/target/pcre/004-win-pdb.patch
+++ b/tools/depends/target/pcre/004-win-pdb.patch
@@ -1,20 +1,18 @@
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
-@@ -969,12 +969,14 @@
+@@ -969,12 +969,12 @@
PERMISSIONS OWNER_WRITE OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE)
IF(MSVC AND INSTALL_MSVC_PDB)
- INSTALL(FILES ${PROJECT_BINARY_DIR}/pcre.pdb
- ${PROJECT_BINARY_DIR}/pcreposix.pdb
+ INSTALL(FILES ${PROJECT_BINARY_DIR}/$<CONFIG>/pcre.pdb
-+ ${PROJECT_BINARY_DIR}/$<CONFIG>/pcrecpp.pdb
+ ${PROJECT_BINARY_DIR}/$<CONFIG>/pcreposix.pdb
DESTINATION bin
CONFIGURATIONS RelWithDebInfo)
- INSTALL(FILES ${PROJECT_BINARY_DIR}/pcred.pdb
- ${PROJECT_BINARY_DIR}/pcreposixd.pdb
+ INSTALL(FILES ${PROJECT_BINARY_DIR}/$<CONFIG>/pcred.pdb
-+ ${PROJECT_BINARY_DIR}/$<CONFIG>/pcrecppd.pdb
+ ${PROJECT_BINARY_DIR}/$<CONFIG>/pcreposixd.pdb
DESTINATION bin
CONFIGURATIONS Debug)
diff --git a/tools/depends/target/python3/PYTHON3-VERSION b/tools/depends/target/python3/PYTHON3-VERSION
index 877902c5ef..c5e1760fb2 100644
--- a/tools/depends/target/python3/PYTHON3-VERSION
+++ b/tools/depends/target/python3/PYTHON3-VERSION
@@ -1,4 +1,4 @@
LIBNAME=Python
-VERSION=3.11.6
+VERSION=3.11.7
ARCHIVE=$(LIBNAME)-$(VERSION).tar.xz
-SHA512=94b1038f6f53de0c44f99f72ed0f2e0791fd9d2a325ae00ba145b2b2c332c27b300b3ea3473017518089478f15e01867b1bb203c16610039cce36f8366de341a
+SHA512=11e06f2ffe1f66888cb5b4e9f607de815294d6863a77eda6ec6d7c724ef158df9f51881f4a956d4a6fa973c2fb6fd031d495e3496e9b0bb53793fb1cc8434c63
diff --git a/xbmc/ContextMenuManager.cpp b/xbmc/ContextMenuManager.cpp
index 607e960366..7aed939162 100644
--- a/xbmc/ContextMenuManager.cpp
+++ b/xbmc/ContextMenuManager.cpp
@@ -62,6 +62,7 @@ void CContextMenuManager::Init()
std::unique_lock<CCriticalSection> lock(m_criticalSection);
m_items = {
std::make_shared<CONTEXTMENU::CVideoBrowse>(),
+ std::make_shared<CONTEXTMENU::CVideoChooseVersion>(),
std::make_shared<CONTEXTMENU::CVideoResume>(),
std::make_shared<CONTEXTMENU::CVideoPlay>(),
std::make_shared<CONTEXTMENU::CVideoPlayUsing>(),
diff --git a/xbmc/Util.cpp b/xbmc/Util.cpp
index a94c1d16a5..8a6bae30da 100644
--- a/xbmc/Util.cpp
+++ b/xbmc/Util.cpp
@@ -435,6 +435,46 @@ std::string CUtil::GetDiscNumberFromPath(const std::string& path)
return discNum;
}
+bool CUtil::GetFilenameIdentifier(const std::string& fileName,
+ std::string& identifierType,
+ std::string& identifier)
+{
+ std::string match;
+ return GetFilenameIdentifier(fileName, identifierType, identifier, match);
+}
+
+bool CUtil::GetFilenameIdentifier(const std::string& fileName,
+ std::string& identifierType,
+ std::string& identifier,
+ std::string& match)
+{
+ CRegExp reIdentifier(true, CRegExp::autoUtf8);
+
+ const std::shared_ptr<CAdvancedSettings> advancedSettings =
+ CServiceBroker::GetSettingsComponent()->GetAdvancedSettings();
+ if (!reIdentifier.RegComp(advancedSettings->m_videoFilenameIdentifierRegExp))
+ {
+ CLog::LogF(LOGERROR, "Invalid filename identifier RegExp:'{}'",
+ advancedSettings->m_videoFilenameIdentifierRegExp);
+ return false;
+ }
+ else
+ {
+ if (reIdentifier.RegComp(advancedSettings->m_videoFilenameIdentifierRegExp))
+ {
+ if (reIdentifier.RegFind(fileName) >= 0)
+ {
+ match = reIdentifier.GetMatch(0);
+ identifierType = reIdentifier.GetMatch(1);
+ identifier = reIdentifier.GetMatch(2);
+ StringUtils::ToLower(identifierType);
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
void CUtil::CleanString(const std::string& strFileName,
std::string& strTitle,
std::string& strTitleAndYear,
@@ -447,6 +487,12 @@ void CUtil::CleanString(const std::string& strFileName,
if (strFileName == "..")
return;
+ std::string identifier;
+ std::string identifierType;
+ std::string identifierMatch;
+ if (GetFilenameIdentifier(strFileName, identifierType, identifier, identifierMatch))
+ StringUtils::Replace(strTitleAndYear, identifierMatch, "");
+
const std::shared_ptr<CAdvancedSettings> advancedSettings = CServiceBroker::GetSettingsComponent()->GetAdvancedSettings();
const std::vector<std::string> &regexps = advancedSettings->m_videoCleanStringRegExps;
diff --git a/xbmc/Util.h b/xbmc/Util.h
index 44991514f5..b93df4c3c8 100644
--- a/xbmc/Util.h
+++ b/xbmc/Util.h
@@ -43,6 +43,13 @@ public:
std::string& strYear,
bool bRemoveExtension = false,
bool bCleanChars = true);
+ static bool GetFilenameIdentifier(const std::string& fileName,
+ std::string& identifierType,
+ std::string& identifier);
+ static bool GetFilenameIdentifier(const std::string& fileName,
+ std::string& identifierType,
+ std::string& identifier,
+ std::string& match);
static std::string GetTitleFromPath(const CURL& url, bool bIsFolder = false);
static std::string GetTitleFromPath(const std::string& strFileNameAndPath, bool bIsFolder = false);
diff --git a/xbmc/addons/Scraper.cpp b/xbmc/addons/Scraper.cpp
index ad7b251052..66cedcb969 100644
--- a/xbmc/addons/Scraper.cpp
+++ b/xbmc/addons/Scraper.cpp
@@ -30,6 +30,7 @@
#include "settings/SettingsComponent.h"
#include "settings/SettingsValueFlatJsonSerializer.h"
#include "utils/CharsetConverter.h"
+#include "utils/JSONVariantWriter.h"
#include "utils/ScraperParser.h"
#include "utils/ScraperUrl.h"
#include "utils/StringUtils.h"
@@ -731,10 +732,10 @@ static std::string ParseFanart(const CFileItem &item, int nFanart, const std::st
}
template<class T>
-static void DetailsFromFileItem(const CFileItem &, T &);
+static bool DetailsFromFileItem(const CFileItem&, T&);
template<>
-void DetailsFromFileItem<CAlbum>(const CFileItem &item, CAlbum &album)
+bool DetailsFromFileItem<CAlbum>(const CFileItem& item, CAlbum& album)
{
album.strAlbum = item.GetLabel();
album.strMusicBrainzAlbumID = FromString(item, "album.musicbrainzid");
@@ -777,10 +778,11 @@ void DetailsFromFileItem<CAlbum>(const CFileItem &item, CAlbum &album)
int nThumbs = item.GetProperty("album.thumbs").asInteger32();
ParseThumbs(album.thumbURL, item, nThumbs, "album.thumb");
+ return true;
}
template<>
-void DetailsFromFileItem<CArtist>(const CFileItem &item, CArtist &artist)
+bool DetailsFromFileItem<CArtist>(const CFileItem& item, CArtist& artist)
{
artist.strArtist = item.GetLabel();
artist.strMusicBrainzArtistID = FromString(item, "artist.musicbrainzid");
@@ -846,34 +848,58 @@ void DetailsFromFileItem<CArtist>(const CFileItem &item, CArtist &artist)
for (unsigned int i = 0; i < fanart.GetNumFanarts(); i++)
artist.thumbURL.AddParsedUrl(fanart.GetImageURL(i), "fanart", fanart.GetPreviewURL(i));
}
+ return true;
}
template<>
-void DetailsFromFileItem<CVideoInfoTag>(const CFileItem &item, CVideoInfoTag &tag)
+bool DetailsFromFileItem<CVideoInfoTag>(const CFileItem& item, CVideoInfoTag& tag)
{
if (item.HasVideoInfoTag())
+ {
tag = *item.GetVideoInfoTag();
+ return true;
+ }
+ return false;
}
template<class T>
-static bool PythonDetails(const std::string &ID,
- const std::string &key,
- const std::string &url,
- const std::string &action,
- const std::string &pathSettings,
- T &result)
+static bool PythonDetails(const std::string& ID,
+ const std::string& key,
+ const std::string& url,
+ const std::string& action,
+ const std::string& pathSettings,
+ const std::unordered_map<std::string, std::string>& uniqueIDs,
+ T& result)
{
+ CVariant ids;
+ for (const auto& [identifierType, identifier] : uniqueIDs)
+ ids[identifierType] = identifier;
+ std::string uids;
+ CJSONVariantWriter::Write(ids, uids, true);
std::stringstream str;
str << "plugin://" << ID << "?action=" << action << "&" << key << "=" << CURL::Encode(url);
str << "&pathSettings=" << CURL::Encode(pathSettings);
+ if (!uniqueIDs.empty())
+ str << "&uniqueIDs=" << CURL::Encode(uids);
CFileItem item(url, false);
if (!XFILE::CPluginDirectory::GetPluginResult(str.str(), item, false))
return false;
- DetailsFromFileItem(item, result);
- return true;
+ return DetailsFromFileItem(item, result);
+}
+
+template<class T>
+static bool PythonDetails(const std::string& ID,
+ const std::string& key,
+ const std::string& url,
+ const std::string& action,
+ const std::string& pathSettings,
+ T& result)
+{
+ const std::unordered_map<std::string, std::string> ids;
+ return PythonDetails(ID, key, url, action, pathSettings, ids, result);
}
// fetch list of matching movies sorted by relevance (may be empty);
@@ -1324,10 +1350,11 @@ EPISODELIST CScraper::GetEpisodeList(XFILE::CCurlFile &fcurl, const CScraperUrl
}
// takes URL; returns true and populates video details on success, false otherwise
-bool CScraper::GetVideoDetails(XFILE::CCurlFile &fcurl,
- const CScraperUrl &scurl,
+bool CScraper::GetVideoDetails(XFILE::CCurlFile& fcurl,
+ const std::unordered_map<std::string, std::string>& uniqueIDs,
+ const CScraperUrl& scurl,
bool fMovie /*else episode*/,
- CVideoInfoTag &video)
+ CVideoInfoTag& video)
{
CLog::Log(LOGDEBUG,
"{}: Reading {} '{}' using {} scraper "
@@ -1339,7 +1366,8 @@ bool CScraper::GetVideoDetails(XFILE::CCurlFile &fcurl,
if (m_isPython)
return PythonDetails(ID(), "url", scurl.GetFirstThumbUrl(),
- fMovie ? "getdetails" : "getepisodedetails", GetPathSettingsAsJSON(), video);
+ fMovie ? "getdetails" : "getepisodedetails", GetPathSettingsAsJSON(),
+ uniqueIDs, video);
std::string sFunc = fMovie ? "GetDetails" : "GetEpisodeDetails";
std::vector<std::string> vcsIn;
diff --git a/xbmc/addons/Scraper.h b/xbmc/addons/Scraper.h
index 62b0d38139..93d34be3d8 100644
--- a/xbmc/addons/Scraper.h
+++ b/xbmc/addons/Scraper.h
@@ -131,8 +131,11 @@ public:
XFILE::CCurlFile &fcurl, const std::string &sArtist);
VIDEO::EPISODELIST GetEpisodeList(XFILE::CCurlFile &fcurl, const CScraperUrl &scurl);
- bool GetVideoDetails(XFILE::CCurlFile &fcurl, const CScraperUrl &scurl,
- bool fMovie/*else episode*/, CVideoInfoTag &video);
+ bool GetVideoDetails(XFILE::CCurlFile& fcurl,
+ const std::unordered_map<std::string, std::string>& uniqueIDs,
+ const CScraperUrl& scurl,
+ bool fMovie /*else episode*/,
+ CVideoInfoTag& video);
bool GetAlbumDetails(XFILE::CCurlFile &fcurl, const CScraperUrl &scurl,
CAlbum &album);
bool GetArtistDetails(XFILE::CCurlFile &fcurl, const CScraperUrl &scurl,
diff --git a/xbmc/favourites/GUIWindowFavourites.cpp b/xbmc/favourites/GUIWindowFavourites.cpp
index 762697af3e..10cfc0180f 100644
--- a/xbmc/favourites/GUIWindowFavourites.cpp
+++ b/xbmc/favourites/GUIWindowFavourites.cpp
@@ -50,43 +50,46 @@ namespace
class CVideoSelectActionProcessor : public VIDEO::GUILIB::CVideoSelectActionProcessorBase
{
public:
- explicit CVideoSelectActionProcessor(CFileItem& item) : CVideoSelectActionProcessorBase(item) {}
+ explicit CVideoSelectActionProcessor(const std::shared_ptr<CFileItem>& item)
+ : CVideoSelectActionProcessorBase(item)
+ {
+ }
protected:
bool OnPlayPartSelected(unsigned int part) override
{
// part numbers are 1-based
FAVOURITES_UTILS::ExecuteAction(
- {"PlayMedia", m_item, StringUtils::Format("playoffset={}", part - 1)});
+ {"PlayMedia", *m_item, StringUtils::Format("playoffset={}", part - 1)});
return true;
}
bool OnResumeSelected() override
{
- FAVOURITES_UTILS::ExecuteAction({"PlayMedia", m_item, "resume"});
+ FAVOURITES_UTILS::ExecuteAction({"PlayMedia", *m_item, "resume"});
return true;
}
bool OnPlaySelected() override
{
- FAVOURITES_UTILS::ExecuteAction({"PlayMedia", m_item, "noresume"});
+ FAVOURITES_UTILS::ExecuteAction({"PlayMedia", *m_item, "noresume"});
return true;
}
bool OnQueueSelected() override
{
- FAVOURITES_UTILS::ExecuteAction({"QueueMedia", m_item, ""});
+ FAVOURITES_UTILS::ExecuteAction({"QueueMedia", *m_item, ""});
return true;
}
bool OnInfoSelected() override
{
- return UTILS::GUILIB::CGUIContentUtils::ShowInfoForItem(m_item);
+ return UTILS::GUILIB::CGUIContentUtils::ShowInfoForItem(*m_item);
}
bool OnMoreSelected() override
{
- CONTEXTMENU::ShowFor(std::make_shared<CFileItem>(m_item), CContextMenuManager::MAIN);
+ CONTEXTMENU::ShowFor(m_item, CContextMenuManager::MAIN);
return true;
}
};
@@ -94,18 +97,21 @@ protected:
class CVideoPlayActionProcessor : public VIDEO::GUILIB::CVideoPlayActionProcessorBase
{
public:
- explicit CVideoPlayActionProcessor(CFileItem& item) : CVideoPlayActionProcessorBase(item) {}
+ explicit CVideoPlayActionProcessor(const ::std::shared_ptr<CFileItem>& item)
+ : CVideoPlayActionProcessorBase(item)
+ {
+ }
protected:
bool OnResumeSelected() override
{
- FAVOURITES_UTILS::ExecuteAction({"PlayMedia", m_item, "resume"});
+ FAVOURITES_UTILS::ExecuteAction({"PlayMedia", *m_item, "resume"});
return true;
}
bool OnPlaySelected() override
{
- FAVOURITES_UTILS::ExecuteAction({"PlayMedia", m_item, "noresume"});
+ FAVOURITES_UTILS::ExecuteAction({"PlayMedia", *m_item, "noresume"});
return true;
}
};
@@ -132,8 +138,8 @@ bool CGUIWindowFavourites::OnSelect(int itemIdx)
// video select action setting is for files only, except exec func is playmedia...
if (targetItem.HasVideoInfoTag() && (!targetItem.m_bIsFolder || isPlayMedia))
{
- CVideoSelectActionProcessor proc{targetItem};
- if (proc.Process())
+ CVideoSelectActionProcessor proc{std::make_shared<CFileItem>(targetItem)};
+ if (proc.ProcessDefaultAction())
return true;
}
@@ -154,24 +160,24 @@ bool CGUIWindowFavourites::OnAction(const CAction& action)
if (!target)
return false;
- CFileItem item{*target};
+ const auto item{std::make_shared<CFileItem>(*target)};
// video play action setting is for files and folders...
- if (item.HasVideoInfoTag() || (item.m_bIsFolder && VIDEO_UTILS::IsItemPlayable(item)))
+ if (item->HasVideoInfoTag() || (item->m_bIsFolder && VIDEO_UTILS::IsItemPlayable(*item)))
{
CVideoPlayActionProcessor proc{item};
- if (proc.Process())
+ if (proc.ProcessDefaultAction())
return true;
}
- if (CPlayerUtils::IsItemPlayable(item))
+ if (CPlayerUtils::IsItemPlayable(*item))
{
- CFavouritesURL target{item, {}};
+ CFavouritesURL target{*item, {}};
if (target.GetAction() != CFavouritesURL::Action::PLAY_MEDIA)
{
// build a playmedia execute string for given target
target = CFavouritesURL{CFavouritesURL::Action::PLAY_MEDIA,
- {StringUtils::Paramify(item.GetPath())}};
+ {StringUtils::Paramify(item->GetPath())}};
}
return FAVOURITES_UTILS::ExecuteAction(target);
}
diff --git a/xbmc/filesystem/FTPParse.cpp b/xbmc/filesystem/FTPParse.cpp
index 664cb2c290..dbbc033a40 100644
--- a/xbmc/filesystem/FTPParse.cpp
+++ b/xbmc/filesystem/FTPParse.cpp
@@ -8,9 +8,7 @@
#include "FTPParse.h"
-#include <cmath>
-
-#include <pcrecpp.h>
+#include <regex>
CFTPParse::CFTPParse()
{
@@ -44,86 +42,46 @@ time_t CFTPParse::getTime()
return m_time;
}
-void CFTPParse::setTime(const std::string& str)
+namespace
+{
+const std::string months = "janfebmaraprmayjunjulaugsepoctnovdec";
+
+// set time_struct.tm_mon from the 3-letter "abbreviated month name"
+void setMonFromName(struct tm& time_struct, const std::string& name)
{
- /* Variables used to capture patterns via the regexes */
- std::string month;
- std::string day;
- std::string year;
- std::string hour;
- std::string minute;
- std::string second;
- std::string am_or_pm;
+ std::smatch match;
+ if (std::regex_search(months, match, std::regex(name, std::regex_constants::icase)))
+ {
+ int pos = match.position();
+ if (name.size() == 3 && pos % 3 == 0)
+ time_struct.tm_mon = pos / 3;
+ }
+}
+} // namespace
+void CFTPParse::setTime(const std::string& str)
+{
/* time struct used to set the time_t variable */
struct tm time_struct = {};
- /* Regex to read Unix, NetWare and NetPresenz time format */
- pcrecpp::RE unix_re("^([A-Za-z]{3})" // month
- "\\s+(\\d{1,2})" // day of month
- "\\s+([:\\d]{4,5})$" // time of day or year
- );
-
- /* Regex to read MultiNet time format */
- pcrecpp::RE multinet_re("^(\\d{1,2})" // day of month
- "-([A-Za-z]{3})" // month
- "-(\\d{4})" // year
- "\\s+(\\d{2})" // hour
- ":(\\d{2})" // minute
- "(:(\\d{2}))?$" // second
- );
-
- /* Regex to read MSDOS time format */
- pcrecpp::RE msdos_re("^(\\d{2})" // month
- "-(\\d{2})" // day of month
- "-(\\d{2})" // year
- "\\s+(\\d{2})" // hour
- ":(\\d{2})" // minute
- "([AP]M)$" // AM or PM
- );
-
- if (unix_re.FullMatch(str, &month, &day, &year))
+ // sub matches from regex_match() calls below
+ std::smatch match;
+
+ // Regex to read Unix, NetWare and NetPresenz time format
+ if (std::regex_match(str, match,
+ std::regex("^([A-Za-z]{3})" // month
+ "\\s+(\\d{1,2})" // day of month
+ "\\s+([:\\d]{4,5})$"))) // time of day or year
{
+ auto month = match[1].str();
+ auto day = match[2].str();
+ auto year = match[3].str();
+
/* set the month */
- if (pcrecpp::RE("jan",
- pcrecpp::RE_Options().set_caseless(true)).FullMatch(month))
- time_struct.tm_mon = 0;
- else if (pcrecpp::RE("feb",
- pcrecpp::RE_Options().set_caseless(true)).FullMatch(month))
- time_struct.tm_mon = 1;
- else if (pcrecpp::RE("mar",
- pcrecpp::RE_Options().set_caseless(true)).FullMatch(month))
- time_struct.tm_mon = 2;
- else if (pcrecpp::RE("apr",
- pcrecpp::RE_Options().set_caseless(true)).FullMatch(month))
- time_struct.tm_mon = 3;
- else if (pcrecpp::RE("may",
- pcrecpp::RE_Options().set_caseless(true)).FullMatch(month))
- time_struct.tm_mon = 4;
- else if (pcrecpp::RE("jun",
- pcrecpp::RE_Options().set_caseless(true)).FullMatch(month))
- time_struct.tm_mon = 5;
- else if (pcrecpp::RE("jul",
- pcrecpp::RE_Options().set_caseless(true)).FullMatch(month))
- time_struct.tm_mon = 6;
- else if (pcrecpp::RE("aug",
- pcrecpp::RE_Options().set_caseless(true)).FullMatch(month))
- time_struct.tm_mon = 7;
- else if (pcrecpp::RE("sep",
- pcrecpp::RE_Options().set_caseless(true)).FullMatch(month))
- time_struct.tm_mon = 8;
- else if (pcrecpp::RE("oct",
- pcrecpp::RE_Options().set_caseless(true)).FullMatch(month))
- time_struct.tm_mon = 9;
- else if (pcrecpp::RE("nov",
- pcrecpp::RE_Options().set_caseless(true)).FullMatch(month))
- time_struct.tm_mon = 10;
- else if (pcrecpp::RE("dec",
- pcrecpp::RE_Options().set_caseless(true)).FullMatch(month))
- time_struct.tm_mon = 11;
+ setMonFromName(time_struct, month);
/* set the day of the month */
- time_struct.tm_mday = atoi(day.c_str());
+ time_struct.tm_mday = std::stol(day);
time_t t = time(NULL);
struct tm *current_time;
@@ -133,11 +91,11 @@ void CFTPParse::setTime(const std::string& str)
#else
current_time = localtime(&t);
#endif
- if (pcrecpp::RE("(\\d{2}):(\\d{2})").FullMatch(year, &hour, &minute))
+ if (std::regex_match(year, match, std::regex("(\\d{2}):(\\d{2})")))
{
/* set the hour and minute */
- time_struct.tm_hour = atoi(hour.c_str());
- time_struct.tm_min = atoi(minute.c_str());
+ time_struct.tm_hour = std::stol(match[1].str());
+ time_struct.tm_min = std::stol(match[2].str());
/* set the year */
if ((current_time->tm_mon - time_struct.tm_mon < 0) ||
@@ -150,261 +108,113 @@ void CFTPParse::setTime(const std::string& str)
else
{
/* set the year */
- time_struct.tm_year = atoi(year.c_str()) - 1900;
+ time_struct.tm_year = std::stol(year) - 1900;
}
-
- /* set the day of the week */
- time_struct.tm_wday = getDayOfWeek(time_struct.tm_mon + 1,
- time_struct.tm_mday,
- time_struct.tm_year + 1900);
}
- else if (multinet_re.FullMatch(str, &day, &month, &year,
- &hour, &minute, (void*)NULL, &second))
+ // Regex to read MultiNet time format
+ else if (std::regex_match(str, match,
+ std::regex("^(\\d{1,2})" // day of month
+ "-([A-Za-z]{3})" // month
+ "-(\\d{4})" // year
+ "\\s+(\\d{2})" // hour
+ ":(\\d{2})" // minute
+ "(:(\\d{2}))?$"))) // second
{
+ auto day = match[1].str();
+ auto month = match[2].str();
+ auto year = match[3].str();
+ auto hour = match[4].str();
+ auto minute = match[5].str();
+ // match[6] ignored
+ auto second = match[7].str();
+
/* set the month */
- if (pcrecpp::RE("jan",
- pcrecpp::RE_Options().set_caseless(true)).FullMatch(month))
- time_struct.tm_mon = 0;
- else if (pcrecpp::RE("feb",
- pcrecpp::RE_Options().set_caseless(true)).FullMatch(month))
- time_struct.tm_mon = 1;
- else if (pcrecpp::RE("mar",
- pcrecpp::RE_Options().set_caseless(true)).FullMatch(month))
- time_struct.tm_mon = 2;
- else if (pcrecpp::RE("apr",
- pcrecpp::RE_Options().set_caseless(true)).FullMatch(month))
- time_struct.tm_mon = 3;
- else if (pcrecpp::RE("may",
- pcrecpp::RE_Options().set_caseless(true)).FullMatch(month))
- time_struct.tm_mon = 4;
- else if (pcrecpp::RE("jun",
- pcrecpp::RE_Options().set_caseless(true)).FullMatch(month))
- time_struct.tm_mon = 5;
- else if (pcrecpp::RE("jul",
- pcrecpp::RE_Options().set_caseless(true)).FullMatch(month))
- time_struct.tm_mon = 6;
- else if (pcrecpp::RE("aug",
- pcrecpp::RE_Options().set_caseless(true)).FullMatch(month))
- time_struct.tm_mon = 7;
- else if (pcrecpp::RE("sep",
- pcrecpp::RE_Options().set_caseless(true)).FullMatch(month))
- time_struct.tm_mon = 8;
- else if (pcrecpp::RE("oct",
- pcrecpp::RE_Options().set_caseless(true)).FullMatch(month))
- time_struct.tm_mon = 9;
- else if (pcrecpp::RE("nov",
- pcrecpp::RE_Options().set_caseless(true)).FullMatch(month))
- time_struct.tm_mon = 10;
- else if (pcrecpp::RE("dec",
- pcrecpp::RE_Options().set_caseless(true)).FullMatch(month))
- time_struct.tm_mon = 11;
+ setMonFromName(time_struct, month);
/* set the day of the month and year */
- time_struct.tm_mday = atoi(day.c_str());
- time_struct.tm_year = atoi(year.c_str()) - 1900;
+ time_struct.tm_mday = std::stol(day);
+ time_struct.tm_year = std::stol(year) - 1900;
/* set the hour and minute */
- time_struct.tm_hour = atoi(hour.c_str());
- time_struct.tm_min = atoi(minute.c_str());
+ time_struct.tm_hour = std::stol(hour);
+ time_struct.tm_min = std::stol(minute);
/* set the second if given*/
if (second.length() > 0)
- time_struct.tm_sec = atoi(second.c_str());
-
- /* set the day of the week */
- time_struct.tm_wday = getDayOfWeek(time_struct.tm_mon + 1,
- time_struct.tm_mday,
- time_struct.tm_year + 1900);
+ time_struct.tm_sec = std::stol(second);
}
- else if (msdos_re.FullMatch(str, &month, &day,
- &year, &hour, &minute, &am_or_pm))
+ // Regex to read MSDOS time format
+ else if (std::regex_match(str, match,
+ std::regex("^(\\d{2})" // month
+ "-(\\d{2})" // day of month
+ "-(\\d{2})" // year
+ "\\s+(\\d{2})" // hour
+ ":(\\d{2})" // minute
+ "([AP]M)$"))) // AM or PM
{
+ auto month = match[1].str();
+ auto day = match[2].str();
+ auto year = match[3].str();
+ auto hour = match[4].str();
+ auto minute = match[5].str();
+ auto am_or_pm = match[6].str();
+
/* set the month and the day of the month */
- time_struct.tm_mon = atoi(month.c_str()) - 1;
- time_struct.tm_mday = atoi(day.c_str());
+ time_struct.tm_mon = std::stol(month) - 1;
+ time_struct.tm_mday = std::stol(day);
/* set the year */
- time_struct.tm_year = atoi(year.c_str());
+ time_struct.tm_year = std::stoi(year);
if (time_struct.tm_year < 70)
time_struct.tm_year += 100;
/* set the hour */
- time_struct.tm_hour = atoi(hour.c_str());
+ time_struct.tm_hour = std::stoi(hour);
if (time_struct.tm_hour == 12)
time_struct.tm_hour -= 12;
- if (pcrecpp::RE("PM").FullMatch(am_or_pm))
+ if (am_or_pm == "PM")
time_struct.tm_hour += 12;
/* set the minute */
- time_struct.tm_min = atoi(minute.c_str());
-
- /* set the day of the week */
- time_struct.tm_wday = getDayOfWeek(time_struct.tm_mon + 1,
- time_struct.tm_mday,
- time_struct.tm_year + 1900);
+ time_struct.tm_min = std::stoi(minute);
}
/* now set m_time */
m_time = mktime(&time_struct);
}
-int CFTPParse::getDayOfWeek(int month, int date, int year)
-{
- /* Here we use the Doomsday rule to calculate the day of the week */
-
- /* First determine the anchor day */
- int anchor;
- if (year >= 1900 && year < 2000)
- anchor = 3;
- else if (year >= 2000 && year < 2100)
- anchor = 2;
- else if (year >= 2100 && year < 2200)
- anchor = 0;
- else if (year >= 2200 && year < 2300)
- anchor = 5;
- else // must have been given an invalid year :-/
- return -1;
-
- /* Now determine the doomsday */
- int y = year % 100;
- int dday =
- ((y/12 + (y % 12) + ((y % 12)/4)) % 7) + anchor;
-
- /* Determine if the given year is a leap year */
- int leap_year = 0;
- if (((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0))
- leap_year = 1;
-
- /* Now select a doomsday for the given month */
- int mdday = 1;
- if (month == 1)
- {
- if (leap_year)
- mdday = 4;
- else
- mdday = 3;
- }
- if (month == 2)
- {
- if (leap_year)
- mdday = 1;
- else
- mdday = 7;
- }
- if (month == 3)
- mdday = 7;
- if (month == 4)
- mdday = 4;
- if (month == 5)
- mdday = 9;
- if (month == 6)
- mdday = 6;
- if (month == 7)
- mdday = 11;
- if (month == 8)
- mdday = 8;
- if (month == 9)
- mdday = 5;
- if (month == 10)
- mdday = 10;
- if (month == 11)
- mdday = 9;
- if (month == 12)
- mdday = 12;
-
- /* Now calculate the day of the week
- * Sunday = 0, Monday = 1, Tuesday = 2, Wednesday = 3, Thursday = 4,
- * Friday = 5, Saturday = 6.
- */
- int day_of_week = ((date - 1) % 7) - ((mdday - 1) % 7) + dday;
- if (day_of_week >= 7)
- day_of_week -= 7;
-
- return day_of_week;
-}
-
int CFTPParse::FTPParse(const std::string& str)
{
- /* Various variable to capture patterns via the regexes */
- std::string permissions;
- std::string link_count;
- std::string owner;
- std::string group;
- std::string size;
- std::string date;
- std::string name;
- std::string type;
- std::string stuff;
- std::string facts;
- std::string version;
- std::string file_id;
-
- /* Regex for standard Unix listing formats */
- pcrecpp::RE unix_re("^([-bcdlps])" // type
- "([-rwxXsStT]{9})" // permissions
- "\\s+(\\d+)" // hard link count
- "\\s+(\\w+)" // owner
- "\\s+(\\w+)" // group
- "\\s+(\\d+)" // size
- "\\s+([A-Za-z]{3}\\s+\\d{1,2}\\s+[:\\d]{4,5})" // modification date
- "\\s+(.+)$" // name
- );
-
- /* Regex for NetWare listing formats */
- /* See http://www.novell.com/documentation/oes/ftp_enu/data/a3ep22p.html#fbhbaijf */
- pcrecpp::RE netware_re("^([-d])" // type
- "\\s+(\\[[-SRWCIEMFA]{8}\\])" // rights
- "\\s+(\\w+)" // owner
- "\\s+(\\d+)" // size
- "\\s+([A-Za-z]{3}\\s+\\d{1,2}\\s+[:\\d]{4,5})" // time
- "\\s+(.+)$" // name
- );
-
- /* Regex for NetPresenz */
- /* See http://files.stairways.com/other/ftp-list-specs-info.txt */
- /* Here we will capture permissions and size if given */
- pcrecpp::RE netpresenz_re("^([-dl])" // type
- "([-rwx]{9}|)" // permissions
- "\\s+(.*)" // stuff
- "\\s+(\\d+|)" // size
- "\\s+([A-Za-z]{3}\\s+\\d{1,2}\\s+[:\\d]{4,5})" // modification date
- "\\s+(.+)$" // name
- );
-
- /* Regex for EPLF */
- /* See http://cr.yp.to/ftp/list/eplf.html */
- /* SAVE: "(/,|r,|s\\d+,|m\\d+,|i[\\d!#@$%^&*()]+(\\.[\\d!#@$%^&*()]+|),)+" */
- pcrecpp::RE eplf_re("^\\+" // initial "plus" sign
- "([^\\s]+)" // facts
- "\\s(.+)$" // name
- );
-
- /* Regex for MultiNet */
- /* Best documentation found was
- * http://www-sld.slac.stanford.edu/SLDWWW/workbook/vms_files.html */
- pcrecpp::RE multinet_re("^([^;]+)" // name
- ";(\\d+)" // version
- "\\s+([\\d/]+)" // file id
- "\\s+(\\d{1,2}-[A-Za-z]{3}-\\d{4}\\s+\\d{2}:\\d{2}(:\\d{2})?)" // date
- "\\s+\\[([^\\]]+)\\]" // owner,group
- "\\s+\\(([^\\)]+)\\)$" // permissions
- );
-
- /* Regex for MSDOS */
- pcrecpp::RE msdos_re("^(\\d{2}-\\d{2}-\\d{2}\\s+\\d{2}:\\d{2}[AP]M)" // date
- "\\s+(<DIR>|[\\d]+)" // dir or size
- "\\s+(.+)$" // name
- );
-
- if (unix_re.FullMatch(str, &type, &permissions, &link_count, &owner, &group, &size, &date, &name))
+ // sub matches from regex_match() calls below
+ std::smatch match;
+
+ // Regex for standard Unix listing formats
+ if (std::regex_match(
+ str, match,
+ std::regex("^([-bcdlps])" // type
+ "([-rwxXsStT]{9})" // permissions
+ "\\s+(\\d+)" // hard link count
+ "\\s+(\\w+)" // owner
+ "\\s+(\\w+)" // group
+ "\\s+(\\d+)" // size
+ "\\s+([A-Za-z]{3}\\s+\\d{1,2}\\s+[:\\d]{4,5})" // modification date
+ "\\s+(.+)$"))) // name
{
- m_name = name;
- m_size = (uint64_t)strtod(size.c_str(), NULL);
- if (pcrecpp::RE("d").FullMatch(type))
+ auto type = match[1].str();
+ auto permissions = match[2].str();
+ auto link_count = match[3].str();
+ auto owner = match[4].str();
+ auto group = match[5].str();
+ auto size = match[6].str();
+ auto date = match[7].str();
+ m_name = match[8].str();
+
+ m_size = std::stoull(size);
+ if (type == "d")
m_flagtrycwd = 1;
- if (pcrecpp::RE("-").FullMatch(type))
+ if (type == "-")
m_flagtryretr = 1;
- if (pcrecpp::RE("l").FullMatch(type))
+ if (type == "l")
{
m_flagtrycwd = m_flagtryretr = 1;
// handle symlink
@@ -416,27 +226,57 @@ int CFTPParse::FTPParse(const std::string& str)
return 1;
}
- if (netware_re.FullMatch(str, &type, &permissions, &owner, &size, &date, &name))
+ // Regex for NetWare listing formats
+ // See http://www.novell.com/documentation/oes/ftp_enu/data/a3ep22p.html#fbhbaijf
+ if (std::regex_match(str, match,
+ std::regex("^([-d])" // type
+ "\\s+(\\[[-SRWCIEMFA]{8}\\])" // rights
+ "\\s+(\\w+)" // owner
+ "\\s+(\\d+)" // size
+ "\\s+([A-Za-z]{3}\\s+\\d{1,2}\\s+[:\\d]{4,5})" // time
+ "\\s+(.+)$"))) // name
{
- m_name = name;
- m_size = (uint64_t)strtod(size.c_str(), NULL);
- if (pcrecpp::RE("d").FullMatch(type))
+ auto type = match[1].str();
+ auto permissions = match[2].str();
+ auto owner = match[3].str();
+ auto size = match[4].str();
+ auto date = match[5].str();
+ m_name = match[6].str();
+
+ m_size = std::stoull(size);
+ if (type == "d")
m_flagtrycwd = 1;
- if (pcrecpp::RE("-").FullMatch(type))
+ if (type == "-")
m_flagtryretr = 1;
setTime(date);
return 1;
}
- if (netpresenz_re.FullMatch(str, &type, &permissions, &stuff, &size, &date, &name))
+ // Regex for NetPresenz
+ // See http://files.stairways.com/other/ftp-list-specs-info.txt
+ // Here we will capture permissions and size if given
+ if (std::regex_match(
+ str, match,
+ std::regex("^([-dl])" // type
+ "([-rwx]{9}|)" // permissions
+ "\\s+(.*)" // stuff
+ "\\s+(\\d+|)" // size
+ "\\s+([A-Za-z]{3}\\s+\\d{1,2}\\s+[:\\d]{4,5})" // modification date
+ "\\s+(.+)$"))) // name
{
- m_name = name;
- m_size = (uint64_t)strtod(size.c_str(), NULL);
- if (pcrecpp::RE("d").FullMatch(type))
+ auto type = match[1].str();
+ auto permissions = match[2].str();
+ auto stuff = match[3].str();
+ auto size = match[4].str();
+ auto date = match[5].str();
+ m_name = match[6].str();
+
+ m_size = std::stoull(size);
+ if (type == "d")
m_flagtrycwd = 1;
- if (pcrecpp::RE("-").FullMatch(type))
+ if (type == "-")
m_flagtryretr = 1;
- if (pcrecpp::RE("l").FullMatch(type))
+ if (type == "l")
{
m_flagtrycwd = m_flagtryretr = 1;
// handle symlink
@@ -448,27 +288,56 @@ int CFTPParse::FTPParse(const std::string& str)
return 1;
}
- if (eplf_re.FullMatch(str, &facts, &name))
+ // Regex for EPLF
+ // See http://cr.yp.to/ftp/list/eplf.html
+ // SAVE: "(/,|r,|s\\d+,|m\\d+,|i[\\d!#@$%^&*()]+(\\.[\\d!#@$%^&*()]+|),)+"
+ if (std::regex_match(str, match,
+ std::regex("^\\+" // initial "plus" sign
+ "([^\\s]+)" // facts
+ "\\s(.+)$"))) // name
{
- /* Get the type, size, and date from the facts */
- pcrecpp::RE("(\\+|,)(r|/),").PartialMatch(facts, (void*)NULL, &type);
- pcrecpp::RE("(\\+|,)s(\\d+),").PartialMatch(facts, (void*)NULL, &size);
- pcrecpp::RE("(\\+|,)m(\\d+),").PartialMatch(facts, (void*)NULL, &date);
+ auto facts = match[1].str();
+ m_name = match[2].str();
- m_name = name;
- m_size = (uint64_t)strtod(size.c_str(), NULL);
- if (pcrecpp::RE("/").FullMatch(type))
+ /* Get the type, size, and date from the facts */
+ std::regex_search(facts, match, std::regex("(?:\\+|,)(r|/),"));
+ auto type = match[1].str();
+ std::regex_search(facts, match, std::regex("(?:\\+|,)s(\\d+),"));
+ auto size = match[1].str();
+ std::regex_search(facts, match, std::regex("(?:\\+|,)m(\\d+),"));
+ auto date = match[1].str();
+
+ m_size = std::stoull(size);
+ if (type == "/")
m_flagtrycwd = 1;
- if (pcrecpp::RE("r").FullMatch(type))
+ if (type == "r")
m_flagtryretr = 1;
/* eplf stores the date in time_t format already */
- m_time = atoi(date.c_str());
+ m_time = std::stoi(date);
return 1;
}
- if (multinet_re.FullMatch(str, &name, &version, &file_id, &date, (void*)NULL, &owner, &permissions))
+ // Regex for MultiNet
+ // Best documentation found was
+ // http://www-sld.slac.stanford.edu/SLDWWW/workbook/vms_files.html
+ if (std::regex_match(
+ str, match,
+ std::regex("^([^;]+)" // name
+ ";(\\d+)" // version
+ "\\s+([\\d/]+)" // file id
+ "\\s+(\\d{1,2}-[A-Za-z]{3}-\\d{4}\\s+\\d{2}:\\d{2}(:\\d{2})?)" // date
+ "\\s+\\[([^\\]]+)\\]" // owner,group
+ "\\s+\\(([^\\)]+)\\)$"))) // permissions
{
- if (pcrecpp::RE("\\.DIR$").PartialMatch(name))
+ auto name = match[1].str();
+ auto version = match[2].str();
+ auto file_id = match[3].str();
+ auto date = match[4].str();
+ // match[5] ignored
+ auto owner = match[6].str();
+ auto permissions = match[7].str();
+
+ if (std::regex_search(name, std::regex("\\.DIR$")))
{
name.resize(name.size() - 4);
m_flagtrycwd = 1;
@@ -482,10 +351,16 @@ int CFTPParse::FTPParse(const std::string& str)
return 1;
}
- if (msdos_re.FullMatch(str, &date, &size, &name))
+ // Regex for MSDOS
+ if (std::regex_match(str, match,
+ std::regex("^(\\d{2}-\\d{2}-\\d{2}\\s+\\d{2}:\\d{2}[AP]M)" // date
+ "\\s+(<DIR>|[\\d]+)" // dir or size
+ "\\s+(.+)$"))) // name
{
- m_name = name;
- if (pcrecpp::RE("<DIR>").FullMatch(size))
+ auto date = match[1].str();
+ auto size = match[2].str();
+ m_name = match[3].str();
+ if (size == "<DIR>")
{
m_flagtrycwd = 1;
m_size = 0;
@@ -493,7 +368,7 @@ int CFTPParse::FTPParse(const std::string& str)
else
{
m_flagtryretr = 1;
- m_size = (uint64_t)strtod(size.c_str(), NULL);
+ m_size = std::stoull(size);
}
setTime(date);
diff --git a/xbmc/filesystem/FTPParse.h b/xbmc/filesystem/FTPParse.h
index 5f56981d64..a853b02869 100644
--- a/xbmc/filesystem/FTPParse.h
+++ b/xbmc/filesystem/FTPParse.h
@@ -29,5 +29,4 @@ private:
uint64_t m_size; // number of octets
time_t m_time = 0; // modification time
void setTime(const std::string& str); // Method used to set m_time from a string
- int getDayOfWeek(int month, int date, int year); // Method to get day of week
};
diff --git a/xbmc/games/controllers/ControllerTranslator.cpp b/xbmc/games/controllers/ControllerTranslator.cpp
index df8641be28..c840a1845d 100644
--- a/xbmc/games/controllers/ControllerTranslator.cpp
+++ b/xbmc/games/controllers/ControllerTranslator.cpp
@@ -450,6 +450,8 @@ KEYBOARD::KeySymbol CControllerTranslator::TranslateKeysym(const std::string& sy
return XBMCK_EURO;
if (symbol == "undo")
return XBMCK_UNDO;
+ if (symbol == "oem102")
+ return XBMCK_OEM_102;
return XBMCK_UNKNOWN;
}
@@ -736,6 +738,8 @@ const char* CControllerTranslator::TranslateKeycode(KEYBOARD::KeySymbol keycode)
return "euro";
case XBMCK_UNDO:
return "undo";
+ case XBMCK_OEM_102:
+ return "oem102";
default:
break;
}
diff --git a/xbmc/guilib/GUIWindowManager.cpp b/xbmc/guilib/GUIWindowManager.cpp
index 555857849d..3104ce1be8 100644
--- a/xbmc/guilib/GUIWindowManager.cpp
+++ b/xbmc/guilib/GUIWindowManager.cpp
@@ -293,7 +293,7 @@ void CGUIWindowManager::CreateWindows()
Add(new CGUIDialogOK);
Add(new CGUIDialogVideoInfo);
Add(new CGUIDialogVideoVersion(WINDOW_DIALOG_VIDEO_VERSION));
- Add(new CGUIDialogVideoVersion(WINDOW_DIALOG_VIDEO_VERSION_PLAY));
+ Add(new CGUIDialogVideoVersion(WINDOW_DIALOG_VIDEO_VERSION_SELECT));
Add(new CGUIDialogTextViewer);
Add(new CGUIWindowFullScreen);
Add(new CGUIWindowVisualisation);
@@ -335,7 +335,7 @@ bool CGUIWindowManager::DestroyWindows()
DestroyWindow(WINDOW_DIALOG_MUSIC_INFO);
DestroyWindow(WINDOW_DIALOG_VIDEO_INFO);
DestroyWindow(WINDOW_DIALOG_VIDEO_VERSION);
- DestroyWindow(WINDOW_DIALOG_VIDEO_VERSION_PLAY);
+ DestroyWindow(WINDOW_DIALOG_VIDEO_VERSION_SELECT);
DestroyWindow(WINDOW_VIDEO_PLAYLIST);
DestroyWindow(WINDOW_VIDEO_NAV);
DestroyWindow(WINDOW_FILES);
diff --git a/xbmc/guilib/WindowIDs.h b/xbmc/guilib/WindowIDs.h
index 8b54b358d7..3f70bd8fc3 100644
--- a/xbmc/guilib/WindowIDs.h
+++ b/xbmc/guilib/WindowIDs.h
@@ -169,7 +169,7 @@
#define WINDOW_VISUALISATION 12006
#define WINDOW_SLIDESHOW 12007
#define WINDOW_DIALOG_COLOR_PICKER 12008
-#define WINDOW_DIALOG_VIDEO_VERSION_PLAY 12009
+#define WINDOW_DIALOG_VIDEO_VERSION_SELECT 12009
#define WINDOW_WEATHER 12600
#define WINDOW_SCREENSAVER 12900
#define WINDOW_DIALOG_VIDEO_OSD 12901
diff --git a/xbmc/input/WindowTranslator.cpp b/xbmc/input/WindowTranslator.cpp
index cfcba73003..c1bbd68da7 100644
--- a/xbmc/input/WindowTranslator.cpp
+++ b/xbmc/input/WindowTranslator.cpp
@@ -120,7 +120,7 @@ const CWindowTranslator::WindowMapByName CWindowTranslator::WindowMappingByName
{"okdialog", WINDOW_DIALOG_OK},
{"movieinformation", WINDOW_DIALOG_VIDEO_INFO},
{"videoversion", WINDOW_DIALOG_VIDEO_VERSION},
- {"videoversionplay", WINDOW_DIALOG_VIDEO_VERSION_PLAY},
+ {"videoversionselect", WINDOW_DIALOG_VIDEO_VERSION_SELECT},
{"textviewer", WINDOW_DIALOG_TEXT_VIEWER},
{"fullscreenvideo", WINDOW_FULLSCREEN_VIDEO},
{"dialogcolorpicker", WINDOW_DIALOG_COLOR_PICKER},
diff --git a/xbmc/input/XBMC_keysym.h b/xbmc/input/XBMC_keysym.h
index 0d65130b92..7a23dabc33 100644
--- a/xbmc/input/XBMC_keysym.h
+++ b/xbmc/input/XBMC_keysym.h
@@ -133,6 +133,11 @@ typedef enum
XBMCK_MEDIA_REWIND = 0xBA,
XBMCK_MEDIA_FASTFORWARD = 0xBB,
+ // This key is not present on standard US keyboard layouts. For European
+ // layouts it's usually located to the right of left-shift key, with '\' as
+ // its main function.
+ XBMCK_OEM_102 = 0xE2,
+
// Numeric keypad
XBMCK_KP0 = 0x100,
XBMCK_KP1 = 0x101,
diff --git a/xbmc/interfaces/builtins/PlayerBuiltins.cpp b/xbmc/interfaces/builtins/PlayerBuiltins.cpp
index 01ee12c1c5..25e6f9c226 100644
--- a/xbmc/interfaces/builtins/PlayerBuiltins.cpp
+++ b/xbmc/interfaces/builtins/PlayerBuiltins.cpp
@@ -513,13 +513,13 @@ int PlayOrQueueMedia(const std::vector<std::string>& params, bool forcePlay)
if (askToResume)
{
- const VIDEO::GUILIB::SelectAction action =
+ const VIDEO::GUILIB::Action action =
VIDEO::GUILIB::CVideoSelectActionProcessorBase::ChoosePlayOrResume(item);
- if (action == VIDEO::GUILIB::SELECT_ACTION_RESUME)
+ if (action == VIDEO::GUILIB::ACTION_RESUME)
{
item.SetStartOffset(STARTOFFSET_RESUME);
}
- else if (action != VIDEO::GUILIB::SELECT_ACTION_PLAY)
+ else if (action != VIDEO::GUILIB::ACTION_PLAY_FROM_BEGINNING)
{
// The Resume dialog was closed without any choice
return false;
diff --git a/xbmc/listproviders/DirectoryProvider.cpp b/xbmc/listproviders/DirectoryProvider.cpp
index b581cf6e2a..2811ec1882 100644
--- a/xbmc/listproviders/DirectoryProvider.cpp
+++ b/xbmc/listproviders/DirectoryProvider.cpp
@@ -37,7 +37,6 @@
#include "video/VideoInfoTag.h"
#include "video/VideoThumbLoader.h"
#include "video/VideoUtils.h"
-#include "video/dialogs/GUIDialogVideoVersion.h"
#include "video/guilib/VideoPlayActionProcessor.h"
#include "video/guilib/VideoSelectActionProcessor.h"
@@ -475,7 +474,7 @@ bool ExecuteAction(const CExecString& execute)
class CVideoSelectActionProcessor : public VIDEO::GUILIB::CVideoSelectActionProcessorBase
{
public:
- CVideoSelectActionProcessor(CDirectoryProvider& provider, CFileItem& item)
+ CVideoSelectActionProcessor(CDirectoryProvider& provider, const std::shared_ptr<CFileItem>& item)
: CVideoSelectActionProcessorBase(item), m_provider(provider)
{
}
@@ -484,49 +483,37 @@ protected:
bool OnPlayPartSelected(unsigned int part) override
{
// part numbers are 1-based
- ExecuteAction({"PlayMedia", m_item, StringUtils::Format("playoffset={}", part - 1)});
+ ExecuteAction({"PlayMedia", *m_item, StringUtils::Format("playoffset={}", part - 1)});
return true;
}
bool OnResumeSelected() override
{
- ExecuteAction({"PlayMedia", m_item, "resume"});
+ ExecuteAction({"PlayMedia", *m_item, "resume"});
return true;
}
bool OnPlaySelected() override
{
- //! @todo get rid of special handling for movie versions
- if (m_item.GetVideoInfoTag()->m_type == MediaTypeMovie)
- {
- auto videoItem = std::make_shared<CFileItem>(m_item);
- CGUIDialogVideoVersion::PlayVideoVersion(
- videoItem,
- [](const std::shared_ptr<CFileItem>& item) {
- ExecuteAction({"PlayMedia", *item.get(), "noresume"});
- });
- }
- else
- ExecuteAction({"PlayMedia", m_item, "noresume"});
-
+ ExecuteAction({"PlayMedia", *m_item, "noresume"});
return true;
}
bool OnQueueSelected() override
{
- ExecuteAction({"QueueMedia", m_item, ""});
+ ExecuteAction({"QueueMedia", *m_item, ""});
return true;
}
bool OnInfoSelected() override
{
- m_provider.OnInfo(std::make_shared<CFileItem>(m_item));
+ m_provider.OnInfo(m_item);
return true;
}
bool OnMoreSelected() override
{
- m_provider.OnContextMenu(std::make_shared<CFileItem>(m_item));
+ m_provider.OnContextMenu(m_item);
return true;
}
@@ -537,30 +524,21 @@ private:
class CVideoPlayActionProcessor : public VIDEO::GUILIB::CVideoPlayActionProcessorBase
{
public:
- explicit CVideoPlayActionProcessor(CFileItem& item) : CVideoPlayActionProcessorBase(item) {}
+ explicit CVideoPlayActionProcessor(const std::shared_ptr<CFileItem>& item)
+ : CVideoPlayActionProcessorBase(item)
+ {
+ }
protected:
bool OnResumeSelected() override
{
- ExecuteAction({"PlayMedia", m_item, "resume"});
+ ExecuteAction({"PlayMedia", *m_item, "resume"});
return true;
}
bool OnPlaySelected() override
{
- //! @todo get rid of special handling for movie versions
- if (m_item.GetVideoInfoTag()->m_type == MediaTypeMovie)
- {
- auto videoItem = std::make_shared<CFileItem>(m_item);
- CGUIDialogVideoVersion::PlayVideoVersion(
- videoItem,
- [](const std::shared_ptr<CFileItem>& item) {
- ExecuteAction({"PlayMedia", *item.get(), "noresume"});
- });
- }
- else
- ExecuteAction({"PlayMedia", m_item, "noresume"});
-
+ ExecuteAction({"PlayMedia", *m_item, "noresume"});
return true;
}
};
@@ -585,8 +563,8 @@ bool CDirectoryProvider::OnClick(const CGUIListItemPtr& item)
// video select action setting is for files only, except exec func is playmedia...
if (targetItem.HasVideoInfoTag() && (!targetItem.m_bIsFolder || isPlayMedia))
{
- CVideoSelectActionProcessor proc{*this, targetItem};
- if (proc.Process())
+ CVideoSelectActionProcessor proc{*this, std::make_shared<CFileItem>(targetItem)};
+ if (proc.ProcessDefaultAction())
return true;
}
@@ -616,8 +594,8 @@ bool CDirectoryProvider::OnPlay(const CGUIListItemPtr& item)
if (targetItem.HasVideoInfoTag() ||
(targetItem.m_bIsFolder && VIDEO_UTILS::IsItemPlayable(targetItem)))
{
- CVideoPlayActionProcessor proc{targetItem};
- if (proc.Process())
+ CVideoPlayActionProcessor proc{std::make_shared<CFileItem>(targetItem)};
+ if (proc.ProcessDefaultAction())
return true;
}
diff --git a/xbmc/network/DNSNameCache.cpp b/xbmc/network/DNSNameCache.cpp
index af2ac1ad1f..63fcfae9ed 100644
--- a/xbmc/network/DNSNameCache.cpp
+++ b/xbmc/network/DNSNameCache.cpp
@@ -24,6 +24,10 @@
#include <netdb.h>
#include <netinet/in.h>
+#if defined(TARGET_FREEBSD)
+#include <sys/socket.h>
+#endif
+
CDNSNameCache g_DNSCache;
CCriticalSection CDNSNameCache::m_critical;
@@ -38,18 +42,19 @@ bool CDNSNameCache::Lookup(const std::string& strHostName, std::string& strIpAdd
return false;
// first see if this is already an ip address
- unsigned long address = inet_addr(strHostName.c_str());
+ in_addr addr4;
+ in6_addr addr6;
strIpAddress.clear();
- if (address != INADDR_NONE)
+ if (inet_pton(AF_INET, strHostName.c_str(), &addr4) ||
+ inet_pton(AF_INET6, strHostName.c_str(), &addr6))
{
- strIpAddress = StringUtils::Format("{}.{}.{}.{}", (address & 0xFF), (address & 0xFF00) >> 8,
- (address & 0xFF0000) >> 16, (address & 0xFF000000) >> 24);
+ strIpAddress = strHostName;
return true;
}
// check if there's a custom entry or if it's already cached
- if(g_DNSCache.GetCached(strHostName, strIpAddress))
+ if (g_DNSCache.GetCached(strHostName, strIpAddress))
return true;
// perform dns lookup
diff --git a/xbmc/pvr/dialogs/GUIDialogPVRGuideInfo.cpp b/xbmc/pvr/dialogs/GUIDialogPVRGuideInfo.cpp
index 9b8ed4fa4a..1605234bfe 100644
--- a/xbmc/pvr/dialogs/GUIDialogPVRGuideInfo.cpp
+++ b/xbmc/pvr/dialogs/GUIDialogPVRGuideInfo.cpp
@@ -140,9 +140,8 @@ bool CGUIDialogPVRGuideInfo::OnClickButtonPlay(const CGUIMessage& message)
const auto recording{CPVRItem(m_progItem).GetRecording()};
if (recording)
{
- CFileItem item{recording};
- CGUIPVRRecordingsPlayActionProcessor proc{item};
- proc.Process();
+ CGUIPVRRecordingsPlayActionProcessor proc{std::make_shared<CFileItem>(recording)};
+ proc.ProcessDefaultAction();
if (proc.UserCancelled())
Open();
}
diff --git a/xbmc/pvr/dialogs/GUIDialogPVRRecordingInfo.cpp b/xbmc/pvr/dialogs/GUIDialogPVRRecordingInfo.cpp
index a9458f54b3..6019c3feb1 100644
--- a/xbmc/pvr/dialogs/GUIDialogPVRRecordingInfo.cpp
+++ b/xbmc/pvr/dialogs/GUIDialogPVRRecordingInfo.cpp
@@ -60,8 +60,8 @@ bool CGUIDialogPVRRecordingInfo::OnClickButtonPlay(const CGUIMessage& message)
if (m_recordItem)
{
- CGUIPVRRecordingsPlayActionProcessor proc{*m_recordItem};
- proc.Process();
+ CGUIPVRRecordingsPlayActionProcessor proc{m_recordItem};
+ proc.ProcessDefaultAction();
if (proc.UserCancelled())
Open();
}
diff --git a/xbmc/pvr/guilib/PVRGUIActionsPlayback.cpp b/xbmc/pvr/guilib/PVRGUIActionsPlayback.cpp
index 4e834af724..504351698a 100644
--- a/xbmc/pvr/guilib/PVRGUIActionsPlayback.cpp
+++ b/xbmc/pvr/guilib/PVRGUIActionsPlayback.cpp
@@ -60,13 +60,13 @@ bool CPVRGUIActionsPlayback::CheckResumeRecording(const CFileItem& item) const
{
bool bPlayIt(true);
- const VIDEO::GUILIB::SelectAction action =
+ const VIDEO::GUILIB::Action action =
VIDEO::GUILIB::CVideoSelectActionProcessorBase::ChoosePlayOrResume(item);
- if (action == VIDEO::GUILIB::SELECT_ACTION_RESUME)
+ if (action == VIDEO::GUILIB::ACTION_RESUME)
{
const_cast<CFileItem*>(&item)->SetStartOffset(STARTOFFSET_RESUME);
}
- else if (action == VIDEO::GUILIB::SELECT_ACTION_PLAY)
+ else if (action == VIDEO::GUILIB::ACTION_PLAY_FROM_BEGINNING)
{
const_cast<CFileItem*>(&item)->SetStartOffset(0);
}
diff --git a/xbmc/pvr/guilib/PVRGUIRecordingsPlayActionProcessor.h b/xbmc/pvr/guilib/PVRGUIRecordingsPlayActionProcessor.h
index 14225bc3b6..80df2dfc96 100644
--- a/xbmc/pvr/guilib/PVRGUIRecordingsPlayActionProcessor.h
+++ b/xbmc/pvr/guilib/PVRGUIRecordingsPlayActionProcessor.h
@@ -19,7 +19,7 @@ namespace PVR
class CGUIPVRRecordingsPlayActionProcessor : public VIDEO::GUILIB::CVideoPlayActionProcessorBase
{
public:
- explicit CGUIPVRRecordingsPlayActionProcessor(CFileItem& item)
+ explicit CGUIPVRRecordingsPlayActionProcessor(const std::shared_ptr<CFileItem>& item)
: CVideoPlayActionProcessorBase(item)
{
}
@@ -27,7 +27,7 @@ public:
protected:
bool OnResumeSelected() override
{
- m_item.SetStartOffset(STARTOFFSET_RESUME);
+ m_item->SetStartOffset(STARTOFFSET_RESUME);
Play();
return true;
}
@@ -42,7 +42,7 @@ private:
void Play()
{
CServiceBroker::GetPVRManager().Get<PVR::GUI::Playback>().PlayRecording(
- m_item, false /* no resume check */);
+ *m_item, false /* no resume check */);
}
};
} // namespace PVR
diff --git a/xbmc/pvr/windows/GUIWindowPVRRecordings.cpp b/xbmc/pvr/windows/GUIWindowPVRRecordings.cpp
index d939d741b5..3f545098de 100644
--- a/xbmc/pvr/windows/GUIWindowPVRRecordings.cpp
+++ b/xbmc/pvr/windows/GUIWindowPVRRecordings.cpp
@@ -227,7 +227,9 @@ namespace
class CVideoSelectActionProcessor : public VIDEO::GUILIB::CVideoSelectActionProcessorBase
{
public:
- CVideoSelectActionProcessor(CGUIWindowPVRRecordingsBase& window, CFileItem& item, int itemIndex)
+ CVideoSelectActionProcessor(CGUIWindowPVRRecordingsBase& window,
+ const std::shared_ptr<CFileItem>& item,
+ int itemIndex)
: CVideoSelectActionProcessorBase(item), m_window(window), m_itemIndex(itemIndex)
{
}
@@ -242,27 +244,26 @@ protected:
bool OnResumeSelected() override
{
CServiceBroker::GetPVRManager().Get<PVR::GUI::Playback>().ResumePlayRecording(
- m_item, true /* fall back to play if no resume possible */);
+ *m_item, true /* fall back to play if no resume possible */);
return true;
}
bool OnPlaySelected() override
{
CServiceBroker::GetPVRManager().Get<PVR::GUI::Playback>().PlayRecording(
- m_item, false /* no resume check */);
+ *m_item, false /* no resume check */);
return true;
}
bool OnQueueSelected() override
{
- VIDEO_UTILS::QueueItem(std::make_shared<CFileItem>(m_item),
- VIDEO_UTILS::QueuePosition::POSITION_END);
+ VIDEO_UTILS::QueueItem(m_item, VIDEO_UTILS::QueuePosition::POSITION_END);
return true;
}
bool OnInfoSelected() override
{
- CServiceBroker::GetPVRManager().Get<PVR::GUI::Recordings>().ShowRecordingInfo(m_item);
+ CServiceBroker::GetPVRManager().Get<PVR::GUI::Recordings>().ShowRecordingInfo(*m_item);
return true;
}
@@ -280,37 +281,40 @@ private:
class CVideoPlayActionProcessor : public CVideoPlayActionProcessorBase
{
public:
- explicit CVideoPlayActionProcessor(CFileItem& item) : CVideoPlayActionProcessorBase(item) {}
+ explicit CVideoPlayActionProcessor(const std::shared_ptr<CFileItem>& item)
+ : CVideoPlayActionProcessorBase(item)
+ {
+ }
protected:
bool OnResumeSelected() override
{
- if (m_item.m_bIsFolder)
+ if (m_item->m_bIsFolder)
{
- m_item.SetStartOffset(STARTOFFSET_RESUME);
+ m_item->SetStartOffset(STARTOFFSET_RESUME);
CServiceBroker::GetPVRManager().Get<PVR::GUI::Playback>().PlayRecordingFolder(
- m_item, false /* no resume check */);
+ *m_item, false /* no resume check */);
}
else
{
CServiceBroker::GetPVRManager().Get<PVR::GUI::Playback>().ResumePlayRecording(
- m_item, true /* fall back to play if no resume possible */);
+ *m_item, true /* fall back to play if no resume possible */);
}
return true;
}
bool OnPlaySelected() override
{
- if (m_item.m_bIsFolder)
+ if (m_item->m_bIsFolder)
{
- m_item.SetStartOffset(0);
+ m_item->SetStartOffset(0);
CServiceBroker::GetPVRManager().Get<PVR::GUI::Playback>().PlayRecordingFolder(
- m_item, false /* no resume check */);
+ *m_item, false /* no resume check */);
}
else
{
CServiceBroker::GetPVRManager().Get<PVR::GUI::Playback>().PlayRecording(
- m_item, false /* no resume check */);
+ *m_item, false /* no resume check */);
}
return true;
}
@@ -346,8 +350,8 @@ bool CGUIWindowPVRRecordingsBase::OnMessage(CGUIMessage& message)
if (!item->IsParentFolder() && message.GetParam1() == ACTION_PLAYER_PLAY)
{
- CVideoPlayActionProcessor proc{*item};
- bReturn = proc.Process();
+ CVideoPlayActionProcessor proc{item};
+ bReturn = proc.ProcessDefaultAction();
}
else if (item->m_bIsFolder)
{
@@ -356,8 +360,8 @@ bool CGUIWindowPVRRecordingsBase::OnMessage(CGUIMessage& message)
}
else
{
- CVideoSelectActionProcessor proc(*this, *item, iItem);
- bReturn = proc.Process();
+ CVideoSelectActionProcessor proc(*this, item, iItem);
+ bReturn = proc.ProcessDefaultAction();
}
break;
}
diff --git a/xbmc/settings/AdvancedSettings.cpp b/xbmc/settings/AdvancedSettings.cpp
index bae673d187..85cba8597a 100644
--- a/xbmc/settings/AdvancedSettings.cpp
+++ b/xbmc/settings/AdvancedSettings.cpp
@@ -195,6 +195,7 @@ void CAdvancedSettings::Initialize()
m_fullScreenOnMovieStart = true;
m_cachePath = "special://temp/";
+ m_videoFilenameIdentifierRegExp = R"([\{\[](\w+?)(?:id)?[-=](\w+)[\}|\]])";
m_videoCleanDateTimeRegExp = "(.*[^ _\\,\\.\\(\\)\\[\\]\\-])[ _\\.\\(\\)\\[\\]\\-]+(19[0-9][0-9]|20[0-9][0-9])([ _\\,\\.\\(\\)\\[\\]\\-]|[^0-9]$)?";
m_videoCleanStringRegExps.clear();
@@ -632,6 +633,7 @@ void CAdvancedSettings::ParseSettingsFile(const std::string &file)
if (pVideoExcludes)
GetCustomRegexps(pVideoExcludes, m_videoCleanStringRegExps);
+ XMLUtils::GetString(pElement, "filenameidentifier", m_videoFilenameIdentifierRegExp);
XMLUtils::GetString(pElement,"cleandatetime", m_videoCleanDateTimeRegExp);
XMLUtils::GetString(pElement,"ppffmpegpostprocessing",m_videoPPFFmpegPostProc);
XMLUtils::GetInt(pElement,"vdpauscaling",m_videoVDPAUScaling);
diff --git a/xbmc/settings/AdvancedSettings.h b/xbmc/settings/AdvancedSettings.h
index b972933b29..a18e7aaacf 100644
--- a/xbmc/settings/AdvancedSettings.h
+++ b/xbmc/settings/AdvancedSettings.h
@@ -199,6 +199,7 @@ class CAdvancedSettings : public ISettingCallback, public ISettingsHandler
bool m_fullScreenOnMovieStart;
std::string m_cachePath;
std::string m_videoCleanDateTimeRegExp;
+ std::string m_videoFilenameIdentifierRegExp;
std::vector<std::string> m_videoCleanStringRegExps;
std::vector<std::string> m_videoExcludeFromListingRegExps;
std::vector<std::string> m_allExcludeFromScanRegExps;
diff --git a/xbmc/settings/Settings.h b/xbmc/settings/Settings.h
index 3ba4b08cde..8a62a03b4d 100644
--- a/xbmc/settings/Settings.h
+++ b/xbmc/settings/Settings.h
@@ -101,7 +101,6 @@ public:
static constexpr auto SETTING_VIDEOLIBRARY_IGNOREVIDEOEXTRAS = "videolibrary.ignorevideoextras";
static constexpr auto SETTING_VIDEOLIBRARY_SHOWVIDEOVERSIONSASFOLDER =
"videolibrary.showvideoversionsasfolder";
- static constexpr auto SETTING_VIDEOPLAYER_PLAYDEFAULTVERSION = "videoplayer.playdefaultversion";
static constexpr auto SETTING_LOCALE_AUDIOLANGUAGE = "locale.audiolanguage";
static constexpr auto SETTING_VIDEOPLAYER_PREFERDEFAULTFLAG = "videoplayer.preferdefaultflag";
static constexpr auto SETTING_VIDEOPLAYER_AUTOPLAYNEXTITEM = "videoplayer.autoplaynextitem";
@@ -137,6 +136,7 @@ public:
static constexpr auto SETTING_VIDEOPLAYER_SUPPORTMVC = "videoplayer.supportmvc";
static constexpr auto SETTING_VIDEOPLAYER_CONVERTDOVI = "videoplayer.convertdovi";
static constexpr auto SETTING_MYVIDEOS_SELECTACTION = "myvideos.selectaction";
+ static constexpr auto SETTING_MYVIDEOS_SELECTDEFAULTVERSION = "myvideos.selectdefaultversion";
static constexpr auto SETTING_MYVIDEOS_PLAYACTION = "myvideos.playaction";
static constexpr auto SETTING_MYVIDEOS_USETAGS = "myvideos.usetags";
static constexpr auto SETTING_MYVIDEOS_EXTRACTFLAGS = "myvideos.extractflags";
diff --git a/xbmc/test/TestUtil.cpp b/xbmc/test/TestUtil.cpp
index 6215b9356e..57767ea67f 100644
--- a/xbmc/test/TestUtil.cpp
+++ b/xbmc/test/TestUtil.cpp
@@ -97,6 +97,8 @@ struct TestUtilCleanStringData
std::string expTitle;
std::string expTitleYear;
std::string expYear;
+ std::string expIdentifierType{};
+ std::string expIdentifier{};
};
std::ostream& operator<<(std::ostream& os, const TestUtilCleanStringData& rhs)
@@ -110,6 +112,15 @@ class TestUtilCleanString : public Test, public WithParamInterface<TestUtilClean
{
};
+TEST_P(TestUtilCleanString, GetFilenameIdentifier)
+{
+ std::string identifierType;
+ std::string identifier;
+ CUtil::GetFilenameIdentifier(GetParam().input, identifierType, identifier);
+ EXPECT_EQ(identifierType, GetParam().expIdentifierType);
+ EXPECT_EQ(identifier, GetParam().expIdentifier);
+}
+
TEST_P(TestUtilCleanString, CleanString)
{
std::string title, titleYear, year;
@@ -131,6 +142,12 @@ const TestUtilCleanStringData values[] = {
{"Some.Movie.1954.BDRip.1080p.mkv", true, "Some Movie", "Some Movie (1954)", "1954"},
{"Some «Movie».2021.WEB-DL.2160p.HDR.mkv", true, "Some «Movie»", "Some «Movie» (2021)", "2021"},
{"Some Movie (2013).mp4", true, "Some Movie", "Some Movie (2013)", "2013"},
+ {"Some Movie (2013) [imdbid-tt123].mp4", true, "Some Movie", "Some Movie (2013)", "2013",
+ "imdb", "tt123"},
+ {"Some Movie (2013) {tmdb-123}.mp4", true, "Some Movie", "Some Movie (2013)", "2013", "tmdb",
+ "123"},
+ {"Some Movie (2013) {tmdb=123}.mp4", true, "Some Movie", "Some Movie (2013)", "2013", "tmdb",
+ "123"},
// no result because of the text (Director Cut), it can also a be a movie translation
{"Some (Director Cut).BDRemux.mkv", true, "Some (Director Cut)", "Some (Director Cut)", ""}};
diff --git a/xbmc/utils/LangCodeExpander.cpp b/xbmc/utils/LangCodeExpander.cpp
index f683905049..aa629c2b08 100644
--- a/xbmc/utils/LangCodeExpander.cpp
+++ b/xbmc/utils/LangCodeExpander.cpp
@@ -592,8 +592,7 @@ std::string CLangCodeExpander::ConvertToISO6392T(const std::string& lang)
std::string CLangCodeExpander::FindLanguageCodeWithSubtag(const std::string& str)
{
CRegExp regLangCode;
- if (regLangCode.RegComp(
- "(?:^|\\s|\\()(([A-Za-z]{2,3})-([A-Za-z]{2}|[0-9]{3}|[A-Za-z]{4}))(?:$|\\s|\\))") &&
+ if (regLangCode.RegComp("\\{(([A-Za-z]{2,3})-([A-Za-z]{2}|[0-9]{3}|[A-Za-z]{4}))\\}") &&
regLangCode.RegFind(str) >= 0)
{
return regLangCode.GetMatch(1);
diff --git a/xbmc/utils/LangCodeExpander.h b/xbmc/utils/LangCodeExpander.h
index dc9e5dc48a..80f02d7649 100644
--- a/xbmc/utils/LangCodeExpander.h
+++ b/xbmc/utils/LangCodeExpander.h
@@ -120,7 +120,7 @@ public:
* \brief Find a language code with subtag (e.g. zh-tw, zh-Hans) in to a string.
* This function find a limited set of IETF BCP47 specs, so:
* language tag + region subtag, or, language tag + script subtag.
- * The language code can be found also if wrapped with round brackets.
+ * The language code can be found if wrapped by curly brackets e.g. {pt-br}.
* \param str The string where find the language code.
* \return The language code found in the string, otherwise empty string
*/
diff --git a/xbmc/video/ContextMenus.cpp b/xbmc/video/ContextMenus.cpp
index 9a179d5020..955ad2b3a1 100644
--- a/xbmc/video/ContextMenus.cpp
+++ b/xbmc/video/ContextMenus.cpp
@@ -9,6 +9,7 @@
#include "ContextMenus.h"
#include "Autorun.h"
+#include "ContextMenuManager.h"
#include "FileItem.h"
#include "GUIUserMessages.h"
#include "ServiceBroker.h"
@@ -17,11 +18,14 @@
#include "guilib/GUIComponent.h"
#include "guilib/GUIWindowManager.h"
#include "guilib/LocalizeStrings.h"
+#include "utils/ExecString.h"
+#include "utils/StringUtils.h"
#include "utils/URIUtils.h"
#include "video/VideoInfoTag.h"
#include "video/VideoUtils.h"
#include "video/dialogs/GUIDialogVideoInfo.h"
-#include "video/dialogs/GUIDialogVideoVersion.h"
+#include "video/guilib/VideoPlayActionProcessor.h"
+#include "video/guilib/VideoSelectActionProcessor.h"
#include <utility>
@@ -159,6 +163,84 @@ bool CVideoBrowse::Execute(const std::shared_ptr<CFileItem>& item) const
return true;
}
+namespace
+{
+bool ExecuteAction(const CExecString& execute)
+{
+ const std::string execStr{execute.GetExecString()};
+ if (!execStr.empty())
+ {
+ CGUIMessage message(GUI_MSG_EXECUTE, 0, 0);
+ message.SetStringParam(execStr);
+ CServiceBroker::GetGUI()->GetWindowManager().SendMessage(message);
+ return true;
+ }
+ return false;
+}
+
+class CVideoSelectActionProcessor : public VIDEO::GUILIB::CVideoSelectActionProcessorBase
+{
+public:
+ explicit CVideoSelectActionProcessor(const std::shared_ptr<CFileItem>& item)
+ : CVideoSelectActionProcessorBase(item)
+ {
+ }
+
+protected:
+ bool OnPlayPartSelected(unsigned int part) override
+ {
+ // part numbers are 1-based
+ ExecuteAction({"PlayMedia", *m_item, StringUtils::Format("playoffset={}", part - 1)});
+ return true;
+ }
+
+ bool OnResumeSelected() override
+ {
+ ExecuteAction({"PlayMedia", *m_item, "resume"});
+ return true;
+ }
+
+ bool OnPlaySelected() override
+ {
+ ExecuteAction({"PlayMedia", *m_item, "noresume"});
+ return true;
+ }
+
+ bool OnQueueSelected() override
+ {
+ ExecuteAction({"QueueMedia", *m_item, ""});
+ return true;
+ }
+
+ bool OnInfoSelected() override
+ {
+ CGUIDialogVideoInfo::ShowFor(*m_item);
+ return true;
+ }
+
+ bool OnMoreSelected() override
+ {
+ CONTEXTMENU::ShowFor(m_item, CContextMenuManager::MAIN);
+ return true;
+ }
+};
+} // unnamed namespace
+
+bool CVideoChooseVersion::IsVisible(const CFileItem& item) const
+{
+ return item.HasVideoVersions();
+}
+
+bool CVideoChooseVersion::Execute(const std::shared_ptr<CFileItem>& item) const
+{
+ // force selection dialog, regardless of any settings like 'Select default video version'
+ item->SetProperty("force_choose_video_version", true);
+ CVideoSelectActionProcessor proc{item};
+ const bool ret = proc.ProcessDefaultAction();
+ item->ClearProperty("force_choose_video_version");
+ return ret;
+}
+
std::string CVideoResume::GetLabel(const CFileItem& item) const
{
return VIDEO_UTILS::GetResumeString(item.GetItemToPlay());
@@ -175,38 +257,69 @@ bool CVideoResume::IsVisible(const CFileItem& itemIn) const
namespace
{
-void SetPathAndPlay(CFileItem& item, const std::string& player)
+class CVideoPlayActionProcessor : public VIDEO::GUILIB::CVideoPlayActionProcessorBase
{
- if (!item.m_bIsFolder && item.IsVideoDb())
+public:
+ explicit CVideoPlayActionProcessor(const std::shared_ptr<CFileItem>& item,
+ const std::string& player)
+ : CVideoPlayActionProcessorBase(item), m_player(player)
{
- item.SetProperty("original_listitem_url", item.GetPath());
- item.SetPath(item.GetVideoInfoTag()->m_strFileNameAndPath);
}
- item.SetProperty("check_resume", false);
- if (item.IsLiveTV()) // pvr tv or pvr radio?
+protected:
+ bool OnResumeSelected() override
{
- g_application.PlayMedia(item, "", PLAYLIST::TYPE_VIDEO);
+ m_item->SetStartOffset(STARTOFFSET_RESUME);
+ Play();
+ return true;
}
- else
+
+ bool OnPlaySelected() override
{
- item.SetProperty("playlist_type_hint", PLAYLIST::TYPE_VIDEO);
+ Play();
+ return true;
+ }
+
+private:
+ void Play()
+ {
+ m_item->SetProperty("playlist_type_hint", PLAYLIST::TYPE_VIDEO);
+ const ContentUtils::PlayMode mode{m_item->GetProperty("CheckAutoPlayNextItem").asBoolean()
+ ? ContentUtils::PlayMode::CHECK_AUTO_PLAY_NEXT_ITEM
+ : ContentUtils::PlayMode::PLAY_ONLY_THIS};
+ VIDEO_UTILS::PlayItem(m_item, m_player, mode);
+ }
+
+ const std::string m_player;
+};
- const ContentUtils::PlayMode mode = item.GetProperty("CheckAutoPlayNextItem").asBoolean()
- ? ContentUtils::PlayMode::CHECK_AUTO_PLAY_NEXT_ITEM
- : ContentUtils::PlayMode::PLAY_ONLY_THIS;
+void SetPathAndPlay(const std::shared_ptr<CFileItem>& item, const std::string& player, bool resume)
+{
+ item->SetProperty("check_resume", false);
- //! @todo get rid of special handling for movie versions
- if (item.GetStartOffset() != STARTOFFSET_RESUME &&
- item.GetVideoInfoTag()->m_type == MediaTypeMovie)
+ if (item->IsLiveTV()) // pvr tv or pvr radio?
+ {
+ g_application.PlayMedia(*item, "", PLAYLIST::TYPE_VIDEO);
+ }
+ else
+ {
+ if (!item->m_bIsFolder && item->IsVideoDb())
{
- auto videoItem = std::make_shared<CFileItem>(item);
- CGUIDialogVideoVersion::PlayVideoVersion(
- videoItem, [player, mode](const std::shared_ptr<CFileItem>& item)
- { VIDEO_UTILS::PlayItem(item, player, mode); });
+ item->SetProperty("original_listitem_url", item->GetPath());
+ item->SetPath(item->GetVideoInfoTag()->m_strFileNameAndPath);
}
+
+ // play the given/default video version, if multiple versions are available
+ item->SetProperty("prohibit_choose_video_version", true);
+
+ CVideoPlayActionProcessor proc{item, player};
+ if (resume && (item->GetStartOffset() == STARTOFFSET_RESUME ||
+ VIDEO_UTILS::GetItemResumeInformation(*item).isResumable))
+ proc.ProcessAction(VIDEO::GUILIB::ACTION_RESUME);
else
- VIDEO_UTILS::PlayItem(std::make_shared<CFileItem>(item), player, mode);
+ proc.ProcessAction(VIDEO::GUILIB::ACTION_PLAY_FROM_BEGINNING);
+
+ item->ClearProperty("prohibit_choose_video_version");
}
}
@@ -230,14 +343,14 @@ std::vector<std::string> GetPlayers(const CPlayerCoreFactory& playerCoreFactory,
bool CVideoResume::Execute(const std::shared_ptr<CFileItem>& itemIn) const
{
- CFileItem item(itemIn->GetItemToPlay());
+ const auto item{std::make_shared<CFileItem>(itemIn->GetItemToPlay())};
#ifdef HAS_OPTICAL_DRIVE
- if (item.IsDVD() || item.IsCDDA())
- return MEDIA_DETECT::CAutorun::PlayDisc(item.GetPath(), true, false);
+ if (item->IsDVD() || item->IsCDDA())
+ return MEDIA_DETECT::CAutorun::PlayDisc(item->GetPath(), true, false);
#endif
- item.SetStartOffset(STARTOFFSET_RESUME);
- SetPathAndPlay(item, "");
+ item->SetStartOffset(STARTOFFSET_RESUME);
+ SetPathAndPlay(item, "", true);
return true;
};
@@ -258,12 +371,12 @@ bool CVideoPlay::IsVisible(const CFileItem& item) const
bool CVideoPlay::Execute(const std::shared_ptr<CFileItem>& itemIn) const
{
- CFileItem item(itemIn->GetItemToPlay());
+ const auto item{std::make_shared<CFileItem>(itemIn->GetItemToPlay())};
#ifdef HAS_OPTICAL_DRIVE
- if (item.IsDVD() || item.IsCDDA())
- return MEDIA_DETECT::CAutorun::PlayDisc(item.GetPath(), true, true);
+ if (item->IsDVD() || item->IsCDDA())
+ return MEDIA_DETECT::CAutorun::PlayDisc(item->GetPath(), true, true);
#endif
- SetPathAndPlay(item, "");
+ SetPathAndPlay(item, "", false);
return true;
};
@@ -275,14 +388,14 @@ bool CVideoPlayUsing::IsVisible(const CFileItem& item) const
bool CVideoPlayUsing::Execute(const std::shared_ptr<CFileItem>& itemIn) const
{
- CFileItem item{itemIn->GetItemToPlay()};
+ const auto item{std::make_shared<CFileItem>(itemIn->GetItemToPlay())};
const CPlayerCoreFactory& playerCoreFactory{CServiceBroker::GetPlayerCoreFactory()};
- const std::vector<std::string> players{GetPlayers(playerCoreFactory, item)};
+ const std::vector<std::string> players{GetPlayers(playerCoreFactory, *item)};
const std::string player{playerCoreFactory.SelectPlayerDialog(players)};
if (!player.empty())
{
- SetPathAndPlay(item, player);
+ SetPathAndPlay(item, player, false);
return true;
}
return false;
diff --git a/xbmc/video/ContextMenus.h b/xbmc/video/ContextMenus.h
index e220670b02..6728f58d54 100644
--- a/xbmc/video/ContextMenus.h
+++ b/xbmc/video/ContextMenus.h
@@ -86,6 +86,13 @@ struct CVideoBrowse : CStaticContextMenuAction
bool Execute(const std::shared_ptr<CFileItem>& item) const override;
};
+struct CVideoChooseVersion : CStaticContextMenuAction
+{
+ CVideoChooseVersion() : CStaticContextMenuAction(40208) {} // Choose version
+ bool IsVisible(const CFileItem& item) const override;
+ bool Execute(const std::shared_ptr<CFileItem>& item) const override;
+};
+
struct CVideoResume : IContextMenuItem
{
std::string GetLabel(const CFileItem& item) const override;
diff --git a/xbmc/video/VideoDatabase.cpp b/xbmc/video/VideoDatabase.cpp
index 1fcd532b62..cc872df413 100644
--- a/xbmc/video/VideoDatabase.cpp
+++ b/xbmc/video/VideoDatabase.cpp
@@ -4290,7 +4290,8 @@ CVideoInfoTag CVideoDatabase::GetDetailsForMovie(const dbiplus::sql_record* cons
if (getDetails)
{
- GetCast(details.m_iDbId, MediaTypeMovie, details.m_cast);
+ if (getDetails & VideoDbDetailsCast)
+ GetCast(details.m_iDbId, MediaTypeMovie, details.m_cast);
if (getDetails & VideoDbDetailsTag)
GetTags(details.m_iDbId, MediaTypeMovie, details.m_tags);
diff --git a/xbmc/video/VideoInfoDownloader.cpp b/xbmc/video/VideoInfoDownloader.cpp
index 5d0fb1f1b7..cd0a1d850d 100644
--- a/xbmc/video/VideoInfoDownloader.cpp
+++ b/xbmc/video/VideoInfoDownloader.cpp
@@ -80,7 +80,7 @@ void CVideoInfoDownloader::Process()
}
else if (m_state == GET_DETAILS)
{
- if (!GetDetails(m_url, m_movieDetails))
+ if (!GetDetails(m_uniqueIDs, m_url, m_movieDetails))
CLog::Log(LOGERROR, "{}: Error getting details from {}", __FUNCTION__,
m_url.GetFirstThumbUrl());
}
@@ -147,12 +147,14 @@ bool CVideoInfoDownloader::GetArtwork(CVideoInfoTag &details)
return m_info->GetArtwork(*m_http, details);
}
-bool CVideoInfoDownloader::GetDetails(const CScraperUrl &url,
- CVideoInfoTag &movieDetails,
- CGUIDialogProgress *pProgress /* = NULL */)
+bool CVideoInfoDownloader::GetDetails(const std::unordered_map<std::string, std::string>& uniqueIDs,
+ const CScraperUrl& url,
+ CVideoInfoTag& movieDetails,
+ CGUIDialogProgress* pProgress /* = NULL */)
{
//CLog::Log(LOGDEBUG,"CVideoInfoDownloader::GetDetails({})", url.m_strURL);
m_url = url;
+ m_uniqueIDs = uniqueIDs;
m_movieDetails = movieDetails;
// fill in the defaults
@@ -179,7 +181,7 @@ bool CVideoInfoDownloader::GetDetails(const CScraperUrl &url,
return true;
}
else // unthreaded
- return m_info->GetVideoDetails(*m_http, url, true/*fMovie*/, movieDetails);
+ return m_info->GetVideoDetails(*m_http, m_uniqueIDs, url, true /*fMovie*/, movieDetails);
}
bool CVideoInfoDownloader::GetEpisodeDetails(const CScraperUrl &url,
@@ -214,7 +216,7 @@ bool CVideoInfoDownloader::GetEpisodeDetails(const CScraperUrl &url,
return true;
}
else // unthreaded
- return m_info->GetVideoDetails(*m_http, url, false/*fMovie*/, movieDetails);
+ return m_info->GetVideoDetails(*m_http, m_uniqueIDs, url, false /*fMovie*/, movieDetails);
}
bool CVideoInfoDownloader::GetEpisodeList(const CScraperUrl& url,
diff --git a/xbmc/video/VideoInfoDownloader.h b/xbmc/video/VideoInfoDownloader.h
index a85603fe06..4479522a33 100644
--- a/xbmc/video/VideoInfoDownloader.h
+++ b/xbmc/video/VideoInfoDownloader.h
@@ -54,7 +54,10 @@ public:
*/
bool GetArtwork(CVideoInfoTag &details);
- bool GetDetails(const CScraperUrl& url, CVideoInfoTag &movieDetails, CGUIDialogProgress *pProgress = NULL);
+ bool GetDetails(const std::unordered_map<std::string, std::string>& uniqueIDs,
+ const CScraperUrl& url,
+ CVideoInfoTag& movieDetails,
+ CGUIDialogProgress* pProgress = NULL);
bool GetEpisodeDetails(const CScraperUrl& url, CVideoInfoTag &movieDetails, CGUIDialogProgress *pProgress = NULL);
bool GetEpisodeList(const CScraperUrl& url, VIDEO::EPISODELIST& details, CGUIDialogProgress *pProgress = NULL);
@@ -70,6 +73,7 @@ protected:
XFILE::CCurlFile* m_http;
std::string m_movieTitle;
int m_movieYear;
+ std::unordered_map<std::string, std::string> m_uniqueIDs;
MOVIELIST m_movieList;
CVideoInfoTag m_movieDetails;
CScraperUrl m_url;
diff --git a/xbmc/video/VideoInfoScanner.cpp b/xbmc/video/VideoInfoScanner.cpp
index f1fcf6d4df..e70b1ee0a1 100644
--- a/xbmc/video/VideoInfoScanner.cpp
+++ b/xbmc/video/VideoInfoScanner.cpp
@@ -654,6 +654,35 @@ namespace VIDEO
movieTitle = tag->GetTitle();
movieYear = tag->GetYear(); // movieYear is expected to be >= 0
}
+
+ std::string identifierType;
+ std::string identifier;
+ long lResult = -1;
+ if (info2->IsPython() && CUtil::GetFilenameIdentifier(movieTitle, identifierType, identifier))
+ {
+ const std::unordered_map<std::string, std::string> uniqueIDs{{identifierType, identifier}};
+ if (GetDetails(pItem, uniqueIDs, url, info2,
+ (result == CInfoScanner::COMBINED_NFO || result == CInfoScanner::OVERRIDE_NFO)
+ ? loader.get()
+ : nullptr,
+ pDlgProgress))
+ {
+ if ((lResult = AddVideo(pItem, info2->Content(), false, useLocal)) < 0)
+ return INFO_ERROR;
+
+ if (fetchEpisodes)
+ {
+ INFO_RET ret = RetrieveInfoForEpisodes(pItem, lResult, info2, useLocal, pDlgProgress);
+ if (ret == INFO_ADDED)
+ {
+ m_database.SetPathHash(pItem->GetPath(), pItem->GetProperty("hash").asString());
+ return INFO_ADDED;
+ }
+ }
+ return INFO_ADDED;
+ }
+ }
+
if (pURL && pURL->HasUrls())
url = *pURL;
else if ((retVal = FindVideo(movieTitle, movieYear, info2, url, pDlgProgress)) <= 0)
@@ -661,11 +690,12 @@ namespace VIDEO
CLog::Log(LOGDEBUG, "VideoInfoScanner: Fetching url '{}' using {} scraper (content: '{}')",
url.GetFirstThumbUrl(), info2->Name(), TranslateContent(info2->Content()));
+ const std::unordered_map<std::string, std::string> uniqueIDs{{identifierType, identifier}};
- long lResult = -1;
- if (GetDetails(pItem, url, info2,
- (result == CInfoScanner::COMBINED_NFO ||
- result == CInfoScanner::OVERRIDE_NFO) ? loader.get() : nullptr,
+ if (GetDetails(pItem, {}, url, info2,
+ (result == CInfoScanner::COMBINED_NFO || result == CInfoScanner::OVERRIDE_NFO)
+ ? loader.get()
+ : nullptr,
pDlgProgress))
{
if ((lResult = AddVideo(pItem, info2->Content(), false, useLocal)) < 0)
@@ -736,6 +766,24 @@ namespace VIDEO
movieTitle = tag->GetTitle();
movieYear = tag->GetYear(); // movieYear is expected to be >= 0
}
+
+ std::string identifierType;
+ std::string identifier;
+ if (info2->IsPython() && CUtil::GetFilenameIdentifier(movieTitle, identifierType, identifier))
+ {
+ const std::unordered_map<std::string, std::string> uniqueIDs{{identifierType, identifier}};
+ if (GetDetails(pItem, uniqueIDs, url, info2,
+ (result == CInfoScanner::COMBINED_NFO || result == CInfoScanner::OVERRIDE_NFO)
+ ? loader.get()
+ : nullptr,
+ pDlgProgress))
+ {
+ if (AddVideo(pItem, info2->Content(), bDirNames, useLocal) < 0)
+ return INFO_ERROR;
+ return INFO_ADDED;
+ }
+ }
+
if (pURL && pURL->HasUrls())
url = *pURL;
else if ((retVal = FindVideo(movieTitle, movieYear, info2, url, pDlgProgress)) <= 0)
@@ -744,9 +792,10 @@ namespace VIDEO
CLog::Log(LOGDEBUG, "VideoInfoScanner: Fetching url '{}' using {} scraper (content: '{}')",
url.GetFirstThumbUrl(), info2->Name(), TranslateContent(info2->Content()));
- if (GetDetails(pItem, url, info2,
- (result == CInfoScanner::COMBINED_NFO ||
- result == CInfoScanner::OVERRIDE_NFO) ? loader.get() : nullptr,
+ if (GetDetails(pItem, {}, url, info2,
+ (result == CInfoScanner::COMBINED_NFO || result == CInfoScanner::OVERRIDE_NFO)
+ ? loader.get()
+ : nullptr,
pDlgProgress))
{
int dbId = AddVideo(pItem, info2->Content(), bDirNames, useLocal);
@@ -817,6 +866,24 @@ namespace VIDEO
movieTitle = tag->GetTitle();
movieYear = tag->GetYear(); // movieYear is expected to be >= 0
}
+
+ std::string identifierType;
+ std::string identifier;
+ if (info2->IsPython() && CUtil::GetFilenameIdentifier(movieTitle, identifierType, identifier))
+ {
+ const std::unordered_map<std::string, std::string> uniqueIDs{{identifierType, identifier}};
+ if (GetDetails(pItem, uniqueIDs, url, info2,
+ (result == CInfoScanner::COMBINED_NFO || result == CInfoScanner::OVERRIDE_NFO)
+ ? loader.get()
+ : nullptr,
+ pDlgProgress))
+ {
+ if (AddVideo(pItem, info2->Content(), bDirNames, useLocal) < 0)
+ return INFO_ERROR;
+ return INFO_ADDED;
+ }
+ }
+
if (pURL && pURL->HasUrls())
url = *pURL;
else if ((retVal = FindVideo(movieTitle, movieYear, info2, url, pDlgProgress)) <= 0)
@@ -825,9 +892,10 @@ namespace VIDEO
CLog::Log(LOGDEBUG, "VideoInfoScanner: Fetching url '{}' using {} scraper (content: '{}')",
url.GetFirstThumbUrl(), info2->Name(), TranslateContent(info2->Content()));
- if (GetDetails(pItem, url, info2,
- (result == CInfoScanner::COMBINED_NFO ||
- result == CInfoScanner::OVERRIDE_NFO) ? loader.get() : nullptr,
+ if (GetDetails(pItem, {}, url, info2,
+ (result == CInfoScanner::COMBINED_NFO || result == CInfoScanner::OVERRIDE_NFO)
+ ? loader.get()
+ : nullptr,
pDlgProgress))
{
if (AddVideo(pItem, info2->Content(), bDirNames, useLocal) < 0)
@@ -2031,7 +2099,9 @@ namespace VIDEO
return INFO_ADDED;
}
- bool CVideoInfoScanner::GetDetails(CFileItem *pItem, CScraperUrl &url,
+ bool CVideoInfoScanner::GetDetails(CFileItem* pItem,
+ const std::unordered_map<std::string, std::string>& uniqueIDs,
+ CScraperUrl& url,
const ScraperPtr& scraper,
IVideoInfoTagLoader* loader,
CGUIDialogProgress* pDialog /* = NULL */)
@@ -2042,7 +2112,7 @@ namespace VIDEO
m_handle->SetText(url.GetTitle());
CVideoInfoDownloader imdb(scraper);
- bool ret = imdb.GetDetails(url, movieDetails, pDialog);
+ bool ret = imdb.GetDetails(uniqueIDs, url, movieDetails, pDialog);
if (ret)
{
diff --git a/xbmc/video/VideoInfoScanner.h b/xbmc/video/VideoInfoScanner.h
index ba24585b59..9f49103be7 100644
--- a/xbmc/video/VideoInfoScanner.h
+++ b/xbmc/video/VideoInfoScanner.h
@@ -144,14 +144,17 @@ namespace VIDEO
/*! \brief Retrieve detailed information for an item from an online source, optionally supplemented with local data
@todo sort out some better return codes.
\param pItem item to retrieve online details for.
+ \param uniqueIDs Unique IDs for additional information for scrapers.
\param url URL to use to retrieve online details.
\param scraper Scraper that handles parsing the online data.
\param nfoFile if set, we override the online data with the locally supplied data. Defaults to NULL.
\param pDialog progress dialog to update and check for cancellation during processing. Defaults to NULL.
\return true if information is found, false if an error occurred, the lookup was cancelled, or no information was found.
*/
- bool GetDetails(CFileItem *pItem, CScraperUrl &url,
- const ADDON::ScraperPtr &scraper,
+ bool GetDetails(CFileItem* pItem,
+ const std::unordered_map<std::string, std::string>& uniqueIDs,
+ CScraperUrl& url,
+ const ADDON::ScraperPtr& scraper,
VIDEO::IVideoInfoTagLoader* nfoFile = nullptr,
CGUIDialogProgress* pDialog = nullptr);
diff --git a/xbmc/video/dialogs/GUIDialogVideoInfo.cpp b/xbmc/video/dialogs/GUIDialogVideoInfo.cpp
index eae46427ab..df4582d229 100644
--- a/xbmc/video/dialogs/GUIDialogVideoInfo.cpp
+++ b/xbmc/video/dialogs/GUIDialogVideoInfo.cpp
@@ -67,7 +67,6 @@
using namespace XFILE::VIDEODATABASEDIRECTORY;
using namespace XFILE;
using namespace KODI::MESSAGING;
-using namespace VIDEO::GUILIB;
#define CONTROL_IMAGE 3
#define CONTROL_TEXTAREA 4
@@ -712,15 +711,18 @@ void CGUIDialogVideoInfo::ClearCastList()
namespace
{
-class CVideoPlayActionProcessor : public CVideoPlayActionProcessorBase
+class CVideoPlayActionProcessor : public VIDEO::GUILIB::CVideoPlayActionProcessorBase
{
public:
- explicit CVideoPlayActionProcessor(CFileItem& item) : CVideoPlayActionProcessorBase(item) {}
+ explicit CVideoPlayActionProcessor(const std::shared_ptr<CFileItem>& item)
+ : CVideoPlayActionProcessorBase(item)
+ {
+ }
protected:
bool OnResumeSelected() override
{
- m_item.SetStartOffset(STARTOFFSET_RESUME);
+ m_item->SetStartOffset(STARTOFFSET_RESUME);
Play();
return true;
}
@@ -734,21 +736,11 @@ protected:
private:
void Play()
{
- m_item.SetProperty("playlist_type_hint", PLAYLIST::TYPE_VIDEO);
- const ContentUtils::PlayMode mode{m_item.GetProperty("CheckAutoPlayNextItem").asBoolean()
+ m_item->SetProperty("playlist_type_hint", PLAYLIST::TYPE_VIDEO);
+ const ContentUtils::PlayMode mode{m_item->GetProperty("CheckAutoPlayNextItem").asBoolean()
? ContentUtils::PlayMode::CHECK_AUTO_PLAY_NEXT_ITEM
: ContentUtils::PlayMode::PLAY_ONLY_THIS};
-
- //! @todo get rid of special handling for movie versions
- if (m_item.GetStartOffset() != STARTOFFSET_RESUME &&
- m_item.GetVideoInfoTag()->m_type == MediaTypeMovie)
- {
- CGUIDialogVideoVersion::PlayVideoVersion(std::make_shared<CFileItem>(m_item),
- [mode](const std::shared_ptr<CFileItem>& item)
- { VIDEO_UTILS::PlayItem(item, "", mode); });
- }
- else
- VIDEO_UTILS::PlayItem(std::make_shared<CFileItem>(m_item), "", mode);
+ VIDEO_UTILS::PlayItem(m_item, "", mode);
}
};
} // unnamed namespace
@@ -797,22 +789,22 @@ void CGUIDialogVideoInfo::Play(bool resume)
if (resume)
{
- CVideoPlayActionProcessor proc{*m_movieItem};
- proc.Process(PLAY_ACTION_RESUME);
+ CVideoPlayActionProcessor proc{m_movieItem};
+ proc.ProcessAction(VIDEO::GUILIB::ACTION_RESUME);
}
else
{
if (GetControl(CONTROL_BTN_RESUME))
{
// if dialog has a resume button, play button has always the purpose to start from beginning
- CVideoPlayActionProcessor proc{*m_movieItem};
- proc.Process(PLAY_ACTION_PLAY_FROM_BEGINNING);
+ CVideoPlayActionProcessor proc{m_movieItem};
+ proc.ProcessAction(VIDEO::GUILIB::ACTION_PLAY_FROM_BEGINNING);
}
else
{
// play button acts according to default play action setting
- CVideoPlayActionProcessor proc{*m_movieItem};
- proc.Process();
+ CVideoPlayActionProcessor proc{m_movieItem};
+ proc.ProcessDefaultAction();
if (proc.UserCancelled())
{
// The Resume dialog was closed without any choice
diff --git a/xbmc/video/dialogs/GUIDialogVideoVersion.cpp b/xbmc/video/dialogs/GUIDialogVideoVersion.cpp
index ea85194864..800d4ff311 100644
--- a/xbmc/video/dialogs/GUIDialogVideoVersion.cpp
+++ b/xbmc/video/dialogs/GUIDialogVideoVersion.cpp
@@ -11,16 +11,13 @@
#include "FileItem.h"
#include "GUIUserMessages.h"
#include "ServiceBroker.h"
-#include "Util.h"
-#include "application/Application.h"
+#include "URL.h"
#include "cores/VideoPlayer/DVDFileInfo.h"
#include "dialogs/GUIDialogContextMenu.h"
#include "dialogs/GUIDialogFileBrowser.h"
#include "dialogs/GUIDialogOK.h"
#include "dialogs/GUIDialogSelect.h"
#include "dialogs/GUIDialogYesNo.h"
-#include "filesystem/Directory.h"
-#include "filesystem/VideoDatabaseDirectory.h"
#include "guilib/GUIComponent.h"
#include "guilib/GUIImage.h"
#include "guilib/GUIKeyboardFactory.h"
@@ -28,29 +25,24 @@
#include "guilib/GUIWindowManager.h"
#include "guilib/LocalizeStrings.h"
#include "input/Key.h"
-#include "profiles/ProfileManager.h"
-#include "settings/AdvancedSettings.h"
+#include "playlists/PlayListTypes.h"
#include "settings/MediaSourceSettings.h"
-#include "settings/SettingUtils.h"
#include "settings/Settings.h"
#include "settings/SettingsComponent.h"
-#include "settings/lib/Setting.h"
#include "storage/MediaManager.h"
-#include "utils/ExecString.h"
#include "utils/FileExtensionProvider.h"
#include "utils/SortUtils.h"
#include "utils/StringUtils.h"
#include "utils/URIUtils.h"
#include "utils/Variant.h"
#include "utils/log.h"
-#include "video/VideoDbUrl.h"
#include "video/VideoInfoTag.h"
-#include "video/VideoItemArtworkHandler.h"
#include "video/VideoThumbLoader.h"
+#include "video/VideoUtils.h"
#include "video/dialogs/GUIDialogVideoInfo.h"
+#include "video/guilib/VideoPlayActionProcessor.h"
#include <algorithm>
-#include <iterator>
#include <string>
static constexpr unsigned int CONTROL_LABEL_MODE = 1;
@@ -90,6 +82,12 @@ bool CGUIDialogVideoVersion::OnMessage(CGUIMessage& message)
{
switch (message.GetMessage())
{
+ case GUI_MSG_WINDOW_INIT:
+ {
+ m_cancelled = false;
+ break;
+ }
+
case GUI_MSG_WINDOW_DEINIT:
{
ClearVideoVersionList();
@@ -121,15 +119,15 @@ bool CGUIDialogVideoVersion::OnMessage(CGUIMessage& message)
}
else
{
- CONTROL_ENABLE_ON_CONDITION(CONTROL_BUTTON_REMOVE, !m_playMode);
- CONTROL_ENABLE_ON_CONDITION(CONTROL_BUTTON_RENAME, !m_playMode);
- CONTROL_ENABLE_ON_CONDITION(CONTROL_BUTTON_SET_DEFAULT, !m_playMode);
+ CONTROL_ENABLE_ON_CONDITION(CONTROL_BUTTON_REMOVE, m_mode == Mode::MANAGE);
+ CONTROL_ENABLE_ON_CONDITION(CONTROL_BUTTON_RENAME, m_mode == Mode::MANAGE);
+ CONTROL_ENABLE_ON_CONDITION(CONTROL_BUTTON_SET_DEFAULT, m_mode == Mode::MANAGE);
}
- if (!m_playMode)
+ if (m_mode == Mode::MANAGE)
SET_CONTROL_FOCUS(CONTROL_BUTTON_PLAY, 0);
else
- Play();
+ CloseAll();
}
}
else if (control == CONTROL_LIST_EXTRAS_VERSION)
@@ -148,13 +146,13 @@ bool CGUIDialogVideoVersion::OnMessage(CGUIMessage& message)
CONTROL_DISABLE(CONTROL_BUTTON_SET_DEFAULT);
- CONTROL_ENABLE_ON_CONDITION(CONTROL_BUTTON_REMOVE, !m_playMode);
- CONTROL_ENABLE_ON_CONDITION(CONTROL_BUTTON_RENAME, !m_playMode);
+ CONTROL_ENABLE_ON_CONDITION(CONTROL_BUTTON_REMOVE, m_mode == Mode::MANAGE);
+ CONTROL_ENABLE_ON_CONDITION(CONTROL_BUTTON_RENAME, m_mode == Mode::MANAGE);
- if (!m_playMode)
+ if (m_mode == Mode::MANAGE)
SET_CONTROL_FOCUS(CONTROL_BUTTON_PLAY, 0);
else
- Play();
+ CloseAll();
}
}
else if (control == CONTROL_BUTTON_PLAY)
@@ -193,10 +191,16 @@ bool CGUIDialogVideoVersion::OnMessage(CGUIMessage& message)
return CGUIDialog::OnMessage(message);
}
+bool CGUIDialogVideoVersion::OnBack(int actionID)
+{
+ m_cancelled = true;
+ return CGUIDialog::OnBack(actionID);
+}
+
void CGUIDialogVideoVersion::OnInitWindow()
{
// set working mode
- SET_CONTROL_LABEL(CONTROL_LABEL_MODE, !m_playMode ? "manage" : "play");
+ SET_CONTROL_LABEL(CONTROL_LABEL_MODE, m_mode == Mode::MANAGE ? "manage" : "choose");
// set window title
std::string title = m_videoItem->GetVideoInfoTag()->GetTitle();
@@ -205,8 +209,9 @@ void CGUIDialogVideoVersion::OnInitWindow()
if (year != 0)
title = StringUtils::Format("{} ({})", title, year);
- SET_CONTROL_LABEL(CONTROL_LABEL_TITLE,
- StringUtils::Format(g_localizeStrings.Get(!m_playMode ? 40022 : 40023), title));
+ SET_CONTROL_LABEL(
+ CONTROL_LABEL_TITLE,
+ StringUtils::Format(g_localizeStrings.Get(m_mode == Mode::MANAGE ? 40022 : 40023), title));
// bind primary and extras version lists
CGUIMessage msg1(GUI_MSG_LABEL_BIND, GetID(), CONTROL_LIST_PRIMARY_VERSION, 0, 0,
@@ -221,11 +226,11 @@ void CGUIDialogVideoVersion::OnInitWindow()
CONTROL_DISABLE(CONTROL_BUTTON_REMOVE);
CONTROL_DISABLE(CONTROL_BUTTON_SET_DEFAULT);
- CONTROL_ENABLE_ON_CONDITION(CONTROL_BUTTON_ADD_VERSION, !m_playMode);
- CONTROL_ENABLE_ON_CONDITION(CONTROL_BUTTON_ADD_EXTRAS, !m_playMode);
- CONTROL_ENABLE_ON_CONDITION(CONTROL_BUTTON_CHOOSE_ART, !m_playMode);
- CONTROL_ENABLE_ON_CONDITION(CONTROL_BUTTON_RENAME, !m_playMode);
- CONTROL_ENABLE_ON_CONDITION(CONTROL_BUTTON_PLAY, !m_playMode);
+ CONTROL_ENABLE_ON_CONDITION(CONTROL_BUTTON_ADD_VERSION, m_mode == Mode::MANAGE);
+ CONTROL_ENABLE_ON_CONDITION(CONTROL_BUTTON_ADD_EXTRAS, m_mode == Mode::MANAGE);
+ CONTROL_ENABLE_ON_CONDITION(CONTROL_BUTTON_CHOOSE_ART, m_mode == Mode::MANAGE);
+ CONTROL_ENABLE_ON_CONDITION(CONTROL_BUTTON_RENAME, m_mode == Mode::MANAGE);
+ CONTROL_ENABLE_ON_CONDITION(CONTROL_BUTTON_PLAY, m_mode == Mode::MANAGE);
CGUIDialog::OnInitWindow();
}
@@ -274,7 +279,7 @@ void CGUIDialogVideoVersion::RefreshVideoVersionList()
m_database.GetDefaultVideoVersion(itemType, dbId, *m_selectedVideoVersion.get());
}
-void CGUIDialogVideoVersion::SetVideoItem(const std::shared_ptr<CFileItem>& item, bool playMode)
+void CGUIDialogVideoVersion::SetVideoItem(const std::shared_ptr<CFileItem>& item)
{
if (item == nullptr || !item->HasVideoInfoTag() ||
item->GetVideoInfoTag()->m_type != MediaTypeMovie)
@@ -284,7 +289,6 @@ void CGUIDialogVideoVersion::SetVideoItem(const std::shared_ptr<CFileItem>& item
}
m_videoItem = item;
- m_playMode = playMode;
ClearVideoVersionList();
@@ -312,7 +316,7 @@ void CGUIDialogVideoVersion::SetVideoItem(const std::shared_ptr<CFileItem>& item
loader.LoadItem(item.get());
}
-void CGUIDialogVideoVersion::Play()
+void CGUIDialogVideoVersion::CloseAll()
{
// close our dialog
Close(true);
@@ -323,15 +327,51 @@ void CGUIDialogVideoVersion::Play()
WINDOW_DIALOG_VIDEO_INFO);
if (dialog)
dialog->Close(true);
+}
- // set the selected video version as default temporarily
- SetDefaultVideoVersion(*m_selectedVideoVersion.get());
+namespace
+{
+class CVideoPlayActionProcessor : public VIDEO::GUILIB::CVideoPlayActionProcessorBase
+{
+public:
+ explicit CVideoPlayActionProcessor(const std::shared_ptr<CFileItem>& item,
+ const std::shared_ptr<CFileItem>& videoVersion)
+ : CVideoPlayActionProcessorBase(item, videoVersion)
+ {
+ }
+
+protected:
+ bool OnResumeSelected() override
+ {
+ m_item->SetStartOffset(STARTOFFSET_RESUME);
+ Play();
+ return true;
+ }
+
+ bool OnPlaySelected() override
+ {
+ Play();
+ return true;
+ }
+
+private:
+ void Play()
+ {
+ m_item->SetProperty("playlist_type_hint", PLAYLIST::TYPE_VIDEO);
+ const ContentUtils::PlayMode mode{m_item->GetProperty("CheckAutoPlayNextItem").asBoolean()
+ ? ContentUtils::PlayMode::CHECK_AUTO_PLAY_NEXT_ITEM
+ : ContentUtils::PlayMode::PLAY_ONLY_THIS};
+ VIDEO_UTILS::PlayItem(m_item, "", mode);
+ }
+};
+} // unnamed namespace
- // play the video item
- m_playCallback(m_videoItem);
+void CGUIDialogVideoVersion::Play()
+{
+ CloseAll();
- // restore the default video version
- SetDefaultVideoVersion(*m_defaultVideoVersion.get());
+ CVideoPlayActionProcessor proc{m_videoItem, m_selectedVideoVersion};
+ proc.ProcessDefaultAction();
}
void CGUIDialogVideoVersion::Remove()
@@ -599,77 +639,53 @@ void CGUIDialogVideoVersion::SetSelectedVideoVersion(const std::shared_ptr<CFile
m_selectedVideoVersion = std::make_unique<CFileItem>(*version);
}
-void CGUIDialogVideoVersion::SetPlayCallback(VideoVersionPlayCallback callback)
-{
- m_playCallback = callback;
-}
-
-void CGUIDialogVideoVersion::PlayVideoItem(const std::shared_ptr<CFileItem>& item)
-{
- CGUIMessage msg(GUI_MSG_EXECUTE, 0, 0);
- msg.SetStringParam(CExecString("PlayMedia", *item.get(), "noresume").GetExecString());
- CServiceBroker::GetGUI()->GetWindowManager().SendMessage(msg);
-}
-
void CGUIDialogVideoVersion::ManageVideoVersion(const std::shared_ptr<CFileItem>& item)
{
CGUIDialogVideoVersion* dialog =
CServiceBroker::GetGUI()->GetWindowManager().GetWindow<CGUIDialogVideoVersion>(
WINDOW_DIALOG_VIDEO_VERSION);
if (!dialog)
+ {
+ CLog::LogF(LOGERROR, "Unable to get WINDOW_DIALOG_VIDEO_VERSION instance!");
return;
+ }
- dialog->SetVideoItem(item, false);
- dialog->SetPlayCallback(PlayVideoItem);
+ dialog->SetVideoItem(item);
+ dialog->SetMode(Mode::MANAGE);
dialog->Open();
}
-void CGUIDialogVideoVersion::PlayVideoVersion(const std::shared_ptr<CFileItem>& item,
- VideoVersionPlayCallback callback)
+CGUIDialogVideoVersion::VersionSelectResult CGUIDialogVideoVersion::ChooseVideoVersion(
+ const std::shared_ptr<CFileItem>& item)
{
- // play the specified video version
- if (item->GetVideoInfoTag()->m_idVideoVersion > 0)
- {
- callback(item);
- return;
- }
-
- // play the default video version
- if (CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool(
- CSettings::SETTING_VIDEOPLAYER_PLAYDEFAULTVERSION))
+ if (!item->HasVideoInfoTag())
{
- auto temp = item;
-
- // play a temporary copy of the item if it is video version folder
- if (item->GetVideoInfoTag()->m_idVideoVersion == VIDEO_VERSION_ID_ALL &&
- CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool(
- CSettings::SETTING_VIDEOLIBRARY_SHOWVIDEOVERSIONSASFOLDER))
- {
- temp = std::make_shared<CFileItem>(*item);
- temp->m_bIsFolder = false;
- }
-
- callback(temp);
- return;
+ CLog::LogF(LOGWARNING, "Item is not a video. path={}", item->GetPath());
+ return {true, {}};
}
- // play the video item directly
- if (!item->GetVideoInfoTag()->m_hasVideoVersions)
+ if (!item->HasVideoVersions())
{
- callback(item);
- return;
+ CLog::LogF(LOGWARNING, "Item has no video versions. path={}", item->GetPath());
+ return {true, {}};
}
- // prompt to play selected video version
- CGUIDialogVideoVersion* dialog =
+ // prompt to select a video version
+ CGUIDialogVideoVersion* dialog{
CServiceBroker::GetGUI()->GetWindowManager().GetWindow<CGUIDialogVideoVersion>(
- WINDOW_DIALOG_VIDEO_VERSION_PLAY);
+ WINDOW_DIALOG_VIDEO_VERSION_SELECT)};
if (!dialog)
- return;
+ {
+ CLog::LogF(LOGERROR, "Unable to get WINDOW_DIALOG_VIDEO_VERSION_SELECT instance!");
+ return {true, {}};
+ }
- dialog->SetVideoItem(item, true);
- dialog->SetPlayCallback(PlayVideoItem);
+ dialog->SetVideoItem(item);
+ dialog->SetMode(Mode::CHOOSE);
dialog->Open();
+
+ // get the selected video version from dialog if not cancelled
+ return {dialog->m_cancelled, dialog->m_selectedVideoVersion};
}
int CGUIDialogVideoVersion::ManageVideoVersionContextMenu(const std::shared_ptr<CFileItem>& version)
@@ -695,7 +711,8 @@ int CGUIDialogVideoVersion::ManageVideoVersionContextMenu(const std::shared_ptr<
videoItem))
return -1;
- dialog->SetVideoItem(std::make_shared<CFileItem>(videoItem), false);
+ dialog->SetVideoItem(std::make_shared<CFileItem>(videoItem));
+ dialog->SetMode(Mode::MANAGE);
dialog->SetSelectedVideoVersion(version);
switch (static_cast<CONTEXT_BUTTON>(button))
diff --git a/xbmc/video/dialogs/GUIDialogVideoVersion.h b/xbmc/video/dialogs/GUIDialogVideoVersion.h
index bb2c72eff9..b408f3c782 100644
--- a/xbmc/video/dialogs/GUIDialogVideoVersion.h
+++ b/xbmc/video/dialogs/GUIDialogVideoVersion.h
@@ -25,23 +25,33 @@ public:
CGUIDialogVideoVersion(int id);
~CGUIDialogVideoVersion(void) override;
bool OnMessage(CGUIMessage& message) override;
- void SetVideoItem(const std::shared_ptr<CFileItem>& item, bool playMode);
+ bool OnBack(int actionID) override;
+
+ enum class Mode
+ {
+ MANAGE,
+ CHOOSE,
+ };
+ void SetMode(Mode mode) { m_mode = mode; }
+ void SetVideoItem(const std::shared_ptr<CFileItem>& item);
+
static std::tuple<int, std::string> NewVideoVersion();
static bool ConvertVideoVersion(const std::shared_ptr<CFileItem>& item);
static bool ProcessVideoVersion(VideoDbContentType itemType, int dbId);
static int SelectVideoVersion(const std::shared_ptr<CFileItem>& item);
static void ManageVideoVersion(const std::shared_ptr<CFileItem>& item);
- static void PlayVideoItem(const std::shared_ptr<CFileItem>& item);
static std::string GenerateExtrasVideoVersion(const std::string& extrasRoot,
const std::string& extrasPath);
static std::string GenerateExtrasVideoVersion(const std::string& extrasPath);
-
- using VideoVersionPlayCallback = std::function<void(const std::shared_ptr<CFileItem>& item)>;
- static void PlayVideoVersion(const std::shared_ptr<CFileItem>& item,
- VideoVersionPlayCallback play);
-
static int ManageVideoVersionContextMenu(const std::shared_ptr<CFileItem>& version);
+ struct VersionSelectResult
+ {
+ bool cancelled{false};
+ std::shared_ptr<CFileItem> selected;
+ };
+ static VersionSelectResult ChooseVideoVersion(const std::shared_ptr<CFileItem>& item);
+
protected:
void OnInitWindow() override;
@@ -50,7 +60,6 @@ private:
void SetSelectedVideoVersion(const std::shared_ptr<CFileItem>& version);
void ClearVideoVersionList();
void RefreshVideoVersionList();
- void SetPlayCallback(VideoVersionPlayCallback callback);
void AddVideoVersion(bool primary);
void Play();
void AddVersion();
@@ -59,15 +68,14 @@ private:
void SetDefault();
void Remove();
void ChooseArt();
-
- VideoVersionPlayCallback m_playCallback;
+ void CloseAll();
std::shared_ptr<CFileItem> m_videoItem;
- bool m_playMode{false};
-
+ Mode m_mode{Mode::MANAGE};
+ bool m_cancelled{false};
CVideoDatabase m_database;
std::unique_ptr<CFileItemList> m_primaryVideoVersionList;
std::unique_ptr<CFileItemList> m_extrasVideoVersionList;
std::unique_ptr<CFileItem> m_defaultVideoVersion;
- std::unique_ptr<CFileItem> m_selectedVideoVersion;
+ std::shared_ptr<CFileItem> m_selectedVideoVersion;
};
diff --git a/xbmc/video/guilib/CMakeLists.txt b/xbmc/video/guilib/CMakeLists.txt
index b0a93d5234..a953270624 100644
--- a/xbmc/video/guilib/CMakeLists.txt
+++ b/xbmc/video/guilib/CMakeLists.txt
@@ -1,9 +1,10 @@
set(SOURCES VideoPlayActionProcessor.cpp
- VideoSelectActionProcessor.cpp)
+ VideoSelectActionProcessor.cpp
+ VideoActionProcessorHelper.cpp)
-set(HEADERS VideoPlayAction.h
+set(HEADERS VideoAction.h
VideoPlayActionProcessor.h
- VideoSelectAction.h
- VideoSelectActionProcessor.h)
+ VideoSelectActionProcessor.h
+ VideoActionProcessorHelper.h)
core_add_library(video_guilib)
diff --git a/xbmc/video/guilib/VideoAction.h b/xbmc/video/guilib/VideoAction.h
new file mode 100644
index 0000000000..d2efd86d3c
--- /dev/null
+++ b/xbmc/video/guilib/VideoAction.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2023 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#pragma once
+
+namespace VIDEO
+{
+namespace GUILIB
+{
+// Note: Do not change the numerical values of the elements. Some of them are used as values for
+// the integer settings SETTING_MYVIDEOS_SELECTACTION and SETTING_MYVIDEOS_PLAYACTION.
+enum Action
+{
+ ACTION_CHOOSE = 0,
+ ACTION_PLAY_OR_RESUME = 1, // if resume is possible, ask user. play from beginning otherwise
+ ACTION_RESUME = 2, // resume if possibly, play from beginning otherwise
+ ACTION_INFO = 3,
+ ACTION_MORE = 4,
+ ACTION_PLAY_FROM_BEGINNING = 5, // play from beginning, also if resume would be possible
+ ACTION_PLAYPART = 6,
+ ACTION_QUEUE = 7,
+};
+} // namespace GUILIB
+} // namespace VIDEO
diff --git a/xbmc/video/guilib/VideoActionProcessorHelper.cpp b/xbmc/video/guilib/VideoActionProcessorHelper.cpp
new file mode 100644
index 0000000000..04f3132cbb
--- /dev/null
+++ b/xbmc/video/guilib/VideoActionProcessorHelper.cpp
@@ -0,0 +1,161 @@
+/*
+ * Copyright (C) 2023 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#include "VideoActionProcessorHelper.h"
+
+#include "FileItem.h"
+#include "GUIUserMessages.h"
+#include "ServiceBroker.h"
+#include "guilib/GUIComponent.h"
+#include "guilib/GUIWindowManager.h"
+#include "settings/Settings.h"
+#include "settings/SettingsComponent.h"
+#include "settings/lib/Setting.h"
+#include "utils/log.h"
+#include "video/VideoDatabase.h"
+#include "video/dialogs/GUIDialogVideoVersion.h"
+
+using namespace VIDEO::GUILIB;
+
+CVideoActionProcessorHelper::~CVideoActionProcessorHelper()
+{
+ RestoreDefaultVideoVersion();
+}
+
+void CVideoActionProcessorHelper::SetDefaultVideoVersion()
+{
+ RestoreDefaultVideoVersion();
+
+ //! @todo this hack must go away! Playback currently only works if we persist the
+ //! movie version to play in the video database temporarily, until playback was started.
+ CVideoDatabase db;
+ if (!db.Open())
+ {
+ CLog::LogF(LOGERROR, "Unable to open video database!");
+ return;
+ }
+
+ const VideoDbContentType itemType{m_item->GetVideoContentType()};
+ const int dbId{m_item->GetVideoInfoTag()->m_iDbId};
+
+ CFileItem defaultVideoVersion;
+ db.GetDefaultVideoVersion(itemType, dbId, defaultVideoVersion);
+ m_defaultVideoVersionFileId = defaultVideoVersion.GetVideoInfoTag()->m_iDbId;
+ m_defaultVideoVersionDynPath = defaultVideoVersion.GetDynPath();
+
+ db.SetDefaultVideoVersion(itemType, dbId, m_videoVersion->GetVideoInfoTag()->m_iDbId);
+
+ m_item->SetDynPath(m_videoVersion->GetDynPath());
+ db.GetDetailsByTypeAndId(*m_item, itemType, dbId);
+
+ // notify all windows to update the file item
+ CGUIMessage msg(GUI_MSG_NOTIFY_ALL, 0, 0, GUI_MSG_UPDATE_ITEM, GUI_MSG_FLAG_FORCE_UPDATE, m_item);
+ CServiceBroker::GetGUI()->GetWindowManager().SendMessage(msg);
+}
+
+void CVideoActionProcessorHelper::RestoreDefaultVideoVersion()
+{
+ //! @todo this hack must go away!
+ if (m_restoreFolderFlag)
+ {
+ m_restoreFolderFlag = false;
+ m_item->m_bIsFolder = true;
+ }
+
+ if (m_defaultVideoVersionFileId == -1)
+ return;
+
+ //! @todo this hack must go away! Playback currently only works if we persist the
+ //! movie version to play in the video database temporarily, until playback was started.
+ CVideoDatabase db;
+ if (!db.Open())
+ {
+ CLog::LogF(LOGERROR, "Unable to open video database!");
+ return;
+ }
+
+ const VideoDbContentType itemType{m_item->GetVideoContentType()};
+ const int dbId{m_item->GetVideoInfoTag()->m_iDbId};
+
+ db.SetDefaultVideoVersion(itemType, dbId, m_defaultVideoVersionFileId);
+
+ m_item->SetDynPath(m_defaultVideoVersionDynPath);
+ db.GetDetailsByTypeAndId(*m_item, itemType, dbId);
+
+ m_defaultVideoVersionFileId = -1;
+ m_defaultVideoVersionDynPath.clear();
+
+ // notify all windows to update the file item
+ CGUIMessage msg(GUI_MSG_NOTIFY_ALL, 0, 0, GUI_MSG_UPDATE_ITEM, GUI_MSG_FLAG_FORCE_UPDATE, m_item);
+ CServiceBroker::GetGUI()->GetWindowManager().SendMessage(msg);
+}
+
+std::shared_ptr<CFileItem> CVideoActionProcessorHelper::ChooseVideoVersion()
+{
+ if (!m_videoVersion && m_item->HasVideoVersions())
+ {
+ if (!m_item->GetProperty("force_choose_video_version").asBoolean(false))
+ {
+ // select the specified video version
+ if (m_item->GetVideoInfoTag()->m_idVideoVersion > 0)
+ m_videoVersion = m_item;
+
+ const auto settings{CServiceBroker::GetSettingsComponent()->GetSettings()};
+
+ if (!m_videoVersion)
+ {
+ //! @todo get rid of this hack to patch away item's folder flag if it is video version
+ //! folder
+ if (m_item->GetVideoInfoTag()->m_idVideoVersion == VIDEO_VERSION_ID_ALL &&
+ settings->GetBool(CSettings::SETTING_VIDEOLIBRARY_SHOWVIDEOVERSIONSASFOLDER))
+ {
+ m_item->m_bIsFolder = false;
+ m_restoreFolderFlag = true;
+ }
+ }
+
+ if (!m_videoVersion)
+ {
+ // select the default video version
+ if (settings->GetBool(CSettings::SETTING_MYVIDEOS_SELECTDEFAULTVERSION))
+ {
+ CVideoDatabase db;
+ if (!db.Open())
+ {
+ CLog::LogF(LOGERROR, "Unable to open video database!");
+ }
+ else
+ {
+ CFileItem defaultVersion;
+ db.GetDefaultVideoVersion(m_item->GetVideoContentType(),
+ m_item->GetVideoInfoTag()->m_iDbId, defaultVersion);
+ if (!defaultVersion.HasVideoInfoTag() || defaultVersion.GetVideoInfoTag()->IsEmpty())
+ CLog::LogF(LOGERROR, "Unable to get default video version from video database!");
+ else
+ m_videoVersion = std::make_shared<const CFileItem>(defaultVersion);
+ }
+ }
+ }
+ }
+
+ if (!m_videoVersion && (m_item->GetProperty("force_choose_video_version").asBoolean(false) ||
+ !m_item->GetProperty("prohibit_choose_video_version").asBoolean(false)))
+ {
+ const auto result{CGUIDialogVideoVersion::ChooseVideoVersion(m_item)};
+ if (result.cancelled)
+ return {};
+ else
+ m_videoVersion = result.selected;
+ }
+ }
+
+ if (m_videoVersion)
+ SetDefaultVideoVersion();
+
+ return m_item;
+}
diff --git a/xbmc/video/guilib/VideoActionProcessorHelper.h b/xbmc/video/guilib/VideoActionProcessorHelper.h
new file mode 100644
index 0000000000..0238d70953
--- /dev/null
+++ b/xbmc/video/guilib/VideoActionProcessorHelper.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2023 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#pragma once
+
+#include <memory>
+#include <string>
+
+class CFileItem;
+
+namespace VIDEO
+{
+namespace GUILIB
+{
+class CVideoActionProcessorHelper
+{
+public:
+ CVideoActionProcessorHelper(const std::shared_ptr<CFileItem>& item,
+ const std::shared_ptr<const CFileItem>& videoVersion)
+ : m_item{item}, m_videoVersion{videoVersion}
+ {
+ }
+ virtual ~CVideoActionProcessorHelper();
+
+ std::shared_ptr<CFileItem> ChooseVideoVersion();
+
+private:
+ CVideoActionProcessorHelper() = delete;
+ void SetDefaultVideoVersion();
+ void RestoreDefaultVideoVersion();
+
+ std::shared_ptr<CFileItem> m_item;
+ std::shared_ptr<const CFileItem> m_videoVersion;
+ int m_defaultVideoVersionFileId{-1};
+ std::string m_defaultVideoVersionDynPath;
+ bool m_restoreFolderFlag{false};
+};
+} // namespace GUILIB
+} // namespace VIDEO
diff --git a/xbmc/video/guilib/VideoPlayAction.h b/xbmc/video/guilib/VideoPlayAction.h
deleted file mode 100644
index a566875602..0000000000
--- a/xbmc/video/guilib/VideoPlayAction.h
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Copyright (C) 2023 Team Kodi
- * This file is part of Kodi - https://kodi.tv
- *
- * SPDX-License-Identifier: GPL-2.0-or-later
- * See LICENSES/README.md for more information.
- */
-
-#pragma once
-
-namespace VIDEO
-{
-namespace GUILIB
-{
-// Note: Do not change the numerical values of the elements. Some of them are used as values for
-// the integer setting SETTING_MYVIDEOS_PLAYACTION.
-enum PlayAction
-{
- PLAY_ACTION_PLAY_OR_RESUME = 1, // if resume is possible, ask user. play from beginning otherwise
- PLAY_ACTION_RESUME = 2, // resume if possibly, play from beginning otherwise
- PLAY_ACTION_PLAY_FROM_BEGINNING = 5, // play from beginning, also if resume would be possible
-};
-} // namespace GUILIB
-} // namespace VIDEO
diff --git a/xbmc/video/guilib/VideoPlayActionProcessor.cpp b/xbmc/video/guilib/VideoPlayActionProcessor.cpp
index 6e0e75fdae..bea41524d8 100644
--- a/xbmc/video/guilib/VideoPlayActionProcessor.cpp
+++ b/xbmc/video/guilib/VideoPlayActionProcessor.cpp
@@ -8,48 +8,66 @@
#include "VideoPlayActionProcessor.h"
+#include "FileItem.h"
#include "ServiceBroker.h"
#include "dialogs/GUIDialogContextMenu.h"
#include "guilib/LocalizeStrings.h"
#include "settings/Settings.h"
#include "settings/SettingsComponent.h"
+#include "utils/Variant.h"
#include "video/VideoUtils.h"
+#include "video/guilib/VideoActionProcessorHelper.h"
using namespace VIDEO::GUILIB;
-PlayAction CVideoPlayActionProcessorBase::GetDefaultPlayAction()
+Action CVideoPlayActionProcessorBase::GetDefaultAction()
{
- return static_cast<PlayAction>(CServiceBroker::GetSettingsComponent()->GetSettings()->GetInt(
+ return static_cast<Action>(CServiceBroker::GetSettingsComponent()->GetSettings()->GetInt(
CSettings::SETTING_MYVIDEOS_PLAYACTION));
}
-bool CVideoPlayActionProcessorBase::Process()
+bool CVideoPlayActionProcessorBase::ProcessDefaultAction()
{
- return Process(GetDefaultPlayAction());
+ return ProcessAction(GetDefaultAction());
}
-bool CVideoPlayActionProcessorBase::Process(PlayAction PlayAction)
+bool CVideoPlayActionProcessorBase::ProcessAction(Action action)
{
m_userCancelled = false;
- switch (PlayAction)
+ CVideoActionProcessorHelper procHelper{m_item, m_videoVersion};
+ const auto videoVersion{procHelper.ChooseVideoVersion()};
+ if (videoVersion)
+ m_item = videoVersion;
+ else
{
- case PLAY_ACTION_PLAY_OR_RESUME:
+ m_userCancelled = true;
+ return true; // User cancelled the select menu. We're done.
+ }
+
+ return Process(action);
+}
+
+bool CVideoPlayActionProcessorBase::Process(Action action)
+{
+ switch (action)
+ {
+ case ACTION_PLAY_OR_RESUME:
{
- const VIDEO::GUILIB::PlayAction action = ChoosePlayOrResume();
- if (action < 0)
+ const Action selectedAction = ChoosePlayOrResume(*m_item);
+ if (selectedAction < 0)
{
m_userCancelled = true;
return true; // User cancelled the select menu. We're done.
}
- return Process(action);
+ return Process(selectedAction);
}
- case PLAY_ACTION_RESUME:
+ case ACTION_RESUME:
return OnResumeSelected();
- case PLAY_ACTION_PLAY_FROM_BEGINNING:
+ case ACTION_PLAY_FROM_BEGINNING:
return OnPlaySelected();
default:
@@ -58,19 +76,19 @@ bool CVideoPlayActionProcessorBase::Process(PlayAction PlayAction)
return false; // We did not handle the action.
}
-PlayAction CVideoPlayActionProcessorBase::ChoosePlayOrResume()
+Action CVideoPlayActionProcessorBase::ChoosePlayOrResume(const CFileItem& item)
{
- PlayAction action = PLAY_ACTION_PLAY_FROM_BEGINNING;
+ Action action = ACTION_PLAY_FROM_BEGINNING;
- const std::string resumeString = VIDEO_UTILS::GetResumeString(m_item);
+ const std::string resumeString = VIDEO_UTILS::GetResumeString(item);
if (!resumeString.empty())
{
CContextButtons choices;
- choices.Add(PLAY_ACTION_RESUME, resumeString);
- choices.Add(PLAY_ACTION_PLAY_FROM_BEGINNING, 12021); // Play from beginning
+ choices.Add(ACTION_RESUME, resumeString);
+ choices.Add(ACTION_PLAY_FROM_BEGINNING, 12021); // Play from beginning
- action = static_cast<PlayAction>(CGUIDialogContextMenu::ShowAndGetChoice(choices));
+ action = static_cast<Action>(CGUIDialogContextMenu::ShowAndGetChoice(choices));
}
return action;
diff --git a/xbmc/video/guilib/VideoPlayActionProcessor.h b/xbmc/video/guilib/VideoPlayActionProcessor.h
index ea57549178..33105be8ad 100644
--- a/xbmc/video/guilib/VideoPlayActionProcessor.h
+++ b/xbmc/video/guilib/VideoPlayActionProcessor.h
@@ -8,7 +8,9 @@
#pragma once
-#include "video/guilib/VideoPlayAction.h"
+#include "video/guilib/VideoAction.h"
+
+#include <memory>
class CFileItem;
@@ -19,26 +21,35 @@ namespace GUILIB
class CVideoPlayActionProcessorBase
{
public:
- explicit CVideoPlayActionProcessorBase(CFileItem& item) : m_item(item) {}
+ explicit CVideoPlayActionProcessorBase(const std::shared_ptr<CFileItem>& item) : m_item(item) {}
+ CVideoPlayActionProcessorBase(const std::shared_ptr<CFileItem>& item,
+ const std::shared_ptr<const CFileItem>& videoVersion)
+ : m_item{item}, m_videoVersion{videoVersion}
+ {
+ }
virtual ~CVideoPlayActionProcessorBase() = default;
- static PlayAction GetDefaultPlayAction();
-
- bool Process();
- bool Process(PlayAction playAction);
+ bool ProcessDefaultAction();
+ bool ProcessAction(Action action);
bool UserCancelled() const { return m_userCancelled; }
+ static Action ChoosePlayOrResume(const CFileItem& item);
+
protected:
+ virtual Action GetDefaultAction();
+ virtual bool Process(Action action);
+
virtual bool OnResumeSelected() = 0;
virtual bool OnPlaySelected() = 0;
- CFileItem& m_item;
+ std::shared_ptr<CFileItem> m_item;
bool m_userCancelled{false};
private:
CVideoPlayActionProcessorBase() = delete;
- PlayAction ChoosePlayOrResume();
+
+ const std::shared_ptr<const CFileItem> m_videoVersion;
};
} // namespace GUILIB
} // namespace VIDEO
diff --git a/xbmc/video/guilib/VideoSelectAction.h b/xbmc/video/guilib/VideoSelectAction.h
deleted file mode 100644
index 731e0cf35b..0000000000
--- a/xbmc/video/guilib/VideoSelectAction.h
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright (C) 2023 Team Kodi
- * This file is part of Kodi - https://kodi.tv
- *
- * SPDX-License-Identifier: GPL-2.0-or-later
- * See LICENSES/README.md for more information.
- */
-
-#pragma once
-
-namespace VIDEO
-{
-namespace GUILIB
-{
-// Note: Do not change the numerical values of the elements. Some of them are used as values for
-// the integer setting SETTING_MYVIDEOS_SELECTACTION.
-enum SelectAction
-{
- SELECT_ACTION_CHOOSE = 0,
- SELECT_ACTION_PLAY_OR_RESUME = 1,
- SELECT_ACTION_RESUME = 2,
- SELECT_ACTION_INFO = 3,
- SELECT_ACTION_MORE = 4,
- SELECT_ACTION_PLAY = 5,
- SELECT_ACTION_PLAYPART = 6,
- SELECT_ACTION_QUEUE = 7,
-};
-} // namespace GUILIB
-} // namespace VIDEO
diff --git a/xbmc/video/guilib/VideoSelectActionProcessor.cpp b/xbmc/video/guilib/VideoSelectActionProcessor.cpp
index 1a8d274a4f..4458115bbf 100644
--- a/xbmc/video/guilib/VideoSelectActionProcessor.cpp
+++ b/xbmc/video/guilib/VideoSelectActionProcessor.cpp
@@ -19,45 +19,43 @@
#include "settings/Settings.h"
#include "settings/SettingsComponent.h"
#include "utils/StringUtils.h"
+#include "utils/Variant.h"
#include "video/VideoInfoTag.h"
#include "video/VideoUtils.h"
using namespace VIDEO::GUILIB;
-SelectAction CVideoSelectActionProcessorBase::GetDefaultSelectAction()
+Action CVideoSelectActionProcessorBase::GetDefaultSelectAction()
{
- return static_cast<SelectAction>(CServiceBroker::GetSettingsComponent()->GetSettings()->GetInt(
+ return static_cast<Action>(CServiceBroker::GetSettingsComponent()->GetSettings()->GetInt(
CSettings::SETTING_MYVIDEOS_SELECTACTION));
}
-bool CVideoSelectActionProcessorBase::Process()
+Action CVideoSelectActionProcessorBase::GetDefaultAction()
{
- return Process(GetDefaultSelectAction());
+ return GetDefaultSelectAction();
}
-bool CVideoSelectActionProcessorBase::Process(SelectAction selectAction)
+bool CVideoSelectActionProcessorBase::Process(Action action)
{
- switch (selectAction)
- {
- case SELECT_ACTION_CHOOSE:
- {
- const SelectAction action = ChooseVideoItemSelectAction();
- if (action < 0)
- return true; // User cancelled the context menu. We're done.
+ if (CVideoPlayActionProcessorBase::Process(action))
+ return true;
- return Process(action);
- }
-
- case SELECT_ACTION_PLAY_OR_RESUME:
+ switch (action)
+ {
+ case ACTION_CHOOSE:
{
- const SelectAction action = ChoosePlayOrResume(m_item);
- if (action < 0)
+ const Action selectedAction = ChooseVideoItemSelectAction();
+ if (selectedAction < 0)
+ {
+ m_userCancelled = true;
return true; // User cancelled the select menu. We're done.
+ }
- return Process(action);
+ return Process(selectedAction);
}
- case SELECT_ACTION_PLAYPART:
+ case ACTION_PLAYPART:
{
const unsigned int part = ChooseStackItemPartNumber();
if (part < 1) // part numbers are 1-based
@@ -66,19 +64,13 @@ bool CVideoSelectActionProcessorBase::Process(SelectAction selectAction)
return OnPlayPartSelected(part);
}
- case SELECT_ACTION_RESUME:
- return OnResumeSelected();
-
- case SELECT_ACTION_PLAY:
- return OnPlaySelected();
-
- case SELECT_ACTION_QUEUE:
+ case ACTION_QUEUE:
return OnQueueSelected();
- case SELECT_ACTION_INFO:
+ case ACTION_INFO:
return OnInfoSelected();
- case SELECT_ACTION_MORE:
+ case ACTION_MORE:
return OnMoreSelected();
default:
@@ -90,7 +82,7 @@ bool CVideoSelectActionProcessorBase::Process(SelectAction selectAction)
unsigned int CVideoSelectActionProcessorBase::ChooseStackItemPartNumber() const
{
CFileItemList parts;
- XFILE::CDirectory::GetDirectory(m_item.GetDynPath(), parts, "", XFILE::DIR_FLAG_DEFAULTS);
+ XFILE::CDirectory::GetDirectory(m_item->GetDynPath(), parts, "", XFILE::DIR_FLAG_DEFAULTS);
for (int i = 0; i < parts.Size(); ++i)
parts[i]->SetLabel(StringUtils::Format(g_localizeStrings.Get(23051), i + 1)); // Part #
@@ -110,42 +102,24 @@ unsigned int CVideoSelectActionProcessorBase::ChooseStackItemPartNumber() const
return dialog->GetSelectedItem() + 1; // part numbers are 1-based
}
-SelectAction CVideoSelectActionProcessorBase::ChoosePlayOrResume(const CFileItem& item)
-{
- SelectAction action = SELECT_ACTION_PLAY;
-
- const std::string resumeString = VIDEO_UTILS::GetResumeString(item);
- if (!resumeString.empty())
- {
- CContextButtons choices;
-
- choices.Add(SELECT_ACTION_RESUME, resumeString);
- choices.Add(SELECT_ACTION_PLAY, 12021); // Play from beginning
-
- action = static_cast<SelectAction>(CGUIDialogContextMenu::ShowAndGetChoice(choices));
- }
-
- return action;
-}
-
-SelectAction CVideoSelectActionProcessorBase::ChooseVideoItemSelectAction() const
+Action CVideoSelectActionProcessorBase::ChooseVideoItemSelectAction() const
{
CContextButtons choices;
- const std::string resumeString = VIDEO_UTILS::GetResumeString(m_item);
+ const std::string resumeString = VIDEO_UTILS::GetResumeString(*m_item);
if (!resumeString.empty())
{
- choices.Add(SELECT_ACTION_RESUME, resumeString);
- choices.Add(SELECT_ACTION_PLAY, 12021); // Play from beginning
+ choices.Add(ACTION_RESUME, resumeString);
+ choices.Add(ACTION_PLAY_FROM_BEGINNING, 12021); // Play from beginning
}
else
{
- choices.Add(SELECT_ACTION_PLAY, 208); // Play
+ choices.Add(ACTION_PLAY_FROM_BEGINNING, 208); // Play
}
- choices.Add(SELECT_ACTION_INFO, 22081); // Show information
- choices.Add(SELECT_ACTION_QUEUE, 13347); // Queue item
- choices.Add(SELECT_ACTION_MORE, 22082); // More
+ choices.Add(ACTION_INFO, 22081); // Show information
+ choices.Add(ACTION_QUEUE, 13347); // Queue item
+ choices.Add(ACTION_MORE, 22082); // More
- return static_cast<SelectAction>(CGUIDialogContextMenu::ShowAndGetChoice(choices));
+ return static_cast<Action>(CGUIDialogContextMenu::ShowAndGetChoice(choices));
}
diff --git a/xbmc/video/guilib/VideoSelectActionProcessor.h b/xbmc/video/guilib/VideoSelectActionProcessor.h
index c896a386da..11217df5a6 100644
--- a/xbmc/video/guilib/VideoSelectActionProcessor.h
+++ b/xbmc/video/guilib/VideoSelectActionProcessor.h
@@ -8,7 +8,9 @@
#pragma once
-#include "video/guilib/VideoSelectAction.h"
+#include "video/guilib/VideoPlayActionProcessor.h"
+
+#include <memory>
class CFileItem;
@@ -16,32 +18,36 @@ namespace VIDEO
{
namespace GUILIB
{
-class CVideoSelectActionProcessorBase
+class CVideoSelectActionProcessorBase : public CVideoPlayActionProcessorBase
{
public:
- explicit CVideoSelectActionProcessorBase(CFileItem& item) : m_item(item) {}
- virtual ~CVideoSelectActionProcessorBase() = default;
+ explicit CVideoSelectActionProcessorBase(const std::shared_ptr<CFileItem>& item)
+ : CVideoPlayActionProcessorBase(item)
+ {
+ }
- static SelectAction GetDefaultSelectAction();
+ CVideoSelectActionProcessorBase(const std::shared_ptr<CFileItem>& item,
+ const std::shared_ptr<const CFileItem>& videoVersion)
+ : CVideoPlayActionProcessorBase(item, videoVersion)
+ {
+ }
- bool Process();
- bool Process(SelectAction selectAction);
+ ~CVideoSelectActionProcessorBase() override = default;
- static SelectAction ChoosePlayOrResume(const CFileItem& item);
+ static Action GetDefaultSelectAction();
protected:
+ Action GetDefaultAction() override;
+ bool Process(Action action) override;
+
virtual bool OnPlayPartSelected(unsigned int part) = 0;
- virtual bool OnResumeSelected() = 0;
- virtual bool OnPlaySelected() = 0;
virtual bool OnQueueSelected() = 0;
virtual bool OnInfoSelected() = 0;
virtual bool OnMoreSelected() = 0;
- CFileItem& m_item;
-
private:
CVideoSelectActionProcessorBase() = delete;
- SelectAction ChooseVideoItemSelectAction() const;
+ Action ChooseVideoItemSelectAction() const;
unsigned int ChooseStackItemPartNumber() const;
};
} // namespace GUILIB
diff --git a/xbmc/video/windows/GUIWindowVideoBase.cpp b/xbmc/video/windows/GUIWindowVideoBase.cpp
index 9bb90f0ea2..99721ed0b8 100644
--- a/xbmc/video/windows/GUIWindowVideoBase.cpp
+++ b/xbmc/video/windows/GUIWindowVideoBase.cpp
@@ -57,7 +57,6 @@
#include "video/VideoLibraryQueue.h"
#include "video/VideoUtils.h"
#include "video/dialogs/GUIDialogVideoInfo.h"
-#include "video/dialogs/GUIDialogVideoVersion.h"
#include "video/guilib/VideoPlayActionProcessor.h"
#include "video/guilib/VideoSelectActionProcessor.h"
#include "view/GUIViewState.h"
@@ -543,7 +542,7 @@ class CVideoSelectActionProcessor : public CVideoSelectActionProcessorBase
{
public:
CVideoSelectActionProcessor(CGUIWindowVideoBase& window,
- CFileItem& item,
+ const std::shared_ptr<CFileItem>& item,
int itemIndex,
const std::string& player)
: CVideoSelectActionProcessorBase(item),
@@ -553,7 +552,7 @@ public:
{
// Reset the current start offset. The actual resume
// option is set by the processor, based on the action passed.
- m_item.SetStartOffset(0);
+ m_item->SetStartOffset(0);
}
protected:
@@ -564,8 +563,8 @@ protected:
bool OnResumeSelected() override
{
- m_item.SetStartOffset(STARTOFFSET_RESUME);
- if (m_item.m_bIsFolder)
+ m_item->SetStartOffset(STARTOFFSET_RESUME);
+ if (m_item->m_bIsFolder)
{
// resume playback of the folder
m_window.PlayItem(m_itemIndex, m_player);
@@ -577,7 +576,7 @@ protected:
bool OnPlaySelected() override
{
- if (m_item.m_bIsFolder)
+ if (m_item->m_bIsFolder)
{
// play the folder
m_window.PlayItem(m_itemIndex, m_player);
@@ -608,14 +607,14 @@ private:
};
} // namespace
-bool CGUIWindowVideoBase::OnFileAction(int iItem, SelectAction action, const std::string& player)
+bool CGUIWindowVideoBase::OnFileAction(int iItem, Action action, const std::string& player)
{
const std::shared_ptr<CFileItem> item = m_vecItems->Get(iItem);
if (!item)
return false;
- CVideoSelectActionProcessor proc(*this, *item, iItem, player);
- return proc.Process(action);
+ CVideoSelectActionProcessor proc(*this, item, iItem, player);
+ return proc.ProcessAction(action);
}
bool CGUIWindowVideoBase::OnItemInfo(int iItem)
@@ -741,7 +740,7 @@ class CVideoPlayActionProcessor : public CVideoPlayActionProcessorBase
{
public:
CVideoPlayActionProcessor(CGUIWindowVideoBase& window,
- CFileItem& item,
+ const std::shared_ptr<CFileItem>& item,
int itemIndex,
const std::string& player)
: CVideoPlayActionProcessorBase(item),
@@ -754,14 +753,14 @@ public:
protected:
bool OnResumeSelected() override
{
- m_item.SetStartOffset(STARTOFFSET_RESUME);
- return m_window.OnFileAction(m_itemIndex, SELECT_ACTION_RESUME, m_player);
+ m_item->SetStartOffset(STARTOFFSET_RESUME);
+ return m_window.OnFileAction(m_itemIndex, VIDEO::GUILIB::ACTION_RESUME, m_player);
}
bool OnPlaySelected() override
{
- m_item.SetStartOffset(0);
- return m_window.OnFileAction(m_itemIndex, SELECT_ACTION_PLAY, m_player);
+ m_item->SetStartOffset(0);
+ return m_window.OnFileAction(m_itemIndex, VIDEO::GUILIB::ACTION_PLAY_FROM_BEGINNING, m_player);
}
private:
@@ -776,8 +775,8 @@ bool CGUIWindowVideoBase::OnPlayOrResumeItem(int iItem, const std::string& playe
if (iItem < 0 || iItem >= m_vecItems->Size())
return false;
- CVideoPlayActionProcessor proc{*this, *m_vecItems->Get(iItem), iItem, player};
- return proc.Process();
+ CVideoPlayActionProcessor proc{*this, m_vecItems->Get(iItem), iItem, player};
+ return proc.ProcessDefaultAction();
}
void CGUIWindowVideoBase::GetContextButtons(int itemNumber, CContextButtons &buttons)
@@ -852,13 +851,13 @@ bool CGUIWindowVideoBase::OnPlayStackPart(int itemIndex, unsigned int partNumber
CDirectory::GetDirectory(path, parts, "", DIR_FLAG_DEFAULTS);
const int value = CVideoSelectActionProcessor::ChoosePlayOrResume(*parts[partNumber - 1]);
- if (value == SELECT_ACTION_RESUME)
+ if (value == VIDEO::GUILIB::ACTION_RESUME)
{
const VIDEO_UTILS::ResumeInformation resumeInfo =
VIDEO_UTILS::GetItemResumeInformation(*parts[partNumber - 1]);
item->SetStartOffset(resumeInfo.startOffset);
}
- else if (value != SELECT_ACTION_PLAY)
+ else if (value != VIDEO::GUILIB::ACTION_PLAY_FROM_BEGINNING)
return false; // if not selected PLAY, then we changed our mind so return
item->m_lStartPartNumber = partNumber;
@@ -895,7 +894,7 @@ bool CGUIWindowVideoBase::OnContextButton(int itemNumber, CONTEXT_BUTTON button)
}
case CONTEXT_BUTTON_PLAY_PART:
{
- return OnFileAction(itemNumber, SELECT_ACTION_PLAYPART, "");
+ return OnFileAction(itemNumber, VIDEO::GUILIB::ACTION_PLAYPART, "");
}
case CONTEXT_BUTTON_PLAY_PARTYMODE:
@@ -978,16 +977,7 @@ bool CGUIWindowVideoBase::OnPlayMedia(int iItem, const std::string &player)
if (m_thumbLoader.IsLoading())
m_thumbLoader.StopAsync();
- //! @todo get rid of special handling for movie versions
- if (itemCopy->GetVideoInfoTag()->m_type == MediaTypeMovie ||
- itemCopy->GetVideoInfoTag()->m_type == MediaTypeVideoVersion)
- {
- CGUIDialogVideoVersion::PlayVideoVersion(
- itemCopy, [player](const std::shared_ptr<CFileItem>& item)
- { CServiceBroker::GetPlaylistPlayer().Play(item, player); });
- }
- else
- CServiceBroker::GetPlaylistPlayer().Play(itemCopy, player);
+ CServiceBroker::GetPlaylistPlayer().Play(itemCopy, player);
const auto& components = CServiceBroker::GetAppComponents();
const auto appPlayer = components.GetComponent<CApplicationPlayer>();
diff --git a/xbmc/video/windows/GUIWindowVideoBase.h b/xbmc/video/windows/GUIWindowVideoBase.h
index 9916980d4a..1542ac4dce 100644
--- a/xbmc/video/windows/GUIWindowVideoBase.h
+++ b/xbmc/video/windows/GUIWindowVideoBase.h
@@ -11,7 +11,7 @@
#include "playlists/PlayListTypes.h"
#include "video/VideoDatabase.h"
#include "video/VideoThumbLoader.h"
-#include "video/guilib/VideoSelectAction.h"
+#include "video/guilib/VideoAction.h"
#include "windows/GUIMediaWindow.h"
namespace
@@ -95,7 +95,7 @@ protected:
\param action the action to perform
\return true if the action is performed, false otherwise
*/
- bool OnFileAction(int item, VIDEO::GUILIB::SelectAction action, const std::string& player);
+ bool OnFileAction(int item, VIDEO::GUILIB::Action action, const std::string& player);
void OnRestartItem(int iItem, const std::string &player = "");
bool OnPlayOrResumeItem(int iItem, const std::string& player = "");