Skip to content

Commit

Permalink
Merge pull request xbmc#23863 from ksooo/video-play-actions
Browse files Browse the repository at this point in the history
[settings][video][PVR][listproviders][favourites] Add default play action setting.
  • Loading branch information
ksooo authored Oct 4, 2023
2 parents b96c33a + dd4f5d6 commit 0f28947
Show file tree
Hide file tree
Showing 12 changed files with 383 additions and 92 deletions.
27 changes: 25 additions & 2 deletions addons/resource.language.en_gb/resources/strings.po
Original file line number Diff line number Diff line change
Expand Up @@ -5725,6 +5725,7 @@ msgstr ""
#: xbmc/pvr/PVRGUIActionsPlayback.cpp
#: xbmc/video/ContextMenus.cpp
#: xbmc/video/guilib/VideoSelectActionProcessor.cpp
#: xbmc/video/guilib/VideoPlayActionProcessor.cpp
msgctxt "#12021"
msgid "Play from beginning"
msgstr ""
Expand Down Expand Up @@ -15309,7 +15310,25 @@ msgctxt "#22033"
msgid "Charset"
msgstr ""

#empty strings from id 22034 to 22078
#empty strings from id 22034 to 22075

#. Label for setting to choose the default action for "play"
#: system/settings/settings.xml
msgctxt "#22076"
msgid "Default play action"
msgstr ""

#. Label for value for default play action setting
#: system/settings/settings.xml
msgctxt "#22077"
msgid "Ask if resumable"
msgstr ""

#. Label for value for default play action setting
#: system/settings/settings.xml
msgctxt "#22078"
msgid "Resume"
msgstr ""

#: system/settings/settings.xml
msgctxt "#22079"
Expand Down Expand Up @@ -19638,7 +19657,11 @@ msgctxt "#36203"
msgid "Enables the \"Personal Video Recorder\" (PVR) features. This requires that at least one PVR add-on is installed."
msgstr ""

#empty string with id 36204
#. Description of setting with label #22076 "Default play action"
#: system/settings/settings.xml
msgctxt "#36204"
msgid "Toggle between [Ask if resumable] (default) and [Resume].[CR][Ask if resumable] will ask whether to play from beginning or to resume (if a resume point is present).[CR][Resume] will automatically resume videos from the last position that you were viewing them.[CR]If no resume point is set, playback will automatically start from the beginning."
msgstr ""

#: system/settings/settings.xml
msgctxt "#36205"
Expand Down
11 changes: 11 additions & 0 deletions system/settings/settings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -1015,6 +1015,17 @@
</constraints>
<control type="list" format="string" />
</setting>
<setting id="myvideos.playaction" type="integer" label="22076" help="36204">
<level>0</level>
<default>1</default> <!-- PLAY_ACTION_PLAY_OR_RESUME -->
<constraints>
<options>
<option label="22077">1</option> <!-- PLAY_ACTION_PLAY_OR_RESUME -->
<option label="22078">2</option> <!-- PLAY_ACTION_RESUME -->
</options>
</constraints>
<control type="list" format="string" />
</setting>
<setting id="myvideos.usetags" type="boolean" label="21343" help="21344">
<level>2</level>
<default>false</default>
Expand Down
74 changes: 48 additions & 26 deletions xbmc/favourites/GUIWindowFavourites.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include "utils/StringUtils.h"
#include "video/VideoUtils.h"
#include "video/dialogs/GUIDialogVideoInfo.h"
#include "video/guilib/VideoPlayActionProcessor.h"
#include "video/guilib/VideoSelectActionProcessor.h"

CGUIWindowFavourites::CGUIWindowFavourites()
Expand Down Expand Up @@ -117,6 +118,25 @@ class CVideoSelectActionProcessor : public VIDEO::GUILIB::CVideoSelectActionProc
return true;
}
};

class CVideoPlayActionProcessor : public VIDEO::GUILIB::CVideoPlayActionProcessorBase
{
public:
explicit CVideoPlayActionProcessor(CFileItem& item) : CVideoPlayActionProcessorBase(item) {}

protected:
bool OnResumeSelected() override
{
ExecuteAction({"PlayMedia", m_item, "resume"});
return true;
}

bool OnPlaySelected() override
{
ExecuteAction({"PlayMedia", m_item, "noresume"});
return true;
}
};
} // namespace

bool CGUIWindowFavourites::OnSelect(int item)
Expand All @@ -128,19 +148,20 @@ bool CGUIWindowFavourites::OnSelect(int item)
if (!favURL.IsValid())
return false;

if (favURL.GetAction() == CFavouritesURL::Action::PLAY_MEDIA)
CFileItem targetItem{favURL.GetTarget(), favURL.IsDir()};
targetItem.LoadDetails();

