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.
9 #include "SmartPlaylistDirectory.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"
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"
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
))
51 bool result
= GetDirectory(playlist
, items
);
53 items
.SetProperty("library.smartplaylist", true);
58 bool CSmartPlaylistDirectory::GetDirectory(const PLAYLIST::CSmartPlaylist
& playlist
,
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());
96 pItem
->SetSpecialSort(SortSpecialOnTop
);
102 if (playlist
.GetType() == "movies" ||
103 playlist
.GetType() == "tvshows" ||
104 playlist
.GetType() == "episodes")
106 playlistTypeHint
= PLAYLIST::Id::TYPE_VIDEO
;
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/";
126 URIUtils::AddSlashAtEnd(baseDir
);
128 if (mediaType
== MediaTypeEpisode
)
132 CVideoDbUrl videoUrl
;
133 if (!videoUrl
.FromString(baseDir
))
136 // store the smartplaylist as JSON in the URL as well
138 if (!playlist
.IsEmpty(filter
))
140 if (!playlist
.SaveAsJson(xsp
, !filter
))
145 videoUrl
.AddOption(option
, xsp
);
147 videoUrl
.RemoveOption(option
);
149 CDatabase::Filter dbfilter
;
150 success
= db
.GetItems(videoUrl
.ToString(), items
, dbfilter
, sorting
);
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
;
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://";
178 if (mediaType
== MediaTypeArtist
)
179 baseDir
+= "artists";
180 else if (mediaType
== MediaTypeAlbum
)
182 else if (mediaType
== MediaTypeSong
)
190 URIUtils::AddSlashAtEnd(baseDir
);
193 CMusicDbUrl musicUrl
;
194 if (!musicUrl
.FromString(baseDir
))
197 // store the smartplaylist as JSON in the URL as well
199 if (!plist
.IsEmpty(filter
))
201 if (!plist
.SaveAsJson(xsp
, !filter
))
206 musicUrl
.AddOption(option
, xsp
);
208 musicUrl
.RemoveOption(option
);
210 CDatabase::Filter dbfilter
;
211 success
= db
.GetItems(musicUrl
.ToString(), items
, dbfilter
, sorting
);
214 items
.SetProperty(PROPERTY_PATH_DB
, musicUrl
.ToString());
218 if (playlist
.GetType() == "musicvideos" || playlist
.GetType() == "mixed")
220 playlistTypeHint
= PLAYLIST::Id::TYPE_VIDEO
;
224 PLAYLIST::CSmartPlaylist
mvidPlaylist(playlist
);
225 if (playlist
.GetType() == "mixed")
226 mvidPlaylist
.SetType("musicvideos");
228 std::string baseDir
= strBaseDir
;
231 baseDir
= "videodb://musicvideos/";
237 URIUtils::AddSlashAtEnd(baseDir
);
240 CVideoDbUrl videoUrl
;
241 if (!videoUrl
.FromString(baseDir
))
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")
250 mvidPlaylist
.SetGroup(group
);
253 // store the smartplaylist as JSON in the URL as well
255 if (!mvidPlaylist
.IsEmpty(filter
))
257 if (!mvidPlaylist
.SaveAsJson(xsp
, !filter
))
262 videoUrl
.AddOption(option
, xsp
);
264 videoUrl
.RemoveOption(option
);
266 CFileItemList items2
;
267 CDatabase::Filter dbfilter
;
268 success2
= db
.GetItems(videoUrl
.ToString(), items2
, dbfilter
, sorting
);
271 if (items
.Size() <= 0)
272 items
.SetPath(videoUrl
.ToString());
274 items
.Append(items2
);
277 if (items
.Size() > items2
.Size())
278 items
.SetContent("mixed");
280 items
.SetContent("musicvideos");
282 items
.SetProperty(PROPERTY_PATH_DB
, videoUrl
.ToString());
286 items
.SetLabel(playlist
.GetName());
288 items
.SetContent(group
);
290 items
.SetContent(playlist
.GetType());
292 items
.SetProperty(PROPERTY_SORT_ORDER
, (int)playlist
.GetOrder());
293 items
.SetProperty(PROPERTY_SORT_ASCENDING
, playlist
.GetOrderDirection() == SortOrderAscending
);
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
);
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")
334 bool CSmartPlaylistDirectory::ContainsFiles(const CURL
& url
)
336 // smart playlists always have files??
340 std::string
CSmartPlaylistDirectory::GetPlaylistByName(const std::string
& name
, const std::string
& playlistType
)
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
);
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
)
365 return item
->GetPath();
372 bool CSmartPlaylistDirectory::Remove(const CURL
& url
)
374 return XFILE::CFile::Delete(url
);