diff options
author | Kai Sommerfeld <kai.sommerfeld@gmx.com> | 2022-10-31 23:11:36 +0100 |
---|---|---|
committer | Kai Sommerfeld <kai.sommerfeld@gmx.com> | 2022-11-07 07:49:34 +0100 |
commit | 93c525bb448c5e1ba279567b8e72a34b7845e127 (patch) | |
tree | 3b0437246c9e31da166005a77e24bf35c32f31cc | |
parent | ee399f6e182c2b1ae10ccec40ea171588349290a (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.po | 8 | ||||
-rw-r--r-- | xbmc/FileItem.cpp | 74 | ||||
-rw-r--r-- | xbmc/FileItem.h | 11 | ||||
-rw-r--r-- | xbmc/interfaces/builtins/PlayerBuiltins.cpp | 15 | ||||
-rw-r--r-- | xbmc/pvr/windows/GUIWindowPVRRecordings.cpp | 24 | ||||
-rw-r--r-- | xbmc/video/ContextMenus.cpp | 4 | ||||
-rw-r--r-- | xbmc/video/VideoDatabase.cpp | 38 | ||||
-rw-r--r-- | xbmc/video/VideoDatabase.h | 4 | ||||
-rw-r--r-- | xbmc/video/windows/GUIWindowVideoBase.cpp | 205 |
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); } |