const bool isPlayMedia{favURL.GetAction() == CFavouritesURL::Action::PLAY_MEDIA};

// video select action setting is for files only, except exec func is playmedia...
if (targetItem.HasVideoInfoTag() && (!targetItem.m_bIsFolder || isPlayMedia))
{
// Resolve the favourite
CFileItem targetItem{favURL.GetTarget(), favURL.IsDir()};
targetItem.LoadDetails();
if (targetItem.IsVideo() || (targetItem.m_bIsFolder && VIDEO_UTILS::IsItemPlayable(targetItem)))
{
CVideoSelectActionProcessor proc{targetItem};
if (proc.Process())
return true;
}
CVideoSelectActionProcessor proc{targetItem};
if (proc.Process())
return true;
}

// exec the execute string for the original (!) item
return ExecuteAction(favURL.GetExecString());
}

Expand All @@ -156,26 +177,27 @@ bool CGUIWindowFavourites::OnAction(const CAction& action)
if (!favURL.IsValid())
return false;

// If action is playmedia, just play it
if (favURL.GetAction() == CFavouritesURL::Action::PLAY_MEDIA)
return ExecuteAction(favURL.GetExecString());
CFileItem item{favURL.GetTarget(), favURL.IsDir()};
item.LoadDetails();

// Resolve and check the target
const auto item = std::make_shared<CFileItem>(favURL.GetTarget(), favURL.IsDir());
if (CPlayerUtils::IsItemPlayable(*item))
// video play action setting is for files and folders...
if (item.HasVideoInfoTag() || (item.m_bIsFolder && VIDEO_UTILS::IsItemPlayable(item)))
{
CFavouritesURL target(*item, {});
if (target.GetAction() == CFavouritesURL::Action::PLAY_MEDIA)
{
return ExecuteAction(target.GetExecString());
}
else
CVideoPlayActionProcessor proc{item};
if (proc.Process())
return true;
}

if (CPlayerUtils::IsItemPlayable(item))
{
CFavouritesURL target{item, {}};
if (target.GetAction() != CFavouritesURL::Action::PLAY_MEDIA)
{
// build and execute a playmedia execute string
target = CFavouritesURL(CFavouritesURL::Action::PLAY_MEDIA,
{StringUtils::Paramify(item->GetPath())});
return ExecuteAction(target.GetExecString());
// build a playmedia execute string for given target
target = CFavouritesURL{CFavouritesURL::Action::PLAY_MEDIA,
{StringUtils::Paramify(item.GetPath())}};
}
return ExecuteAction(target.GetExecString());
}
return false;
}
Expand Down
120 changes: 70 additions & 50 deletions xbmc/listproviders/DirectoryProvider.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
#include "video/VideoThumbLoader.h"
#include "video/VideoUtils.h"
#include "video/dialogs/GUIDialogVideoInfo.h"
#include "video/guilib/VideoPlayActionProcessor.h"
#include "video/guilib/VideoSelectActionProcessor.h"

#include <memory>
Expand Down Expand Up @@ -468,6 +469,11 @@ bool ExecuteAction(const std::string& execute)
return false;
}

bool ExecuteAction(const CExecString& execute)
{
return ExecuteAction(execute.GetExecString());
}

class CVideoSelectActionProcessor : public VIDEO::GUILIB::CVideoSelectActionProcessorBase
{
public:
Expand All @@ -480,25 +486,25 @@ class CVideoSelectActionProcessor : public VIDEO::GUILIB::CVideoSelectActionProc
bool OnPlayPartSelected(unsigned int part) override
{
// part numbers are 1-based
BuildAndExecAction("PlayMedia", StringUtils::Format("playoffset={}", part - 1));
ExecuteAction({"PlayMedia", m_item, StringUtils::Format("playoffset={}", part - 1)});
return true;
}

bool OnResumeSelected() override
{
BuildAndExecAction("PlayMedia", "resume");
ExecuteAction({"PlayMedia", m_item, "resume"});
return true;
}

bool OnPlaySelected() override
{
BuildAndExecAction("PlayMedia", "noresume");
ExecuteAction({"PlayMedia", m_item, "noresume"});
return true;
}

bool OnQueueSelected() override
{
BuildAndExecAction("QueueMedia", "");
ExecuteAction({"QueueMedia", m_item, ""});
return true;
}

Expand All @@ -515,92 +521,106 @@ class CVideoSelectActionProcessor : public VIDEO::GUILIB::CVideoSelectActionProc
}

private:
void BuildAndExecAction(const std::string& method, const std::string& param)
{
std::vector<std::string> params{StringUtils::Paramify(m_item.GetPath())};
if (m_item.m_bIsFolder)
params.emplace_back("isdir");
CDirectoryProvider& m_provider;
};

