diff --git a/system/library/music/albums_services.xml b/system/library/music/albums_services.xml new file mode 100644 index 0000000000..a7bf5da687 --- /dev/null +++ b/system/library/music/albums_services.xml @@ -0,0 +1,7 @@ + + + + DefaultMusicAlbums.png + services://music/albums + albums + diff --git a/system/library/music/artists_services.xml b/system/library/music/artists_services.xml new file mode 100644 index 0000000000..ca35795f77 --- /dev/null +++ b/system/library/music/artists_services.xml @@ -0,0 +1,7 @@ + + + + DefaultMusicArtists.png + artists + services://music/artists/ + diff --git a/system/library/music/recentlyaddedalbums.xml b/system/library/music/recentlyaddedalbums.xml index 549d1c2fd4..ede74c35b9 100644 --- a/system/library/music/recentlyaddedalbums.xml +++ b/system/library/music/recentlyaddedalbums.xml @@ -1,6 +1,6 @@ - + DefaultMusicRecentlyAdded.png - musicdb://recentlyaddedalbums/ + services://music/recentlyaddedalbums/ diff --git a/system/library/music/songs_services.xml b/system/library/music/songs_services.xml new file mode 100644 index 0000000000..bc2d03b064 --- /dev/null +++ b/system/library/music/songs_services.xml @@ -0,0 +1,7 @@ + + + + DefaultMusicSongs.png + songs + services://music/songs/ + diff --git a/system/library/video/inprogressmovies.xml b/system/library/video/inprogressmovies.xml index ed3f14a2d3..fbb89bd974 100644 --- a/system/library/video/inprogressmovies.xml +++ b/system/library/video/inprogressmovies.xml @@ -1,7 +1,7 @@ - + DefaultInProgressShows.png movies - + services://movies/inprogressmovies diff --git a/system/library/video/inprogressshows.xml b/system/library/video/inprogressshows.xml index f058db54bf..c3eaf0b9db 100644 --- a/system/library/video/inprogressshows.xml +++ b/system/library/video/inprogressshows.xml @@ -1,7 +1,7 @@ - + DefaultInProgressShows.png tvshows - + services://tvshows/inprogressshows/ diff --git a/system/library/video/movies_services/actors.xml b/system/library/video/movies_services/actors.xml new file mode 100644 index 0000000000..2ce84dbf39 --- /dev/null +++ b/system/library/video/movies_services/actors.xml @@ -0,0 +1,8 @@ + + + + DefaultActor.png + movies + services://movies/actors/ + + diff --git a/system/library/video/movies_services/country.xml b/system/library/video/movies_services/country.xml new file mode 100644 index 0000000000..a419a503bb --- /dev/null +++ b/system/library/video/movies_services/country.xml @@ -0,0 +1,7 @@ + + + + DefaultCountry.png + movies + services://movies/countries/ + diff --git a/system/library/video/movies_services/directors.xml b/system/library/video/movies_services/directors.xml new file mode 100644 index 0000000000..710a8de0f9 --- /dev/null +++ b/system/library/video/movies_services/directors.xml @@ -0,0 +1,7 @@ + + + + DefaultDirector.png + movies + services://movies/directors/ + diff --git a/system/library/video/movies_services/genres.xml b/system/library/video/movies_services/genres.xml new file mode 100644 index 0000000000..040f202ea4 --- /dev/null +++ b/system/library/video/movies_services/genres.xml @@ -0,0 +1,7 @@ + + + + DefaultGenre.png + movies + services://movies/genres/ + diff --git a/system/library/video/movies_services/index.xml b/system/library/video/movies_services/index.xml new file mode 100644 index 0000000000..2c8cf9de7c --- /dev/null +++ b/system/library/video/movies_services/index.xml @@ -0,0 +1,6 @@ + + + + + DefaultMovies.png + diff --git a/system/library/video/movies_services/sets.xml b/system/library/video/movies_services/sets.xml new file mode 100644 index 0000000000..d84b734f68 --- /dev/null +++ b/system/library/video/movies_services/sets.xml @@ -0,0 +1,7 @@ + + + + DefaultSets.png + movies + services://movies/sets/ + diff --git a/system/library/video/movies_services/studios.xml b/system/library/video/movies_services/studios.xml new file mode 100644 index 0000000000..1883604ab3 --- /dev/null +++ b/system/library/video/movies_services/studios.xml @@ -0,0 +1,7 @@ + + + + DefaultStudios.png + movies + services://movies/studios/ + diff --git a/system/library/video/movies_services/tags.xml b/system/library/video/movies_services/tags.xml new file mode 100644 index 0000000000..2a1d807670 --- /dev/null +++ b/system/library/video/movies_services/tags.xml @@ -0,0 +1,7 @@ + + + + DefaultTags.png + movies + services://movies/tags/ + diff --git a/system/library/video/movies_services/titles.xml b/system/library/video/movies_services/titles.xml new file mode 100644 index 0000000000..261ad13813 --- /dev/null +++ b/system/library/video/movies_services/titles.xml @@ -0,0 +1,8 @@ + + + + DefaultMovieTitle.png + movies + sorttitle + services://movies/titles/ + diff --git a/system/library/video/movies_services/years.xml b/system/library/video/movies_services/years.xml new file mode 100644 index 0000000000..45e3fb2ee6 --- /dev/null +++ b/system/library/video/movies_services/years.xml @@ -0,0 +1,8 @@ + + + + DefaultYear.png + movies + services://movies/years/ + + diff --git a/system/library/video/recentlyaddedepisodes.xml b/system/library/video/recentlyaddedepisodes.xml index caf13574d8..42eedce004 100644 --- a/system/library/video/recentlyaddedepisodes.xml +++ b/system/library/video/recentlyaddedepisodes.xml @@ -1,6 +1,6 @@ - + DefaultRecentlyAddedEpisodes.png - videodb://recentlyaddedepisodes/ + services://tvshows/recentlyaddedepisodes/ diff --git a/system/library/video/recentlyaddedmovies.xml b/system/library/video/recentlyaddedmovies.xml index 1363d4b854..d8d01f2ce0 100644 --- a/system/library/video/recentlyaddedmovies.xml +++ b/system/library/video/recentlyaddedmovies.xml @@ -1,6 +1,6 @@ - + DefaultRecentlyAddedMovies.png - videodb://recentlyaddedmovies/ + services://movies/recentlyaddedmovies/ diff --git a/system/library/video/tvshows_services/actors.xml b/system/library/video/tvshows_services/actors.xml new file mode 100644 index 0000000000..2a8bd5b6ed --- /dev/null +++ b/system/library/video/tvshows_services/actors.xml @@ -0,0 +1,7 @@ + + + + DefaultActor.png + tvshows + services://tvshows/actors/ + diff --git a/system/library/video/tvshows_services/genres.xml b/system/library/video/tvshows_services/genres.xml new file mode 100644 index 0000000000..ac07cb0097 --- /dev/null +++ b/system/library/video/tvshows_services/genres.xml @@ -0,0 +1,7 @@ + + + + DefaultGenre.png + tvshows + services://tvshows/genres/ + diff --git a/system/library/video/tvshows_services/index.xml b/system/library/video/tvshows_services/index.xml new file mode 100644 index 0000000000..5a86f1f3c5 --- /dev/null +++ b/system/library/video/tvshows_services/index.xml @@ -0,0 +1,5 @@ + + + + DefaultTVShows.png + diff --git a/system/library/video/tvshows_services/studios.xml b/system/library/video/tvshows_services/studios.xml new file mode 100644 index 0000000000..3cf1932e78 --- /dev/null +++ b/system/library/video/tvshows_services/studios.xml @@ -0,0 +1,7 @@ + + + + DefaultStudios.png + tvshows + services://tvshows/studios/ + diff --git a/system/library/video/tvshows_services/tags.xml b/system/library/video/tvshows_services/tags.xml new file mode 100644 index 0000000000..d6103a510c --- /dev/null +++ b/system/library/video/tvshows_services/tags.xml @@ -0,0 +1,7 @@ + + + + DefaultTags.png + tvshows + services://tvshows/tags/ + diff --git a/system/library/video/tvshows_services/titles.xml b/system/library/video/tvshows_services/titles.xml new file mode 100644 index 0000000000..7fba49a70d --- /dev/null +++ b/system/library/video/tvshows_services/titles.xml @@ -0,0 +1,8 @@ + + + + DefaultTVShowTitle.png + tvshows + services://tvshows/titles/ + sorttitle + diff --git a/system/library/video/tvshows_services/years.xml b/system/library/video/tvshows_services/years.xml new file mode 100644 index 0000000000..9823ec0c15 --- /dev/null +++ b/system/library/video/tvshows_services/years.xml @@ -0,0 +1,7 @@ + + + + DefaultYear.png + tvshows + services://tvshows/years/ + diff --git a/system/library/video_flat/inprogressmovies.xml b/system/library/video_flat/inprogressmovies.xml new file mode 100644 index 0000000000..fbb89bd974 --- /dev/null +++ b/system/library/video_flat/inprogressmovies.xml @@ -0,0 +1,7 @@ + + + + DefaultInProgressShows.png + movies + services://movies/inprogressmovies + diff --git a/system/library/video_flat/inprogressshows.xml b/system/library/video_flat/inprogressshows.xml index f058db54bf..c3eaf0b9db 100644 --- a/system/library/video_flat/inprogressshows.xml +++ b/system/library/video_flat/inprogressshows.xml @@ -1,7 +1,7 @@ - + DefaultInProgressShows.png tvshows - + services://tvshows/inprogressshows/ diff --git a/system/library/video_flat/movies.xml b/system/library/video_flat/movies.xml index 13f2904e84..2cc29768fd 100644 --- a/system/library/video_flat/movies.xml +++ b/system/library/video_flat/movies.xml @@ -1,7 +1,8 @@ - + DefaultMovies.png movies sorttitle + services://movies/titles/ diff --git a/system/library/video_flat/recentlyaddedepisodes.xml b/system/library/video_flat/recentlyaddedepisodes.xml index caf13574d8..42eedce004 100644 --- a/system/library/video_flat/recentlyaddedepisodes.xml +++ b/system/library/video_flat/recentlyaddedepisodes.xml @@ -1,6 +1,6 @@ - + DefaultRecentlyAddedEpisodes.png - videodb://recentlyaddedepisodes/ + services://tvshows/recentlyaddedepisodes/ diff --git a/system/library/video_flat/recentlyaddedmovies.xml b/system/library/video_flat/recentlyaddedmovies.xml index 1363d4b854..d8d01f2ce0 100644 --- a/system/library/video_flat/recentlyaddedmovies.xml +++ b/system/library/video_flat/recentlyaddedmovies.xml @@ -1,6 +1,6 @@ - + DefaultRecentlyAddedMovies.png - videodb://recentlyaddedmovies/ + services://movies/recentlyaddedmovies/ diff --git a/system/library/video_flat/tvshows.xml b/system/library/video_flat/tvshows.xml index 5f19e4d89b..2eba10cd2d 100644 --- a/system/library/video_flat/tvshows.xml +++ b/system/library/video_flat/tvshows.xml @@ -1,7 +1,8 @@ - + DefaultTVShows.png tvshows sorttitle + services://movies/titles/ diff --git a/xbmc/FileItem.cpp b/xbmc/FileItem.cpp index 094d53de52..57b11a4fa1 100644 --- a/xbmc/FileItem.cpp +++ b/xbmc/FileItem.cpp @@ -1150,6 +1150,11 @@ bool CFileItem::IsVirtualDirectoryRoot() const return (m_bIsFolder && m_strPath.empty()); } +bool CFileItem::IsFolder() const +{ + return m_bIsFolder; +} + bool CFileItem::IsRemovable() const { return IsOnDVD() || IsCDDA() || m_iDriveType == CMediaSource::SOURCE_TYPE_REMOVABLE; diff --git a/xbmc/FileItem.h b/xbmc/FileItem.h index 03d6c72dc9..eaf562bc9c 100644 --- a/xbmc/FileItem.h +++ b/xbmc/FileItem.h @@ -218,6 +218,7 @@ class CFileItem : bool IsPVRRadioRDS() const; bool IsType(const char *ext) const; bool IsVirtualDirectoryRoot() const; + bool IsFolder() const; bool IsReadOnly() const; bool CanQueue() const; void SetCanQueue(bool bYesNo); diff --git a/xbmc/Util.cpp b/xbmc/Util.cpp index 674f6ff767..8231d0f872 100644 --- a/xbmc/Util.cpp +++ b/xbmc/Util.cpp @@ -1033,6 +1033,12 @@ int CUtil::GetMatchingSource(const std::string& strPath1, VECSOURCES& VECSOURCES strPath = checkURL.GetHostName(); if (checkURL.IsProtocol("plugin")) return 1; + if (checkURL.IsProtocol("services")) + return 1; + if (checkURL.IsProtocol("plex")) + return 1; + if (checkURL.IsProtocol("emby")) + return 1; if (checkURL.IsProtocol("multipath")) strPath = CMultiPathDirectory::GetFirstPath(strPath); diff --git a/xbmc/addons/AddonManager.cpp b/xbmc/addons/AddonManager.cpp index ec40f42194..ebfe18ab19 100644 --- a/xbmc/addons/AddonManager.cpp +++ b/xbmc/addons/AddonManager.cpp @@ -201,12 +201,14 @@ static constexpr const char* addonWhiteList[] = { "screensaver.xbmc.builtin.system", "script.module.requests", "script.plex", + "script.skinshortcuts", "skin.amber", "skin.blackglassnova", "skin.mrmc", "skin.opacity", - "skin.pm3.hd", + "skin.pm3-hd", "skin.sio2", + "skin.titan", "visualization.spectrum", "visualization.waveform", "webinterface.default", diff --git a/xbmc/addons/Skin.cpp b/xbmc/addons/Skin.cpp index fcdb426ae6..4f44d98ea3 100644 --- a/xbmc/addons/Skin.cpp +++ b/xbmc/addons/Skin.cpp @@ -235,6 +235,19 @@ void CSkinInfo::Start() m_currentAspect = res.strId; } } + +std::string CSkinInfo::GetSkinIncludeFile(const std::string& strFile) const +{ + // try to load include from alternate location (support for skinshortcuts etc.) + std::string strPathAlt = URIUtils::AddFileToFolder(Profile(), strFile); + if (CFile::Exists(strPathAlt)) + { + CLog::Log(LOGDEBUG, "Loading skin include from non-default location: %s", strPathAlt.c_str()); + return strPathAlt; + } + else + return GetSkinPath(strFile); +} std::string CSkinInfo::GetSkinPath(const std::string& strFile, RESOLUTION_INFO *res, const std::string& strBaseDir /* = "" */) const { @@ -264,6 +277,7 @@ std::string CSkinInfo::GetSkinPath(const std::string& strFile, RESOLUTION_INFO * strPath = URIUtils::AddFileToFolder(strPathToUse, res->strMode); strPath = URIUtils::AddFileToFolder(strPath, strFile); + return strPath; } diff --git a/xbmc/addons/Skin.h b/xbmc/addons/Skin.h index a1278bed68..b78d7afde3 100644 --- a/xbmc/addons/Skin.h +++ b/xbmc/addons/Skin.h @@ -117,6 +117,13 @@ class CSkinInfo : public CAddon void Start(); bool HasSkinFile(const std::string &strFile) const; + + /*! \brief Get the full path for the specified file in the skin's include definition. + Try custom path first (for compatability with scripts like skinshortcuts etc.) + \param file XML file to look for + \return path to the XML file + */ + std::string GetSkinIncludeFile(const std::string& strFile) const; /*! \brief Get the full path to the specified file in the skin We search for XML files in the skin folder that best matches the current resolution. diff --git a/xbmc/filesystem/FavouritesDirectory.cpp b/xbmc/filesystem/FavouritesDirectory.cpp index cc09b0db9b..5606f7c78f 100644 --- a/xbmc/filesystem/FavouritesDirectory.cpp +++ b/xbmc/filesystem/FavouritesDirectory.cpp @@ -201,6 +201,8 @@ std::string CFavouritesDirectory::GetExecutePath(const CFileItem &item, const st { if (item.IsVideoDb() && item.HasVideoInfoTag()) execute = StringUtils::Format("PlayMedia(%s)", StringUtils::Paramify(item.GetVideoInfoTag()->m_strFileNameAndPath).c_str()); + else if (item.IsMediaServiceBased() && item.HasVideoInfoTag()) + execute = StringUtils::Format("PlayMedia(%s)", StringUtils::Paramify(item.GetVideoInfoTag()->m_strFileNameAndPath).c_str()); else if (item.IsMusicDb() && item.HasMusicInfoTag()) execute = StringUtils::Format("PlayMedia(%s)", StringUtils::Paramify(item.GetMusicInfoTag()->GetURL()).c_str()); else if (item.IsPicture()) diff --git a/xbmc/filesystem/PlexDirectory.cpp b/xbmc/filesystem/PlexDirectory.cpp index efa45335d6..cbdb345647 100644 --- a/xbmc/filesystem/PlexDirectory.cpp +++ b/xbmc/filesystem/PlexDirectory.cpp @@ -54,11 +54,16 @@ bool CPlexDirectory::GetDirectory(const CURL& url, CFileItemList &items) CLog::Log(LOGDEBUG, "CPlexDirectory::GetDirectory strURL = %s", strUrl.c_str()); - CVideoDatabase database; - database.Open(); - bool hasMovies = database.HasContent(VIDEODB_CONTENT_MOVIES); - bool hasShows = database.HasContent(VIDEODB_CONTENT_TVSHOWS); - database.Close(); + CVideoDatabase vdatabase; + vdatabase.Open(); + bool hasMovies = vdatabase.HasContent(VIDEODB_CONTENT_MOVIES); + bool hasShows = vdatabase.HasContent(VIDEODB_CONTENT_TVSHOWS); + vdatabase.Close(); + CMusicDatabase mdatabase; + mdatabase.Open(); + bool hasMusic = mdatabase.HasContent(); + mdatabase.Close(); + if (StringUtils::StartsWithNoCase(strUrl, "plex://movies/")) { @@ -306,15 +311,27 @@ bool CPlexDirectory::GetDirectory(const CURL& url, CFileItemList &items) { if (section.empty()) { - //look through all plex servers and pull content data for "show" type + std::string pathsection = ""; + if (basePath == "artists") + pathsection = "all"; + else if (basePath == "albums") + pathsection = "all?type=9"; + else if (basePath == "songs") + pathsection = "all?type=10"; + else if (basePath == "recentlyaddedalbums") + pathsection = "recentlyAdded"; + //look through all plex servers and pull content data for "music" type std::vector clients; CPlexServices::GetInstance().GetClients(clients); for (const auto &client : clients) { client->ClearSectionItems(); std::vector contents = client->GetArtistContent(); - if (contents.size() > 1 || ((items.Size() > 0 || CServicesManager::GetInstance().HasEmbyServices() || clients.size() > 1) && contents.size() == 1)) + if (contents.size() > 1 || + ((items.Size() > 0 || hasMusic || CServicesManager::GetInstance().HasEmbyServices() || + clients.size() > 1) && contents.size() == 1)) { + // multiple folders or providers found, add root folder for each node for (const auto &content : contents) { std::string title = client->FormatContentTitle(content.title); @@ -325,7 +342,7 @@ bool CPlexDirectory::GetDirectory(const CURL& url, CFileItemList &items) // have to do it this way because raw url has authToken as protocol option CURL curl(client->GetUrl()); curl.SetProtocol(client->GetProtocol()); - std::string filename = StringUtils::Format("%s/%s", content.section.c_str(), (basePath == "root" || basePath == "artists"? "all":basePath.c_str())); + std::string filename = StringUtils::Format("%s/%s", content.section.c_str(), pathsection.c_str()); curl.SetFileName(filename); pItem->SetPath("plex://music/" + basePath + "/" + Base64URL::Encode(curl.Get())); pItem->SetLabel(title); @@ -341,16 +358,16 @@ bool CPlexDirectory::GetDirectory(const CURL& url, CFileItemList &items) } else if (contents.size() == 1) { + // only one folder/provider found, pull content directly CURL curl(client->GetUrl()); curl.SetProtocol(client->GetProtocol()); - curl.SetFileName(contents[0].section + "/all"); - CPlexUtils::GetPlexArtistsOrAlbum(items, curl.Get(), false); + std::string filename = StringUtils::Format("%s/%s", contents[0].section.c_str(), pathsection.c_str()); + curl.SetFileName(filename); + CDirectory::GetDirectory("plex://music/" + basePath + "/" + Base64URL::Encode(curl.Get()), items); items.SetContent("artists"); - items.SetPath("plex://music/albums/"); CPlexUtils::SetPlexItemProperties(items, client); for (int item = 0; item < items.Size(); ++item) CPlexUtils::SetPlexItemProperties(*items[item], client); - CLog::Log(LOGDEBUG, "CPlexDirectory::GetDirectory '/all' client(%s), shows(%d)", client->GetServerName().c_str(), items.Size()); } std::string label = basePath; if (URIUtils::GetFileName(basePath) == "recentlyaddedalbums") diff --git a/xbmc/guilib/GUIIncludes.cpp b/xbmc/guilib/GUIIncludes.cpp index 3ee1138be7..5590087476 100644 --- a/xbmc/guilib/GUIIncludes.cpp +++ b/xbmc/guilib/GUIIncludes.cpp @@ -146,20 +146,20 @@ bool CGUIIncludes::LoadIncludesFromXML(const TiXmlElement *root) } else if (node->Attribute("file")) { + std::string includeFile = g_SkinInfo->GetSkinIncludeFile(node->Attribute("file")); const char *condition = node->Attribute("condition"); if (condition) { // check this condition INFO::InfoPtr conditionID = g_infoManager.Register(condition); bool value = conditionID->Get(); - if (value) { // load this file in as well - LoadIncludes(g_SkinInfo->GetSkinPath(node->Attribute("file"))); + LoadIncludes(includeFile); } } else - LoadIncludes(g_SkinInfo->GetSkinPath(node->Attribute("file"))); + LoadIncludes(includeFile); } node = node->NextSiblingElement("include"); } diff --git a/xbmc/interfaces/IAnnouncer.h b/xbmc/interfaces/IAnnouncer.h index e3dfdd1f58..b3c5baae16 100644 --- a/xbmc/interfaces/IAnnouncer.h +++ b/xbmc/interfaces/IAnnouncer.h @@ -33,7 +33,8 @@ namespace ANNOUNCEMENT Application = 0x040, Input = 0x080, PVR = 0x100, - Other = 0x200 + Other = 0x200, + MediaService = 0x300 }; #define ANNOUNCE_ALL (Player | Playlist | GUI | System | VideoLibrary | AudioLibrary | Application | Input | ANNOUNCEMENT::PVR | Other) diff --git a/xbmc/listproviders/DirectoryProvider.cpp b/xbmc/listproviders/DirectoryProvider.cpp index d13a157a8a..e412872065 100644 --- a/xbmc/listproviders/DirectoryProvider.cpp +++ b/xbmc/listproviders/DirectoryProvider.cpp @@ -39,6 +39,9 @@ #include "utils/Variant.h" #include "utils/XMLUtils.h" #include "video/VideoThumbLoader.h" +#include "services/ServicesManager.h" +#include "playlists/PlayList.h" +#include "PlayListPlayer.h" using namespace XFILE; using namespace ANNOUNCEMENT; @@ -212,19 +215,20 @@ bool CDirectoryProvider::Update(bool forceRefresh) void CDirectoryProvider::Announce(AnnouncementFlag flag, const char *sender, const char *message, const CVariant &data) { // we are only interested in library changes - if ((flag & (VideoLibrary | AudioLibrary)) == 0) + if ((flag & (VideoLibrary | AudioLibrary | MediaService)) == 0) return; - { CSingleLock lock(m_section); // we don't need to refresh anything if there are no fitting // items in this list provider for the announcement flag - if (((flag & VideoLibrary) && - (std::find(m_itemTypes.begin(), m_itemTypes.end(), VIDEO) == m_itemTypes.end())) || - ((flag & AudioLibrary) && - (std::find(m_itemTypes.begin(), m_itemTypes.end(), AUDIO) == m_itemTypes.end()))) - return; - + if (m_itemTypes.size() > 0) + { + if (((flag & VideoLibrary) && + (std::find(m_itemTypes.begin(), m_itemTypes.end(), VIDEO) == m_itemTypes.end())) || + ((flag & AudioLibrary) && + (std::find(m_itemTypes.begin(), m_itemTypes.end(), AUDIO) == m_itemTypes.end()))) + return; + } // if we're in a database transaction, don't bother doing anything just yet if (data.isMember("transaction") && data["transaction"].asBoolean()) return; @@ -234,6 +238,7 @@ void CDirectoryProvider::Announce(AnnouncementFlag flag, const char *sender, con if (strcmp(message, "OnScanFinished") == 0 || strcmp(message, "OnCleanFinished") == 0 || strcmp(message, "OnUpdate") == 0 || + strcmp(message, "ServicesUpdated") == 0 || strcmp(message, "OnRemove") == 0) m_updateState = PENDING; } @@ -290,22 +295,65 @@ bool CDirectoryProvider::OnClick(const CGUIListItemPtr &item) if (item->IsFileItem()) { CFileItem fileItem(*std::static_pointer_cast(item)); - std::string target = fileItem.GetProperty("node.target").asString(); - if (target.empty()) - target = m_currentTarget; - if (target.empty()) - target = m_target.GetLabel(m_parentID, false); - if (fileItem.HasProperty("node.target_url")) - fileItem.SetPath(fileItem.GetProperty("node.target_url").asString()); - // grab the execute string - std::string execute = CFavouritesDirectory::GetExecutePath(fileItem, target); - if (!execute.empty()) + + if (fileItem.IsMediaServiceBased() && !fileItem.IsFolder()) { - CGUIMessage message(GUI_MSG_EXECUTE, 0, 0); - message.SetStringParam(execute); - g_windowManager.SendMessage(message); + // handle playback for items from mediaservice + if (fileItem.IsAudio()) + { + // music items + CFileItemList items; + CServicesManager::GetInstance().GetAlbumSongs(fileItem, items); + g_playlistPlayer.Reset(); + g_playlistPlayer.SetCurrentPlaylist(PLAYLIST_MUSIC); + PLAYLIST::CPlayList& playlist = g_playlistPlayer.GetPlaylist(PLAYLIST_MUSIC); + playlist.Clear(); + playlist.Add(items); + // play full album, starting with first song... + g_playlistPlayer.Play(0); + g_windowManager.ActivateWindow(WINDOW_VISUALISATION); + } + else + { + // video items + if (!CServicesManager::GetInstance().GetResolutions(fileItem)) + return false; + CServicesManager::GetInstance().GetURL(fileItem); + + // always resume at resume point for now + fileItem.m_lStartOffset = STARTOFFSET_RESUME; + + g_playlistPlayer.Reset(); + g_playlistPlayer.SetCurrentPlaylist(PLAYLIST_VIDEO); + PLAYLIST::CPlayList& playlist = g_playlistPlayer.GetPlaylist(PLAYLIST_VIDEO); + playlist.Clear(); + CFileItemPtr movieItem(new CFileItem(fileItem)); + playlist.Add(movieItem); + + // play item + g_playlistPlayer.Play(0); + } return true; } + else + { + std::string target = fileItem.GetProperty("node.target").asString(); + if (target.empty()) + target = m_currentTarget; + if (target.empty()) + target = m_target.GetLabel(m_parentID, false); + if (fileItem.HasProperty("node.target_url")) + fileItem.SetPath(fileItem.GetProperty("node.target_url").asString()); + // grab the execute string + std::string execute = CFavouritesDirectory::GetExecutePath(fileItem, target); + if (!execute.empty()) + { + CGUIMessage message(GUI_MSG_EXECUTE, 0, 0); + message.SetStringParam(execute); + g_windowManager.SendMessage(message); + return true; + } + } } return false; } @@ -346,8 +394,8 @@ bool CDirectoryProvider::UpdateURL() m_currentUrl = value; - // Register this provider only if we have library content - RegisterListProvider(URIUtils::IsLibraryContent(m_currentUrl)); + // Register this provider only if we have library content or a media service + RegisterListProvider(URIUtils::IsLibraryContent(m_currentUrl) || URIUtils::IsServices(m_currentUrl)); return true; } diff --git a/xbmc/services/plex/PlexUtils.cpp b/xbmc/services/plex/PlexUtils.cpp index cce24435b0..d552e4cabd 100644 --- a/xbmc/services/plex/PlexUtils.cpp +++ b/xbmc/services/plex/PlexUtils.cpp @@ -165,6 +165,47 @@ void CPlexUtils::SetPlexItemProperties(CFileItem &item, const CPlexClientPtr &cl item.SetProperty("MediaServicesLocalItem", true); } +void CPlexUtils::SetPlexRatingProperties(CFileItem &plexItem, const CVariant &item) +{ + // set rating (extract ratingtype from ratingimage) + std::string ratingProvider = ""; + std::string ratingDelimiter = "://"; + std::string ratingImageValue = item["ratingImage"].asString(); + if (ratingImageValue != "") + { + std::string::size_type pos = ratingImageValue.find(ratingDelimiter); + ratingProvider = ratingImageValue.substr(0, pos); + std::string ratingImage = ratingImageValue.substr(pos + ratingDelimiter.length()); + plexItem.SetProperty("ratingImage", ratingImage); + if (ratingProvider == "rottentomatoes") + plexItem.SetProperty("RottenTomatoesRating", item["rating"].asFloat() * 10); + } + plexItem.GetVideoInfoTag()->SetRating(item["rating"].asFloat(), ratingProvider, true); + + // audience rating + std::string audienceRatingImageValue = item["audienceRatingImage"].asString(); + if (audienceRatingImageValue != "") + { + std::string::size_type pos = audienceRatingImageValue.find(ratingDelimiter); + ratingProvider = audienceRatingImageValue.substr(0, pos); + std::string audienceRatingImage = audienceRatingImageValue.substr(pos + ratingDelimiter.length()); + plexItem.SetProperty("audienceRatingImage", audienceRatingImage); + plexItem.SetProperty("audienceRating", item["audienceRating"].asString()); + if (ratingProvider == "rottentomatoes") + plexItem.SetProperty("RottenTomatoesAudienceRating", item["audienceRating"].asFloat() * 10); + ratingProvider += "audience"; + plexItem.GetVideoInfoTag()->SetRating(item["audienceRating"].asFloat(), ratingProvider, false); + } + + // User rating + if (item["userRating"].asString() != "") { + plexItem.GetVideoInfoTag()->SetUserrating(item["userRating"].asInteger()); + } + + // MPAA rating + plexItem.GetVideoInfoTag()->m_strMPAARating = item["contentRating"].asString(); +} + #pragma mark - Plex Server Utils void CPlexUtils::SetWatched(CFileItem &item) { @@ -616,7 +657,7 @@ bool CPlexUtils::GetItemSubtiles(CFileItem &item) for (auto variantIt = variantMedia.begin_array(); variantIt != variantMedia.end_array(); ++variantIt) { if (*variantIt != CVariant::VariantTypeNull) - GetMediaDetals(item, curl, *variantIt, item.GetProperty("PlexMediaID").asString()); + GetMediaDetails(item, curl, *variantIt, item.GetProperty("PlexMediaID").asString()); } } } @@ -681,7 +722,7 @@ bool CPlexUtils::GetMoreResolutions(CFileItem &item) if (*variantIt != CVariant::VariantTypeNull) { CFileItem mediaItem(item); - GetMediaDetals(mediaItem, curl, *variantIt); + GetMediaDetails(mediaItem, curl, *variantIt); resolutionList.push_back(mediaItem); choices.Add(resolutionList.size(), mediaItem.GetProperty("PlexResolutionChoice").c_str()); } @@ -1287,9 +1328,10 @@ bool CPlexUtils::ParsePlexVideos(CFileItemList &items, CURL url, const CVariant plexItem->SetArt("fanart", url.Get()); plexItem->GetVideoInfoTag()->SetYear(item["year"].asInteger()); - plexItem->GetVideoInfoTag()->SetRating(item["rating"].asFloat()); - plexItem->GetVideoInfoTag()->m_strMPAARating = item["contentRating"].asString(); - + + // Set ratings + SetPlexRatingProperties(*plexItem, item); + // lastViewedAt means that it was watched, if so we set m_playCount to 1 and set overlay. // If we have "viewOffset" that means we are partially watched and shoudl not set m_playCount to 1 if (item.isMember("lastViewedAt") && !item.isMember("viewOffset")) @@ -1306,7 +1348,7 @@ bool CPlexUtils::ParsePlexVideos(CFileItemList &items, CURL url, const CVariant plexItem->m_lStartOffset = item["viewOffset"].asInteger() / 1000; const CVariant media = makeVariantArrayIfSingleItem(item["Media"]); - GetMediaDetals(*plexItem, url, media[0]); + GetMediaDetails(*plexItem, url, media[0]); if (formatLabel) { @@ -1848,7 +1890,7 @@ void CPlexUtils::GetMusicDetails(CFileItem &item, const CVariant &video) */ } -void CPlexUtils::GetMediaDetals(CFileItem &item, CURL url, const CVariant &media, std::string id) +void CPlexUtils::GetMediaDetails(CFileItem &item, CURL url, const CVariant &media, std::string id) { if (!media.isNull() && (id == "0" || media["id"].asString() == id)) { diff --git a/xbmc/services/plex/PlexUtils.h b/xbmc/services/plex/PlexUtils.h index 07453a7c6f..22e5502582 100644 --- a/xbmc/services/plex/PlexUtils.h +++ b/xbmc/services/plex/PlexUtils.h @@ -45,6 +45,7 @@ class CPlexUtils static void GetDefaultHeaders(XFILE::CCurlFile &curl); static void SetPlexItemProperties(CFileItem &item); static void SetPlexItemProperties(CFileItem &item, const CPlexClientPtr &client); + static void SetPlexRatingProperties(CFileItem &plexItem, const CVariant &item); // Plex Server Utils static void SetWatched(CFileItem &item); @@ -100,7 +101,7 @@ class CPlexUtils static void ReportToServer(std::string url, std::string filename); static void GetVideoDetails(CFileItem &item, const CVariant &variant); static void GetMusicDetails(CFileItem &item, const CVariant &video); - static void GetMediaDetals(CFileItem &item, CURL url, const CVariant &media, std::string id = "0"); + static void GetMediaDetails(CFileItem &item, CURL url, const CVariant &media, std::string id = "0"); static CVariant GetPlexCVariant(std::string url, std::string filter = ""); static TiXmlDocument GetPlexXML(std::string url, std::string filter = ""); static int ParsePlexCVariant(const CVariant &item); diff --git a/xbmc/utils/HomeShelfJob.cpp b/xbmc/utils/HomeShelfJob.cpp index 212af03525..b24a5f23ec 100644 --- a/xbmc/utils/HomeShelfJob.cpp +++ b/xbmc/utils/HomeShelfJob.cpp @@ -36,6 +36,7 @@ #include "video/VideoThumbLoader.h" #include "settings/Settings.h" #include "services/ServicesManager.h" +#include "interfaces/AnnouncementManager.h" #if defined(TARGET_DARWIN_TVOS) #include "platform/darwin/DarwinUtils.h" @@ -305,6 +306,9 @@ bool CHomeShelfJob::UpdateTotal() EpWatched = EpWatched + (mediaTotals.iEpisodeTotal - mediaTotals.iEpisodeUnwatched); EpCount = EpCount + mediaTotals.iEpisodeTotal; TvShowsWatched = TvShowsWatched + (mediaTotals.iShowTotal - mediaTotals.iShowUnwatched); + + // signal library providers that our services have been updated so lists can be refreshed if needed etc. + ANNOUNCEMENT::CAnnouncementManager::GetInstance().Announce(ANNOUNCEMENT::MediaService, "xbmc", "ServicesUpdated"); } home->SetProperty("Music.SongsCount" , MusSongTotals);