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 "ServiceBroker.h"
13 #include "filesystem/Directory.h"
14 #include "filesystem/File.h"
15 #include "filesystem/FileDirectoryFactory.h"
16 #include "music/MusicDatabase.h"
17 #include "music/MusicDbUrl.h"
18 #include "playlists/PlayListTypes.h"
19 #include "playlists/SmartPlayList.h"
20 #include "settings/Settings.h"
21 #include "settings/SettingsComponent.h"
22 #include "utils/SortUtils.h"
23 #include "utils/StringUtils.h"
24 #include "utils/URIUtils.h"
25 #include "video/VideoDatabase.h"
26 #include "video/VideoDbUrl.h"
30 #define PROPERTY_PATH_DB "path.db"
31 #define PROPERTY_SORT_ORDER "sort.order"
32 #define PROPERTY_SORT_ASCENDING "sort.ascending"
33 #define PROPERTY_GROUP_BY "group.by"
34 #define PROPERTY_GROUP_MIXED "group.mixed"
38 CSmartPlaylistDirectory::CSmartPlaylistDirectory() = default;
40 CSmartPlaylistDirectory::~CSmartPlaylistDirectory() = default;
42 bool CSmartPlaylistDirectory::GetDirectory(const CURL
& url
, CFileItemList
& items
)
44 // Load in the SmartPlaylist and get the WHERE query
45 CSmartPlaylist playlist
;
46 if (!playlist
.Load(url
))
48 bool result
= GetDirectory(playlist
, items
);
50 items
.SetProperty("library.smartplaylist", true);
55 bool CSmartPlaylistDirectory::GetDirectory(const CSmartPlaylist
&playlist
, CFileItemList
& items
, const std::string
&strBaseDir
/* = "" */, bool filter
/* = false */)
57 bool success
= false, success2
= false;
58 std::vector
<std::string
> virtualFolders
;
60 SortDescription sorting
;
61 if (playlist
.GetLimit() > 0)
62 sorting
.limitEnd
= playlist
.GetLimit();
63 sorting
.sortBy
= playlist
.GetOrder();
64 sorting
.sortOrder
= playlist
.GetOrderAscending() ? SortOrderAscending
: SortOrderDescending
;
65 sorting
.sortAttributes
= playlist
.GetOrderAttributes();
66 if (CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool(CSettings::SETTING_FILELISTS_IGNORETHEWHENSORTING
))
67 sorting
.sortAttributes
= (SortAttribute
)(sorting
.sortAttributes
| SortAttributeIgnoreArticle
);
68 if (playlist
.IsMusicType() && CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool(
69 CSettings::SETTING_MUSICLIBRARY_USEARTISTSORTNAME
))
70 sorting
.sortAttributes
=
71 static_cast<SortAttribute
>(sorting
.sortAttributes
| SortAttributeUseArtistSortName
);
72 items
.SetSortIgnoreFolders((sorting
.sortAttributes
& SortAttributeIgnoreFolders
) ==
73 SortAttributeIgnoreFolders
);
75 std::string option
= !filter
? "xsp" : "filter";
76 std::string group
= playlist
.GetGroup();
77 bool isGrouped
= !group
.empty() && !StringUtils::EqualsNoCase(group
, "none") && !playlist
.IsGroupMixed();
78 // Hint for playlist files like STRM
79 PLAYLIST::Id playlistTypeHint
= PLAYLIST::TYPE_NONE
;
81 // get all virtual folders and add them to the item list
82 playlist
.GetVirtualFolders(virtualFolders
);
83 for (const std::string
& virtualFolder
: virtualFolders
)
85 CFileItemPtr pItem
= CFileItemPtr(new CFileItem(virtualFolder
, true));
86 IFileDirectory
*dir
= CFileDirectoryFactory::Create(pItem
->GetURL(), pItem
.get());
90 pItem
->SetSpecialSort(SortSpecialOnTop
);
96 if (playlist
.GetType() == "movies" ||
97 playlist
.GetType() == "tvshows" ||
98 playlist
.GetType() == "episodes")
100 playlistTypeHint
= PLAYLIST::TYPE_VIDEO
;
104 MediaType mediaType
= CMediaTypes::FromString(playlist
.GetType());
106 std::string baseDir
= strBaseDir
;
107 if (strBaseDir
.empty())
109 if (mediaType
== MediaTypeTvShow
|| mediaType
== MediaTypeEpisode
)
110 baseDir
= "videodb://tvshows/";
111 else if (mediaType
== MediaTypeMovie
)
112 baseDir
= "videodb://movies/";
120 URIUtils::AddSlashAtEnd(baseDir
);
122 if (mediaType
== MediaTypeEpisode
)
126 CVideoDbUrl videoUrl
;
127 if (!videoUrl
.FromString(baseDir
))
130 // store the smartplaylist as JSON in the URL as well
132 if (!playlist
.IsEmpty(filter
))
134 if (!playlist
.SaveAsJson(xsp
, !filter
))
139 videoUrl
.AddOption(option
, xsp
);
141 videoUrl
.RemoveOption(option
);
143 CDatabase::Filter dbfilter
;
144 success
= db
.GetItems(videoUrl
.ToString(), items
, dbfilter
, sorting
);
147 // if we retrieve a list of episodes and we didn't receive
148 // a pre-defined base path, we need to fix it
149 if (strBaseDir
.empty() && mediaType
== MediaTypeEpisode
&& !isGrouped
)
150 videoUrl
.AppendPath("-1/-1/");
151 items
.SetProperty(PROPERTY_PATH_DB
, videoUrl
.ToString());
154 else if (playlist
.IsMusicType() || playlist
.GetType().empty())
156 playlistTypeHint
= PLAYLIST::TYPE_MUSIC
;
160 CSmartPlaylist
plist(playlist
);
161 if (playlist
.GetType() == "mixed" || playlist
.GetType().empty())
162 plist
.SetType("songs");
164 MediaType mediaType
= CMediaTypes::FromString(plist
.GetType());
166 std::string baseDir
= strBaseDir
;
167 if (strBaseDir
.empty())
169 baseDir
= "musicdb://";
172 if (mediaType
== MediaTypeArtist
)
173 baseDir
+= "artists";
174 else if (mediaType
== MediaTypeAlbum
)
176 else if (mediaType
== MediaTypeSong
)
184 URIUtils::AddSlashAtEnd(baseDir
);
187 CMusicDbUrl musicUrl
;
188 if (!musicUrl
.FromString(baseDir
))
191 // store the smartplaylist as JSON in the URL as well
193 if (!plist
.IsEmpty(filter
))
195 if (!plist
.SaveAsJson(xsp
, !filter
))
200 musicUrl
.AddOption(option
, xsp
);
202 musicUrl
.RemoveOption(option
);
204 CDatabase::Filter dbfilter
;
205 success
= db
.GetItems(musicUrl
.ToString(), items
, dbfilter
, sorting
);
208 items
.SetProperty(PROPERTY_PATH_DB
, musicUrl
.ToString());
212 if (playlist
.GetType() == "musicvideos" || playlist
.GetType() == "mixed")
214 playlistTypeHint
= PLAYLIST::TYPE_VIDEO
;
218 CSmartPlaylist
mvidPlaylist(playlist
);
219 if (playlist
.GetType() == "mixed")
220 mvidPlaylist
.SetType("musicvideos");
222 std::string baseDir
= strBaseDir
;
225 baseDir
= "videodb://musicvideos/";
231 URIUtils::AddSlashAtEnd(baseDir
);
234 CVideoDbUrl videoUrl
;
235 if (!videoUrl
.FromString(baseDir
))
238 // adjust the group in case we're retrieving a grouped playlist
239 // based on artists. This is needed because the video library
240 // is using the actorslink table for artists.
241 if (isGrouped
&& group
== "artists")
244 mvidPlaylist
.SetGroup(group
);
247 // store the smartplaylist as JSON in the URL as well
249 if (!mvidPlaylist
.IsEmpty(filter
))
251 if (!mvidPlaylist
.SaveAsJson(xsp
, !filter
))
256 videoUrl
.AddOption(option
, xsp
);
258 videoUrl
.RemoveOption(option
);
260 CFileItemList items2
;
261 CDatabase::Filter dbfilter
;
262 success2
= db
.GetItems(videoUrl
.ToString(), items2
, dbfilter
, sorting
);
265 if (items
.Size() <= 0)
266 items
.SetPath(videoUrl
.ToString());
268 items
.Append(items2
);
271 if (items
.Size() > items2
.Size())
272 items
.SetContent("mixed");
274 items
.SetContent("musicvideos");
276 items
.SetProperty(PROPERTY_PATH_DB
, videoUrl
.ToString());
280 items
.SetLabel(playlist
.GetName());
282 items
.SetContent(group
);
284 items
.SetContent(playlist
.GetType());
286 items
.SetProperty(PROPERTY_SORT_ORDER
, (int)playlist
.GetOrder());
287 items
.SetProperty(PROPERTY_SORT_ASCENDING
, playlist
.GetOrderDirection() == SortOrderAscending
);
290 items
.SetProperty(PROPERTY_GROUP_BY
, group
);
291 items
.SetProperty(PROPERTY_GROUP_MIXED
, playlist
.IsGroupMixed());
294 // sort grouped list by label
295 if (items
.Size() > 1 && !group
.empty())
296 items
.Sort(SortByLabel
, SortOrderAscending
, CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool(CSettings::SETTING_FILELISTS_IGNORETHEWHENSORTING
) ? SortAttributeIgnoreArticle
: SortAttributeNone
);
298 // go through and set the playlist order
299 for (int i
= 0; i
< items
.Size(); i
++)
301 CFileItemPtr item
= items
[i
];
302 item
->m_iprogramCount
= i
; // hack for playlist order
303 item
->SetProperty("playlist_type_hint", playlistTypeHint
);
306 if (playlist
.GetType() == "mixed")
307 return success
|| success2
;
308 else if (playlist
.GetType() == "musicvideos")
314 bool CSmartPlaylistDirectory::ContainsFiles(const CURL
& url
)
316 // smart playlists always have files??
320 std::string
CSmartPlaylistDirectory::GetPlaylistByName(const std::string
& name
, const std::string
& playlistType
)
323 bool filesExist
= false;
324 if (CSmartPlaylist::IsMusicType(playlistType
))
325 filesExist
= CDirectory::GetDirectory("special://musicplaylists/", list
, ".xsp", DIR_FLAG_DEFAULTS
);
326 else // all others are video
327 filesExist
= CDirectory::GetDirectory("special://videoplaylists/", list
, ".xsp", DIR_FLAG_DEFAULTS
);
330 for (int i
= 0; i
< list
.Size(); i
++)
332 CFileItemPtr item
= list
[i
];
333 CSmartPlaylist playlist
;
334 if (playlist
.OpenAndReadName(item
->GetURL()))
336 if (StringUtils::EqualsNoCase(playlist
.GetName(), name
))
337 return item
->GetPath();
340 for (int i
= 0; i
< list
.Size(); i
++)
341 { // check based on filename
342 CFileItemPtr item
= list
[i
];
343 if (URIUtils::GetFileName(item
->GetPath()) == name
)
345 return item
->GetPath();
352 bool CSmartPlaylistDirectory::Remove(const CURL
& url
)
354 return XFILE::CFile::Delete(url
);