if (!param.empty())
params.emplace_back(param);
class CVideoPlayActionProcessor : public VIDEO::GUILIB::CVideoPlayActionProcessorBase
{
public:
explicit CVideoPlayActionProcessor(CFileItem& item) : CVideoPlayActionProcessorBase(item) {}

const CExecString es{method, params};
ExecuteAction(es.GetExecString());
protected:
bool OnResumeSelected() override
{
ExecuteAction({"PlayMedia", m_item, "resume"});
return true;
}

CDirectoryProvider& m_provider;
bool OnPlaySelected() override
{
ExecuteAction({"PlayMedia", m_item, "noresume"});
return true;
}
};
} // namespace

bool CDirectoryProvider::OnClick(const CGUIListItemPtr& item)
{
CFileItem fileItem(*std::static_pointer_cast<CFileItem>(item));
CFileItem targetItem{*std::static_pointer_cast<CFileItem>(item)};

bool isPlayMedia{false};

if (fileItem.IsFavourite())
if (targetItem.IsFavourite())
{
// Resolve the favourite
const CFavouritesURL url{fileItem.GetPath()};
const CFavouritesURL url{targetItem.GetPath()};
if (!url.IsValid())
return false;

if (url.GetAction() == CFavouritesURL::Action::PLAY_MEDIA)
{
CFileItem targetItem{url.GetTarget(), url.IsDir()};
targetItem.LoadDetails();
if (targetItem.IsVideo() ||
(targetItem.m_bIsFolder && VIDEO_UTILS::IsItemPlayable(targetItem)))
{
CVideoSelectActionProcessor proc{*this, targetItem};
if (proc.Process())
return true;
}
}
targetItem = {url.GetTarget(), url.IsDir()};
targetItem.LoadDetails();

isPlayMedia = (url.GetAction() == CFavouritesURL::Action::PLAY_MEDIA);
}
else if (fileItem.HasVideoInfoTag())
else
{
CVideoSelectActionProcessor proc{*this, fileItem};
const CExecString exec{targetItem, GetTarget(targetItem)};
isPlayMedia = (exec.GetFunction() == "playmedia");
}

// 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())
return true;
}

// exec the execute string for the original (!) item
CFileItem fileItem{*std::static_pointer_cast<CFileItem>(item)};

if (fileItem.HasProperty("node.target_url"))
fileItem.SetPath(fileItem.GetProperty("node.target_url").asString());

// grab and execute the execute string
return ExecuteAction(CExecString(fileItem, GetTarget(fileItem)).GetExecString());
return ExecuteAction({fileItem, GetTarget(fileItem)});
}

bool CDirectoryProvider::OnPlay(const CGUIListItemPtr& item)
{
CFileItem fileItem(*std::static_pointer_cast<CFileItem>(item));
CFileItem targetItem{*std::static_pointer_cast<CFileItem>(item)};

if (fileItem.IsFavourite())
if (targetItem.IsFavourite())
{
// Resolve the favourite
const CFavouritesURL url(fileItem.GetPath());
if (url.IsValid())
{
// If action is playmedia, just play it
if (url.GetAction() == CFavouritesURL::Action::PLAY_MEDIA)
return ExecuteAction(url.GetExecString());
const CFavouritesURL url(targetItem.GetPath());
if (!url.IsValid())
return false;

CFileItem targetItem(url.GetTarget(), url.IsDir());
fileItem = targetItem;
}
targetItem = {url.GetTarget(), url.IsDir()};
targetItem.LoadDetails();
}

// video play action setting is for files and folders...
if (targetItem.HasVideoInfoTag() ||
(targetItem.m_bIsFolder && VIDEO_UTILS::IsItemPlayable(targetItem)))
{
CVideoPlayActionProcessor proc{targetItem};
if (proc.Process())
return true;
}

if (CPlayerUtils::IsItemPlayable(fileItem))
if (CPlayerUtils::IsItemPlayable(targetItem))
{
CExecString exec(fileItem, {});
const CExecString exec{targetItem, GetTarget(targetItem)};
if (exec.GetFunction() == "playmedia")
{
return ExecuteAction(exec.GetExecString());
// exec as is
return ExecuteAction(exec);
}
else
{
// build and execute a playmedia execute string
exec = CExecString("PlayMedia", {StringUtils::Paramify(fileItem.GetPath())});
return ExecuteAction(exec.GetExecString());
// build a playmedia execute string for given target and exec this
return ExecuteAction({"PlayMedia", targetItem, ""});
}
}
return true;
Expand Down
Loading

0 comments on commit 0f28947

Please sign in to comment.