Merge pull request #25808 from CastagnaIT/fix_url_parse
[xbmc.git] / xbmc / filesystem / SmartPlaylistDirectory.cpp
blobd82727900da0633c99db480ef50ef81ceb4d04e4
1 /*
2 * Copyright (C) 2005-2018 Team Kodi
3 * This file is part of Kodi - https://kodi.tv
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 * See LICENSES/README.md for more information.
7 */
9 #include "SmartPlaylistDirectory.h"
11 #include "FileItem.h"
12 #include "FileItemList.h"
13 #include "ServiceBroker.h"
14 #include "filesystem/Directory.h"
15 #include "filesystem/File.h"
16 #include "filesystem/FileDirectoryFactory.h"
17 #include "music/MusicDatabase.h"
18 #include "music/MusicDbUrl.h"
19 #include "playlists/PlayListTypes.h"
20 #include "playlists/SmartPlayList.h"
21 #include "settings/Settings.h"
22 #include "settings/SettingsComponent.h"
23 #include "utils/SortUtils.h"
24 #include "utils/StringUtils.h"
25 #include "utils/URIUtils.h"
26 #include "video/VideoDatabase.h"
27 #include "video/VideoDbUrl.h"
29 #include <memory>
31 #define PROPERTY_PATH_DB "path.db"
32 #define PROPERTY_SORT_ORDER "sort.order"
33 #define PROPERTY_SORT_ASCENDING "sort.ascending"
34 #define PROPERTY_GROUP_BY "group.by"
35 #define PROPERTY_GROUP_MIXED "group.mixed"
37 using namespace KODI;
39 namespace XFILE
41 CSmartPlaylistDirectory::CSmartPlaylistDirectory() = default;
43 CSmartPlaylistDirectory::~CSmartPlaylistDirectory() = default;
45 bool CSmartPlaylistDirectory::GetDirectory(const CURL& url, CFileItemList& items)
47 // Load in the SmartPlaylist and get the WHERE query
48 PLAYLIST::CSmartPlaylist playlist;
49 if (!playlist.Load(url))
50 return false;
51 bool result = GetDirectory(playlist, items);
52 if (result)
53 items.SetProperty("library.smartplaylist", true);
55 return result;
58 bool CSmartPlaylistDirectory::GetDirectory(const PLAYLIST::CSmartPlaylist& playlist,
59 CFileItemList& items,
60 const std::string& strBaseDir /* = "" */,
61 bool filter /* = false */)
63 bool success = false, success2 = false;
64 std::vector<std::string> virtualFolders;
66 SortDescription sorting;
67 if (playlist.GetLimit() > 0)
68 sorting.limitEnd = playlist.GetLimit();
69 sorting.sortBy = playlist.GetOrder();
70 sorting.sortOrder = playlist.GetOrderAscending() ? SortOrderAscending : SortOrderDescending;
71 sorting.sortAttributes = playlist.GetOrderAttributes();
72 if (CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool(CSettings::SETTING_FILELISTS_IGNORETHEWHENSORTING))
73 sorting.sortAttributes = (SortAttribute)(sorting.sortAttributes | SortAttributeIgnoreArticle);
74 if (playlist.IsMusicType() && CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool(
75 CSettings::SETTING_MUSICLIBRARY_USEARTISTSORTNAME))
76 sorting.sortAttributes =
77 static_cast<SortAttribute>(sorting.sortAttributes | SortAttributeUseArtistSortName);
78 items.SetSortIgnoreFolders((sorting.sortAttributes & SortAttributeIgnoreFolders) ==
79 SortAttributeIgnoreFolders);
81 std::string option = !filter ? "xsp" : "filter";
82 std::string group = playlist.GetGroup();
83 bool isGrouped = !group.empty() && !StringUtils::EqualsNoCase(group, "none") && !playlist.IsGroupMixed();
84 // Hint for playlist files like STRM
85 PLAYLIST::Id playlistTypeHint = PLAYLIST::Id::TYPE_NONE;
87 // get all virtual folders and add them to the item list
88 playlist.GetVirtualFolders(virtualFolders);
89 for (const std::string& virtualFolder : virtualFolders)
91 CFileItemPtr pItem = std::make_shared<CFileItem>(virtualFolder, true);
92 IFileDirectory *dir = CFileDirectoryFactory::Create(pItem->GetURL(), pItem.get());
94 if (dir != NULL)
96 pItem->SetSpecialSort(SortSpecialOnTop);
97 items.Add(pItem);
98 delete dir;
102 if (playlist.GetType() == "movies" ||
103 playlist.GetType() == "tvshows" ||
104 playlist.GetType() == "episodes")
106 playlistTypeHint = PLAYLIST::Id::TYPE_VIDEO;
107 CVideoDatabase db;
108 if (db.Open())
110 MediaType mediaType = CMediaTypes::FromString(playlist.GetType());
112 std::string baseDir = strBaseDir;
113 if (strBaseDir.empty())
115 if (mediaType == MediaTypeTvShow || mediaType == MediaTypeEpisode)
116 baseDir = "videodb://tvshows/";
117 else if (mediaType == MediaTypeMovie)
118 baseDir = "videodb://movies/";
119 else
120 return false;
122 if (!isGrouped)
123 baseDir += "titles";
124 else
125 baseDir += group;
126 URIUtils::AddSlashAtEnd(baseDir);
128 if (mediaType == MediaTypeEpisode)
129 baseDir += "-1/-1/";
132 CVideoDbUrl videoUrl;
133 if (!videoUrl.FromString(baseDir))
134 return false;
136 // store the smartplaylist as JSON in the URL as well
137 std::string xsp;
138 if (!playlist.IsEmpty(filter))
140 if (!playlist.SaveAsJson(xsp, !filter))
141 return false;
144 if (!xsp.empty())
145 videoUrl.AddOption(option, xsp);
146 else
147 videoUrl.RemoveOption(option);
149 CDatabase::Filter dbfilter;
150 success = db.GetItems(videoUrl.ToString(), items, dbfilter, sorting);
151 db.Close();
153 // if we retrieve a list of episodes and we didn't receive
154 // a pre-defined base path, we need to fix it
155 if (strBaseDir.empty() && mediaType == MediaTypeEpisode && !isGrouped)
156 videoUrl.AppendPath("-1/-1/");
157 items.SetProperty(PROPERTY_PATH_DB, videoUrl.ToString());
160 else if (playlist.IsMusicType() || playlist.GetType().empty())
162 playlistTypeHint = PLAYLIST::Id::TYPE_MUSIC;
163 CMusicDatabase db;
164 if (db.Open())
166 PLAYLIST::CSmartPlaylist plist(playlist);
167 if (playlist.GetType() == "mixed" || playlist.GetType().empty())
168 plist.SetType("songs");
170 MediaType mediaType = CMediaTypes::FromString(plist.GetType());
172 std::string baseDir = strBaseDir;
173 if (strBaseDir.empty())
175 baseDir = "musicdb://";
176 if (!isGrouped)
178 if (mediaType == MediaTypeArtist)
179 baseDir += "artists";
180 else if (mediaType == MediaTypeAlbum)
181 baseDir += "albums";
182 else if (mediaType == MediaTypeSong)
183 baseDir += "songs";
184 else
185 return false;
187 else
188 baseDir += group;
190 URIUtils::AddSlashAtEnd(baseDir);
193 CMusicDbUrl musicUrl;
194 if (!musicUrl.FromString(baseDir))
195 return false;
197 // store the smartplaylist as JSON in the URL as well
198 std::string xsp;
199 if (!plist.IsEmpty(filter))
201 if (!plist.SaveAsJson(xsp, !filter))
202 return false;
205 if (!xsp.empty())
206 musicUrl.AddOption(option, xsp);
207 else
208 musicUrl.RemoveOption(option);
210 CDatabase::Filter dbfilter;
211 success = db.GetItems(musicUrl.ToString(), items, dbfilter, sorting);
212 db.Close();
214 items.SetProperty(PROPERTY_PATH_DB, musicUrl.ToString());
218 if (playlist.GetType() == "musicvideos" || playlist.GetType() == "mixed")
220 playlistTypeHint = PLAYLIST::Id::TYPE_VIDEO;
221 CVideoDatabase db;
222 if (db.Open())
224 PLAYLIST::CSmartPlaylist mvidPlaylist(playlist);
225 if (playlist.GetType() == "mixed")
226 mvidPlaylist.SetType("musicvideos");
228 std::string baseDir = strBaseDir;
229 if (baseDir.empty())
231 baseDir = "videodb://musicvideos/";
233 if (!isGrouped)
234 baseDir += "titles";
235 else
236 baseDir += group;
237 URIUtils::AddSlashAtEnd(baseDir);
240 CVideoDbUrl videoUrl;
241 if (!videoUrl.FromString(baseDir))
242 return false;
244 // adjust the group in case we're retrieving a grouped playlist
245 // based on artists. This is needed because the video library
246 // is using the actorslink table for artists.
247 if (isGrouped && group == "artists")
249 group = "actors";
250 mvidPlaylist.SetGroup(group);
253 // store the smartplaylist as JSON in the URL as well
254 std::string xsp;
255 if (!mvidPlaylist.IsEmpty(filter))
257 if (!mvidPlaylist.SaveAsJson(xsp, !filter))
258 return false;
261 if (!xsp.empty())
262 videoUrl.AddOption(option, xsp);
263 else
264 videoUrl.RemoveOption(option);
266 CFileItemList items2;
267 CDatabase::Filter dbfilter;
268 success2 = db.GetItems(videoUrl.ToString(), items2, dbfilter, sorting);
270 db.Close();
271 if (items.Size() <= 0)
272 items.SetPath(videoUrl.ToString());
274 items.Append(items2);
275 if (items2.Size())
277 if (items.Size() > items2.Size())
278 items.SetContent("mixed");
279 else
280 items.SetContent("musicvideos");
282 items.SetProperty(PROPERTY_PATH_DB, videoUrl.ToString());
286 items.SetLabel(playlist.GetName());
287 if (isGrouped)
288 items.SetContent(group);
289 else
290 items.SetContent(playlist.GetType());
292 items.SetProperty(PROPERTY_SORT_ORDER, (int)playlist.GetOrder());
293 items.SetProperty(PROPERTY_SORT_ASCENDING, playlist.GetOrderDirection() == SortOrderAscending);
294 if (!group.empty())
296 items.SetProperty(PROPERTY_GROUP_BY, group);
297 items.SetProperty(PROPERTY_GROUP_MIXED, playlist.IsGroupMixed());
300 // sort grouped list by label unless random was specified for musicvideo artists
301 if (items.Size() > 1 && !group.empty())
303 if (playlist.GetOrder() == SortByRandom && group == "actors" &&
304 playlist.GetType() == "musicvideos")
305 items.Sort(SortByRandom, SortOrderAscending,
306 CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool(
307 CSettings::SETTING_FILELISTS_IGNORETHEWHENSORTING)
308 ? SortAttributeIgnoreArticle
309 : SortAttributeNone);
310 else
311 items.Sort(SortByLabel, SortOrderAscending,
312 CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool(
313 CSettings::SETTING_FILELISTS_IGNORETHEWHENSORTING)
314 ? SortAttributeIgnoreArticle
315 : SortAttributeNone);
318 // go through and set the playlist order
319 for (int i = 0; i < items.Size(); i++)
321 CFileItemPtr item = items[i];
322 item->m_iprogramCount = i; // hack for playlist order
323 item->SetProperty("playlist_type_hint", static_cast<int>(playlistTypeHint));
326 if (playlist.GetType() == "mixed")
327 return success || success2;
328 else if (playlist.GetType() == "musicvideos")
329 return success2;
330 else
331 return success;
334 bool CSmartPlaylistDirectory::ContainsFiles(const CURL& url)
336 // smart playlists always have files??
337 return true;
340 std::string CSmartPlaylistDirectory::GetPlaylistByName(const std::string& name, const std::string& playlistType)
342 CFileItemList list;
343 bool filesExist = false;
344 if (PLAYLIST::CSmartPlaylist::IsMusicType(playlistType))
345 filesExist = CDirectory::GetDirectory("special://musicplaylists/", list, ".xsp", DIR_FLAG_DEFAULTS);
346 else // all others are video
347 filesExist = CDirectory::GetDirectory("special://videoplaylists/", list, ".xsp", DIR_FLAG_DEFAULTS);
348 if (filesExist)
350 for (int i = 0; i < list.Size(); i++)
352 CFileItemPtr item = list[i];
353 PLAYLIST::CSmartPlaylist playlist;
354 if (playlist.OpenAndReadName(item->GetURL()))
356 if (StringUtils::EqualsNoCase(playlist.GetName(), name))
357 return item->GetPath();
360 for (int i = 0; i < list.Size(); i++)
361 { // check based on filename
362 CFileItemPtr item = list[i];
363 if (URIUtils::GetFileName(item->GetPath()) == name)
364 { // found :)
365 return item->GetPath();
369 return "";
372 bool CSmartPlaylistDirectory::Remove(const CURL& url)
374 return XFILE::CFile::Delete(url);