aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKai Sommerfeld <kai.sommerfeld@gmx.com>2022-10-31 23:11:36 +0100
committerKai Sommerfeld <kai.sommerfeld@gmx.com>2022-11-07 07:49:34 +0100
commit93c525bb448c5e1ba279567b8e72a34b7845e127 (patch)
tree3b0437246c9e31da166005a77e24bf35c32f31cc
parentee399f6e182c2b1ae10ccec40ea171588349290a (diff)
[video][PVR] Feature: Continue watching TV shows, seasons, movie sets and PVR recordings folders via context menu or action 'play'.
-rw-r--r--addons/resource.language.en_gb/resources/strings.po8
-rw-r--r--xbmc/FileItem.cpp74
-rw-r--r--xbmc/FileItem.h11
-rw-r--r--xbmc/interfaces/builtins/PlayerBuiltins.cpp15
-rw-r--r--xbmc/pvr/windows/GUIWindowPVRRecordings.cpp24
-rw-r--r--xbmc/video/ContextMenus.cpp4
-rw-r--r--xbmc/video/VideoDatabase.cpp38
-rw-r--r--xbmc/video/VideoDatabase.h4
-rw-r--r--xbmc/video/windows/GUIWindowVideoBase.cpp205
9 files changed, 334 insertions, 49 deletions
diff --git a/addons/resource.language.en_gb/resources/strings.po b/addons/resource.language.en_gb/resources/strings.po
index a33bc81d88..bd31344ec8 100644
--- a/addons/resource.language.en_gb/resources/strings.po
+++ b/addons/resource.language.en_gb/resources/strings.po
@@ -6995,7 +6995,13 @@ msgctxt "#13361"
msgid "Enable voice"
msgstr ""
-#empty strings from id 13362 to 13374
+#. label for resume context menu item for video folders (like a TV show or a single season of a TV show)
+#: xbmc/video/windows/GUIWindowVideoBase.cpp
+msgctxt "#13362"
+msgid "Continue watching"
+msgstr ""
+
+#empty strings from id 13363 to 13374
msgctxt "#13375"
msgid "Enable device"
diff --git a/xbmc/FileItem.cpp b/xbmc/FileItem.cpp
index 27821aefc8..9d711d1d83 100644
--- a/xbmc/FileItem.cpp
+++ b/xbmc/FileItem.cpp
@@ -3684,6 +3684,80 @@ bool CFileItem::LoadGameTag()
return false;
}
+bool CFileItem::LoadDetails()
+{
+ if (IsVideoDb())
+ {
+ if (HasVideoInfoTag())
+ return true;
+
+ CVideoDatabase db;
+ if (!db.Open())
+ return false;
+
+ VIDEODATABASEDIRECTORY::CQueryParams params;
+ VIDEODATABASEDIRECTORY::CDirectoryNode::GetDatabaseInfo(GetPath(), params);
+
+ if (params.GetMovieId() >= 0)
+ db.GetMovieInfo(GetPath(), *GetVideoInfoTag(), static_cast<int>(params.GetMovieId()));
+ else if (params.GetMVideoId() >= 0)
+ db.GetMusicVideoInfo(GetPath(), *GetVideoInfoTag(), static_cast<int>(params.GetMVideoId()));
+ else if (params.GetEpisodeId() >= 0)
+ db.GetEpisodeInfo(GetPath(), *GetVideoInfoTag(), static_cast<int>(params.GetEpisodeId()));
+ else if (params.GetSetId() >= 0) // movie set
+ db.GetSetInfo(static_cast<int>(params.GetSetId()), *GetVideoInfoTag(), this);
+ else if (params.GetTvShowId() >= 0)
+ {
+ if (params.GetSeason() >= 0)
+ {
+ const int idSeason = db.GetSeasonId(static_cast<int>(params.GetTvShowId()),
+ static_cast<int>(params.GetSeason()));
+ if (idSeason >= 0)
+ db.GetSeasonInfo(idSeason, *GetVideoInfoTag(), this);
+ }
+ else
+ db.GetTvShowInfo(GetPath(), *GetVideoInfoTag(), static_cast<int>(params.GetTvShowId()),
+ this);
+ }
+ else
+ {
+ db.Close();
+ return false;
+ }
+ db.Close();
+ return true;
+ }
+
+ if (m_bIsFolder && URIUtils::IsPVRRecordingFileOrFolder(GetPath()))
+ {
+ if (HasProperty("watchedepisodes") || HasProperty("watched"))
+ return true;
+
+ const std::string parentPath = URIUtils::GetParentPath(GetPath());
+
+ //! @todo optimize, find a way to set the details of the directory without loading its content.
+ CFileItemList items;
+ if (CDirectory::GetDirectory(parentPath, items, "", XFILE::DIR_FLAG_DEFAULTS))
+ {
+ const std::string path = GetPath();
+ const auto it = std::find_if(items.cbegin(), items.cend(),
+ [path](const auto& entry) { return entry->GetPath() == path; });
+ if (it != items.cend())
+ {
+ *this = *(*it);
+ return true;
+ }
+ }
+
+ CLog::LogF(LOGERROR, "Error filling item details (path={})", GetPath());
+ return false;
+ }
+
+ //! @todo add support for other types on demand.
+ CLog::LogF(LOGDEBUG, "Unsupported item type (path={})", GetPath());
+ return false;
+}
+
void CFileItemList::Swap(unsigned int item1, unsigned int item2)
{
if (item1 != item2 && item1 < m_items.size() && item2 < m_items.size())
diff --git a/xbmc/FileItem.h b/xbmc/FileItem.h
index 01d64428ff..e0adc28e4d 100644
--- a/xbmc/FileItem.h
+++ b/xbmc/FileItem.h
@@ -517,8 +517,15 @@ public:
// finds a matching local trailer file
std::string FindTrailer() const;
- virtual bool LoadMusicTag();
- virtual bool LoadGameTag();
+ bool LoadMusicTag();
+ bool LoadGameTag();
+
+ /*! \brief Load detailed data for an item constructed with only a path and a folder flag
+ Fills item's video info tag, sets item properties.
+
+ \return true on success, false otherwise.
+ */
+ bool LoadDetails();
/* Returns the content type of this item if known */
const std::string& GetMimeType() const { return m_mimetype; }
diff --git a/xbmc/interfaces/builtins/PlayerBuiltins.cpp b/xbmc/interfaces/builtins/PlayerBuiltins.cpp
index 992b647957..a7e1380582 100644
--- a/xbmc/interfaces/builtins/PlayerBuiltins.cpp
+++ b/xbmc/interfaces/builtins/PlayerBuiltins.cpp
@@ -484,9 +484,13 @@ int PlayOrQueueMedia(const std::vector<std::string>& params, bool forcePlay)
if (!item.m_bIsFolder && item.IsPlugin())
item.SetProperty("IsPlayable", true);
- if ( askToResume == true )
+ // Here, the item instance has only the path and the folder flag. We need some
+ // extended item properties to process resume successfully. Load them.
+ item.LoadDetails();
+
+ if (askToResume)
{
- if ( CGUIWindowVideoBase::ShowResumeMenu(item) == false )
+ if (!CGUIWindowVideoBase::ShowResumeMenu(item))
return false;
}
@@ -573,6 +577,13 @@ int PlayOrQueueMedia(const std::vector<std::string>& params, bool forcePlay)
if (forcePlay)
{
+ if (item.HasVideoInfoTag() && item.GetStartOffset() == STARTOFFSET_RESUME)
+ {
+ const CBookmark bookmark = item.GetVideoInfoTag()->GetResumePoint();
+ if (bookmark.IsSet())
+ item.SetStartOffset(CUtil::ConvertSecsToMilliSecs(bookmark.timeInSeconds));
+ }
+
if ((item.IsAudio() || item.IsVideo()) && !item.IsSmartPlayList())
CServiceBroker::GetPlaylistPlayer().Play(std::make_shared<CFileItem>(item), "");
else
diff --git a/xbmc/pvr/windows/GUIWindowPVRRecordings.cpp b/xbmc/pvr/windows/GUIWindowPVRRecordings.cpp
index 38c0bc4165..9dc8b886a1 100644
--- a/xbmc/pvr/windows/GUIWindowPVRRecordings.cpp
+++ b/xbmc/pvr/windows/GUIWindowPVRRecordings.cpp
@@ -28,6 +28,7 @@
#include "settings/SettingsComponent.h"
#include "utils/URIUtils.h"
#include "video/VideoLibraryQueue.h"
+#include "video/VideoUtils.h"
#include "video/windows/GUIWindowVideoNav.h"
#include <memory>
@@ -235,19 +236,24 @@ bool CGUIWindowPVRRecordingsBase::OnMessage(CGUIMessage& message)
break;
}
- if (item->m_bIsFolder)
+ if (!item->IsParentFolder() && message.GetParam1() == ACTION_PLAYER_PLAY)
{
- // recording folders and ".." folders in subfolders are handled by base class.
- bReturn = false;
- break;
- }
+ if (item->m_bIsFolder)
+ {
+ if (CGUIWindowVideoNav::ShowResumeMenu(*item))
+ VIDEO_UTILS::PlayItem(item);
+ }
+ else
+ CServiceBroker::GetPVRManager().Get<PVR::GUI::Playback>().PlayRecording(
+ *item, true /* check resume */);
- if (message.GetParam1() == ACTION_PLAYER_PLAY)
- {
- CServiceBroker::GetPVRManager().Get<PVR::GUI::Playback>().PlayRecording(
- *item, true /* check resume */);
bReturn = true;
}
+ else if (item->m_bIsFolder)
+ {
+ // recording folders and ".." folders in subfolders are handled by base class.
+ bReturn = false;
+ }
else
{
switch (m_settings.GetIntValue(CSettings::SETTING_MYVIDEOS_SELECTACTION))
diff --git a/xbmc/video/ContextMenus.cpp b/xbmc/video/ContextMenus.cpp
index 190eaa707b..eaec3064ea 100644
--- a/xbmc/video/ContextMenus.cpp
+++ b/xbmc/video/ContextMenus.cpp
@@ -130,7 +130,7 @@ bool CVideoResume::IsVisible(const CFileItem& itemIn) const
if (item.IsDeleted()) // e.g. trashed pvr recording
return false;
- return CGUIWindowVideoBase::HasResumeItemOffset(&item);
+ return !CGUIWindowVideoBase::GetResumeString(item).empty();
}
namespace
@@ -312,7 +312,7 @@ std::string CVideoPlay::GetLabel(const CFileItem& itemIn) const
CFileItem item(itemIn.GetItemToPlay());
if (item.IsLiveTV())
return g_localizeStrings.Get(19000); // Switch to channel
- if (CGUIWindowVideoBase::HasResumeItemOffset(&item))
+ if (!CGUIWindowVideoBase::GetResumeString(item).empty())
return g_localizeStrings.Get(12021); // Play from beginning
return g_localizeStrings.Get(208); // Play
}
diff --git a/xbmc/video/VideoDatabase.cpp b/xbmc/video/VideoDatabase.cpp
index d832c72e3f..119299c39a 100644
--- a/xbmc/video/VideoDatabase.cpp
+++ b/xbmc/video/VideoDatabase.cpp
@@ -2138,6 +2138,19 @@ bool CVideoDatabase::GetTvShowInfo(const std::string& strPath, CVideoInfoTag& de
bool CVideoDatabase::GetSeasonInfo(int idSeason, CVideoInfoTag& details, bool allDetails /* = true */)
{
+ if (allDetails)
+ {
+ CFileItem dummy; // only interested in the tag data...
+ return GetSeasonInfo(idSeason, details, &dummy);
+ }
+ else
+ {
+ return GetSeasonInfo(idSeason, details, nullptr);
+ }
+}
+
+bool CVideoDatabase::GetSeasonInfo(int idSeason, CVideoInfoTag& details, CFileItem* item)
+{
if (idSeason < 0)
return false;
@@ -2153,7 +2166,7 @@ bool CVideoDatabase::GetSeasonInfo(int idSeason, CVideoInfoTag& details, bool al
if (m_pDS->num_rows() != 1)
return false;
- if (allDetails)
+ if (item)
{
int idShow = m_pDS->fv(1).get_asInt();
@@ -2175,6 +2188,7 @@ bool CVideoDatabase::GetSeasonInfo(int idSeason, CVideoInfoTag& details, bool al
if (season->HasVideoInfoTag() && season->GetVideoInfoTag()->m_iDbId == idSeason && season->GetVideoInfoTag()->m_iIdShow == idShow)
{
details = *season->GetVideoInfoTag();
+ *item = *season;
return true;
}
}
@@ -2283,7 +2297,7 @@ bool CVideoDatabase::GetMusicVideoInfo(const std::string& strFilenameAndPath, CV
return false;
}
-bool CVideoDatabase::GetSetInfo(int idSet, CVideoInfoTag& details)
+bool CVideoDatabase::GetSetInfo(int idSet, CVideoInfoTag& details, CFileItem* item /* = nullptr */)
{
try
{
@@ -2299,6 +2313,8 @@ bool CVideoDatabase::GetSetInfo(int idSet, CVideoInfoTag& details)
return false;
details = *(items[0]->GetVideoInfoTag());
+ if (item)
+ *item = *items[0];
return !details.IsEmpty();
}
catch (...)
@@ -3822,7 +3838,7 @@ void CVideoDatabase::GetDetailsFromDB(const dbiplus::sql_record* const record, i
}
}
-CVideoInfoTag CVideoDatabase::GetDetailsByTypeAndId(VideoDbContentType type, int id)
+bool CVideoDatabase::GetDetailsByTypeAndId(CFileItem& item, VideoDbContentType type, int id)
{
CVideoInfoTag details;
details.Reset();
@@ -3833,7 +3849,7 @@ CVideoInfoTag CVideoDatabase::GetDetailsByTypeAndId(VideoDbContentType type, int
GetMovieInfo("", details, id);
break;
case VideoDbContentType::TVSHOWS:
- GetTvShowInfo("", details, id);
+ GetTvShowInfo("", details, id, &item);
break;
case VideoDbContentType::EPISODES:
GetEpisodeInfo("", details, id);
@@ -3842,10 +3858,20 @@ CVideoInfoTag CVideoDatabase::GetDetailsByTypeAndId(VideoDbContentType type, int
GetMusicVideoInfo("", details, id);
break;
default:
- break;
+ return false;
}
- return details;
+ item.SetFromVideoInfoTag(details);
+ return true;
+}
+
+CVideoInfoTag CVideoDatabase::GetDetailsByTypeAndId(VideoDbContentType type, int id)
+{
+ CFileItem item;
+ if (GetDetailsByTypeAndId(item, type, id))
+ return CVideoInfoTag(*item.GetVideoInfoTag());
+
+ return {};
}
bool CVideoDatabase::GetStreamDetails(CFileItem& item)
diff --git a/xbmc/video/VideoDatabase.h b/xbmc/video/VideoDatabase.h
index 690450a0c9..675ec44e89 100644
--- a/xbmc/video/VideoDatabase.h
+++ b/xbmc/video/VideoDatabase.h
@@ -513,11 +513,12 @@ public:
bool LoadVideoInfo(const std::string& strFilenameAndPath, CVideoInfoTag& details, int getDetails = VideoDbDetailsAll);
bool GetMovieInfo(const std::string& strFilenameAndPath, CVideoInfoTag& details, int idMovie = -1, int getDetails = VideoDbDetailsAll);
bool GetTvShowInfo(const std::string& strPath, CVideoInfoTag& details, int idTvShow = -1, CFileItem* item = NULL, int getDetails = VideoDbDetailsAll);
+ bool GetSeasonInfo(int idSeason, CVideoInfoTag& details, CFileItem* item);
bool GetSeasonInfo(int idSeason, CVideoInfoTag& details, bool allDetails = true);
bool GetEpisodeBasicInfo(const std::string& strFilenameAndPath, CVideoInfoTag& details, int idEpisode = -1);
bool GetEpisodeInfo(const std::string& strFilenameAndPath, CVideoInfoTag& details, int idEpisode = -1, int getDetails = VideoDbDetailsAll);
bool GetMusicVideoInfo(const std::string& strFilenameAndPath, CVideoInfoTag& details, int idMVideo = -1, int getDetails = VideoDbDetailsAll);
- bool GetSetInfo(int idSet, CVideoInfoTag& details);
+ bool GetSetInfo(int idSet, CVideoInfoTag& details, CFileItem* item = nullptr);
bool GetFileInfo(const std::string& strFilenameAndPath, CVideoInfoTag& details, int idFile = -1);
int GetPathId(const std::string& strPath);
@@ -653,6 +654,7 @@ public:
bool GetResumePoint(CVideoInfoTag& tag);
bool GetStreamDetails(CFileItem& item);
bool GetStreamDetails(CVideoInfoTag& tag) const;
+ bool GetDetailsByTypeAndId(CFileItem& item, VideoDbContentType type, int id);
CVideoInfoTag GetDetailsByTypeAndId(VideoDbContentType type, int id);
// scraper settings
diff --git a/xbmc/video/windows/GUIWindowVideoBase.cpp b/xbmc/video/windows/GUIWindowVideoBase.cpp
index 55d38e0f22..ac9ba1bffd 100644
--- a/xbmc/video/windows/GUIWindowVideoBase.cpp
+++ b/xbmc/video/windows/GUIWindowVideoBase.cpp
@@ -597,10 +597,7 @@ void CGUIWindowVideoBase::GetResumeItemOffset(const CFileItem *item, int64_t& st
}
else
{
- CBookmark bookmark;
- std::string strPath = item->GetPath();
- if ((item->IsVideoDb() || item->IsDVD()) && item->HasVideoInfoTag())
- strPath = item->GetVideoInfoTag()->m_strFileNameAndPath;
+ // Obtain the resume bookmark from video db...
CVideoDatabase db;
if (!db.Open())
@@ -608,12 +605,55 @@ void CGUIWindowVideoBase::GetResumeItemOffset(const CFileItem *item, int64_t& st
CLog::Log(LOGERROR, "{} - Cannot open VideoDatabase", __FUNCTION__);
return;
}
- if (db.GetResumeBookMark(strPath, bookmark))
+
+ std::string path = item->GetPath();
+ if (item->IsVideoDb() || item->IsDVD())
+ {
+ if (item->HasVideoInfoTag())
+ {
+ path = item->GetVideoInfoTag()->m_strFileNameAndPath;
+ }
+ else if (item->IsVideoDb())
+ {
+ // Obtain fileNamAndPath from video db
+ VIDEODATABASEDIRECTORY::CQueryParams params;
+ VIDEODATABASEDIRECTORY::CDirectoryNode::GetDatabaseInfo(item->GetPath(), params);
+
+ long id = -1;
+ VideoDbContentType content_type;
+ if ((id = params.GetMovieId()) >= 0)
+ content_type = VideoDbContentType::MOVIES;
+ else if ((id = params.GetEpisodeId()) >= 0)
+ content_type = VideoDbContentType::EPISODES;
+ else if ((id = params.GetMVideoId()) >= 0)
+ content_type = VideoDbContentType::MUSICVIDEOS;
+ else
+ {
+ CLog::Log(LOGERROR, "{} - Cannot obtain video content type", __FUNCTION__);
+ db.Close();
+ return;
+ }
+
+ db.GetFilePathById(static_cast<int>(id), path, content_type);
+ }
+ else
+ {
+ // DVD
+ CLog::Log(LOGERROR, "{} - Cannot obtain bookmark for DVD", __FUNCTION__);
+ db.Close();
+ return;
+ }
+ }
+
+ CBookmark bookmark;
+ db.GetResumeBookMark(path, bookmark);
+ db.Close();
+
+ if (bookmark.IsSet())
{
startoffset = CUtil::ConvertSecsToMilliSecs(bookmark.timeInSeconds);
partNumber = bookmark.partNumber;
}
- db.Close();
}
}
}
@@ -704,6 +744,11 @@ bool CGUIWindowVideoBase::OnFileAction(int iItem, int action, const std::string&
return true;
case SELECT_ACTION_RESUME:
item->SetStartOffset(STARTOFFSET_RESUME);
+ if (item->m_bIsFolder)
+ {
+ PlayItem(iItem, player);
+ return true;
+ }
break;
case SELECT_ACTION_PLAYPART:
if (!OnPlayStackPart(iItem))
@@ -713,6 +758,12 @@ bool CGUIWindowVideoBase::OnFileAction(int iItem, int action, const std::string&
OnQueueItem(iItem);
return true;
case SELECT_ACTION_PLAY:
+ if (item->m_bIsFolder)
+ {
+ PlayItem(iItem, player);
+ return true;
+ }
+ break;
default:
break;
}
@@ -788,23 +839,125 @@ void CGUIWindowVideoBase::OnRestartItem(int iItem, const std::string &player)
CGUIMediaWindow::OnClick(iItem, player);
}
+namespace
+{
+bool HasInProgressVideo(const std::string& path, CVideoDatabase& db)
+{
+ //! @todo this function is really very expensive and should be optimized (at db level).
+
+ CFileItemList items;
+ CUtil::GetRecursiveListing(path, items, {}, XFILE::DIR_FLAG_DEFAULTS);
+
+ if (items.IsEmpty())
+ return false;
+
+ for (const auto& item : items)
+ {
+ const auto videoTag = item->GetVideoInfoTag();
+ if (!item->HasVideoInfoTag())
+ continue;
+
+ if (videoTag->GetPlayCount() > 0)
+ continue;
+
+ // get resume point
+ CBookmark bookmark(videoTag->GetResumePoint());
+ if (!bookmark.IsSet() && db.GetResumeBookMark(videoTag->m_strFileNameAndPath, bookmark))
+ videoTag->SetResumePoint(bookmark);
+
+ if (bookmark.IsSet())
+ return true;
+ }
+
+ return false;
+}
+} // unnamed namespace
+
std::string CGUIWindowVideoBase::GetResumeString(const CFileItem &item)
{
std::string resumeString;
- int64_t startOffset = 0;
- int startPart = 0;
- GetResumeItemOffset(&item, startOffset, startPart);
- if (startOffset > 0)
+ if (item.m_bIsFolder)
+ {
+ bool hasInProgressVideo = false;
+
+ CFileItem folderItem(item);
+ if ((!folderItem.HasProperty("watchedepisodes") || // season/show
+ (folderItem.GetProperty("watchedepisodes").asInteger() == 0)) &&
+ (!folderItem.HasProperty("watched") || // movie set
+ (folderItem.GetProperty("watched").asInteger() == 0)))
+ {
+ CVideoDatabase db;
+ if (db.Open())
+ {
+ if (!folderItem.HasProperty("watchedepisodes") && !folderItem.HasProperty("watched"))
+ {
+ VIDEODATABASEDIRECTORY::CQueryParams params;
+ VIDEODATABASEDIRECTORY::CDirectoryNode::GetDatabaseInfo(item.GetPath(), params);
+
+ if (params.GetTvShowId() >= 0)
+ {
+ if (params.GetSeason() >= 0)
+ {
+ const int idSeason = db.GetSeasonId(static_cast<int>(params.GetTvShowId()),
+ static_cast<int>(params.GetSeason()));
+ if (idSeason >= 0)
+ {
+ CVideoInfoTag details;
+ db.GetSeasonInfo(idSeason, details, &folderItem);
+ }
+ }
+ else
+ {
+ CVideoInfoTag details;
+ db.GetTvShowInfo(item.GetPath(), details, static_cast<int>(params.GetTvShowId()),
+ &folderItem);
+ }
+ }
+ else if (params.GetSetId() >= 0)
+ {
+ CVideoInfoTag details;
+ db.GetSetInfo(static_cast<int>(params.GetSetId()), details, &folderItem);
+ }
+ }
+
+ // no episodes/movies watched completely, but there could be some or more we have
+ // started watching
+ if ((folderItem.HasProperty("watchedepisodes") && // season/show
+ folderItem.GetProperty("watchedepisodes").asInteger() == 0) ||
+ (folderItem.HasProperty("watched") && // movie set
+ folderItem.GetProperty("watched").asInteger() == 0))
+ hasInProgressVideo = HasInProgressVideo(item.GetPath(), db);
+
+ db.Close();
+ }
+ }
+
+ if (hasInProgressVideo ||
+ (folderItem.GetProperty("watchedepisodes").asInteger() > 0 &&
+ folderItem.GetProperty("unwatchedepisodes").asInteger() > 0) ||
+ (folderItem.GetProperty("watched").asInteger() > 0 &&
+ folderItem.GetProperty("unwatched").asInteger() > 0))
+ {
+ resumeString = g_localizeStrings.Get(13362); // Continue watching
+ }
+ }
+ else
{
- resumeString =
- StringUtils::Format(g_localizeStrings.Get(12022),
- StringUtils::SecondsToTimeString(
- static_cast<long>(CUtil::ConvertMilliSecsToSecsInt(startOffset)),
- TIME_FORMAT_HH_MM_SS));
- if (startPart > 0)
+ int64_t startOffset = 0;
+ int startPart = 0;
+ GetResumeItemOffset(&item, startOffset, startPart);
+ if (startOffset > 0)
{
- std::string partString = StringUtils::Format(g_localizeStrings.Get(23051), startPart);
- resumeString += " (" + partString + ")";
+ resumeString =
+ StringUtils::Format(g_localizeStrings.Get(12022),
+ StringUtils::SecondsToTimeString(
+ static_cast<long>(CUtil::ConvertMilliSecsToSecsInt(startOffset)),
+ TIME_FORMAT_HH_MM_SS));
+ if (startPart > 0)
+ {
+ std::string partString = StringUtils::Format(g_localizeStrings.Get(23051), startPart);
+ resumeString += " (" + partString + ")";
+ }
}
}
return resumeString;
@@ -812,7 +965,7 @@ std::string CGUIWindowVideoBase::GetResumeString(const CFileItem &item)
bool CGUIWindowVideoBase::ShowResumeMenu(CFileItem &item)
{
- if (!item.m_bIsFolder && !item.IsPVR())
+ if (!item.IsLiveTV())
{
std::string resumeString = GetResumeString(item);
if (!resumeString.empty())
@@ -835,13 +988,6 @@ bool CGUIWindowVideoBase::OnResumeItem(int iItem, const std::string &player)
if (iItem < 0 || iItem >= m_vecItems->Size()) return true;
CFileItemPtr item = m_vecItems->Get(iItem);
- if (item->m_bIsFolder)
- {
- // resuming directories isn't supported yet. play.
- PlayItem(iItem, player);
- return true;
- }
-
std::string resumeString = GetResumeString(*item);
if (!resumeString.empty())
@@ -855,6 +1001,13 @@ bool CGUIWindowVideoBase::OnResumeItem(int iItem, const std::string &player)
return OnFileAction(iItem, value, player);
}
+ if (item->m_bIsFolder)
+ {
+ // resuming directories isn't fully supported yet. play all of its content.
+ PlayItem(iItem, player);
+ return true;
+ }
+
return OnFileAction(iItem, SELECT_ACTION_PLAY, player);
}