[Windows] Fix driver version detection of AMD RDNA+ GPU on Windows 10
[xbmc.git] / xbmc / music / MusicInfoLoader.cpp
bloba6bff1a36ef46afd021da01ee102b494306b11fb
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 "MusicInfoLoader.h"
11 #include "Album.h"
12 #include "Artist.h"
13 #include "FileItem.h"
14 #include "FileItemList.h"
15 #include "MusicDatabase.h"
16 #include "MusicThumbLoader.h"
17 #include "ServiceBroker.h"
18 #include "filesystem/File.h"
19 #include "filesystem/MusicDatabaseDirectory/DirectoryNode.h"
20 #include "filesystem/MusicDatabaseDirectory/QueryParams.h"
21 #include "music/MusicFileItemClassify.h"
22 #include "music/tags/MusicInfoTag.h"
23 #include "music/tags/MusicInfoTagLoaderFactory.h"
24 #include "network/NetworkFileItemClassify.h"
25 #include "settings/Settings.h"
26 #include "settings/SettingsComponent.h"
27 #include "utils/Archive.h"
28 #include "utils/StringUtils.h"
29 #include "utils/URIUtils.h"
30 #include "utils/log.h"
32 using namespace KODI;
33 using namespace MUSIC_INFO;
34 using namespace XFILE;
36 // HACK until we make this threadable - specify 1 thread only for now
37 CMusicInfoLoader::CMusicInfoLoader() : CBackgroundInfoLoader()
39 m_mapFileItems = new CFileItemList;
41 m_thumbLoader = new CMusicThumbLoader();
44 CMusicInfoLoader::~CMusicInfoLoader()
46 StopThread();
47 delete m_mapFileItems;
48 delete m_thumbLoader;
51 void CMusicInfoLoader::OnLoaderStart()
53 // Load previously cached items from HD
54 if (!m_strCacheFileName.empty())
55 LoadCache(m_strCacheFileName, *m_mapFileItems);
56 else
58 m_mapFileItems->SetPath(m_pVecItems->GetPath());
59 m_mapFileItems->Load();
60 m_mapFileItems->SetFastLookup(true);
63 m_strPrevPath.clear();
65 m_databaseHits = m_tagReads = 0;
67 if (m_pProgressCallback)
68 m_pProgressCallback->SetProgressMax(m_pVecItems->GetFileCount());
70 m_musicDatabase.Open();
72 if (m_thumbLoader)
73 m_thumbLoader->OnLoaderStart();
76 bool CMusicInfoLoader::LoadAdditionalTagInfo(CFileItem* pItem)
78 if (!pItem || (pItem->m_bIsFolder && !MUSIC::IsAudio(*pItem)) || pItem->IsPlayList() ||
79 pItem->IsNFO() || NETWORK::IsInternetStream(*pItem))
80 return false;
82 if (pItem->GetProperty("hasfullmusictag") == "true")
83 return false; // already have the information
85 std::string path(pItem->GetPath());
86 // For songs in library set the (primary) song artist and album properties
87 // Use song Id (not path) as called for items from either library or file view,
88 // but could also be listitem with tag loaded by a script
89 if (pItem->HasMusicInfoTag() &&
90 pItem->GetMusicInfoTag()->GetType() == MediaTypeSong &&
91 pItem->GetMusicInfoTag()->GetDatabaseId() > 0)
93 CMusicDatabase database;
94 database.Open();
95 // May already have song artist ids as item property set when data read from
96 // db, but check property is valid array (scripts could set item properties
97 // incorrectly), otherwise fetch artist using song id.
98 CArtist artist;
99 bool artistfound = false;
100 if (pItem->HasProperty("artistid") && pItem->GetProperty("artistid").isArray())
102 CVariant::const_iterator_array varid = pItem->GetProperty("artistid").begin_array();
103 int idArtist = static_cast<int>(varid->asInteger());
104 artistfound = database.GetArtist(idArtist, artist, false);
106 else
107 artistfound = database.GetArtistFromSong(pItem->GetMusicInfoTag()->GetDatabaseId(), artist);
108 if (artistfound)
109 CMusicDatabase::SetPropertiesFromArtist(*pItem, artist);
111 // May already have album id, otherwise fetch album from song id
112 CAlbum album;
113 bool albumfound = false;
114 int idAlbum = pItem->GetMusicInfoTag()->GetAlbumId();
115 if (idAlbum > 0)
116 albumfound = database.GetAlbum(idAlbum, album, false);
117 else
118 albumfound = database.GetAlbumFromSong(pItem->GetMusicInfoTag()->GetDatabaseId(), album);
119 if (albumfound)
120 CMusicDatabase::SetPropertiesFromAlbum(*pItem, album);
122 path = pItem->GetMusicInfoTag()->GetURL();
125 CLog::Log(LOGDEBUG, "Loading additional tag info for file {}", path);
127 // we load up the actual tag for this file in order to
128 // fetch the lyrics and add it to the current music info tag
129 CFileItem tempItem(path, false);
130 std::unique_ptr<IMusicInfoTagLoader> pLoader (CMusicInfoTagLoaderFactory::CreateLoader(tempItem));
131 if (nullptr != pLoader)
133 CMusicInfoTag tag;
134 pLoader->Load(path, tag);
135 pItem->GetMusicInfoTag()->SetLyrics(tag.GetLyrics());
136 pItem->SetProperty("hasfullmusictag", "true");
137 return true;
139 return false;
142 bool CMusicInfoLoader::LoadItem(CFileItem* pItem)
144 bool result = LoadItemCached(pItem);
145 result |= LoadItemLookup(pItem);
147 return result;
150 bool CMusicInfoLoader::LoadItemCached(CFileItem* pItem)
152 if ((pItem->m_bIsFolder && !MUSIC::IsAudio(*pItem)) || pItem->IsPlayList() ||
153 pItem->IsSmartPlayList() ||
154 StringUtils::StartsWithNoCase(pItem->GetPath(), "newplaylist://") ||
155 StringUtils::StartsWithNoCase(pItem->GetPath(), "newsmartplaylist://") || pItem->IsNFO() ||
156 (NETWORK::IsInternetStream(*pItem) && !MUSIC::IsMusicDb(*pItem)))
157 return false;
159 // Get thumb for item
160 m_thumbLoader->LoadItem(pItem);
162 return true;
165 bool CMusicInfoLoader::LoadItemLookup(CFileItem* pItem)
167 if (m_pProgressCallback && !pItem->m_bIsFolder)
168 m_pProgressCallback->SetProgressAdvance();
170 if ((pItem->m_bIsFolder && !MUSIC::IsAudio(*pItem)) || //
171 pItem->IsPlayList() || pItem->IsSmartPlayList() || //
172 StringUtils::StartsWithNoCase(pItem->GetPath(), "newplaylist://") || //
173 StringUtils::StartsWithNoCase(pItem->GetPath(), "newsmartplaylist://") || //
174 pItem->IsNFO() || (NETWORK::IsInternetStream(*pItem) && !MUSIC::IsMusicDb(*pItem)))
175 return false;
177 if ((!pItem->HasMusicInfoTag() || !pItem->GetMusicInfoTag()->Loaded()) && MUSIC::IsAudio(*pItem))
179 // first check the cached item
180 CFileItemPtr mapItem = (*m_mapFileItems)[pItem->GetPath()];
181 if (mapItem && mapItem->m_dateTime==pItem->m_dateTime && mapItem->HasMusicInfoTag() && mapItem->GetMusicInfoTag()->Loaded())
182 { // Query map if we previously cached the file on HD
183 *pItem->GetMusicInfoTag() = *mapItem->GetMusicInfoTag();
184 if (mapItem->HasArt("thumb"))
185 pItem->SetArt("thumb", mapItem->GetArt("thumb"));
187 else
189 std::string strPath = URIUtils::GetDirectory(pItem->GetPath());
190 URIUtils::AddSlashAtEnd(strPath);
191 if (strPath!=m_strPrevPath)
193 // The item is from another directory as the last one,
194 // query the database for the new directory...
195 m_musicDatabase.GetSongsByPath(strPath, m_songsMap);
196 m_databaseHits++;
200 This only loads the item with the song from the database when it maps to a single song,
201 it can not load song data for items with cuesheets that expand to multiple songs.
202 For songs from embedded or separate cuesheets strFileName is not unique, so the song map for
203 the path will have the list of songs from that file. But items with cuesheets are expanded
204 (replacing each item with items for every track) elsewhere. When the item we are looking up
205 has a cuesheet document or is a music file with a cuesheet embedded in the tags, and it maps
206 to more than one song then we can not fill the tag data and thumb from the database.
208 MAPSONGS::iterator it = m_songsMap.find(pItem->GetPath()); // Find file in song map
209 if (it != m_songsMap.end() && it->second.size() == 1)
211 // Have we loaded this item from database before,
212 // and even if it has a cuesheet it has only one song
213 pItem->GetMusicInfoTag()->SetSong(it->second[0]);
214 if (!it->second[0].strThumb.empty())
215 pItem->SetArt("thumb", it->second[0].strThumb);
217 else if (MUSIC::IsMusicDb(*pItem))
218 { // a music db item that doesn't have tag loaded - grab details from the database
219 XFILE::MUSICDATABASEDIRECTORY::CQueryParams param;
220 XFILE::MUSICDATABASEDIRECTORY::CDirectoryNode::GetDatabaseInfo(pItem->GetPath(),param);
221 CSong song;
222 if (m_musicDatabase.GetSong(param.GetSongId(), song))
224 pItem->GetMusicInfoTag()->SetSong(song);
225 if (!song.strThumb.empty())
226 pItem->SetArt("thumb", song.strThumb);
229 else if (CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool(
230 CSettings::SETTING_MUSICFILES_USETAGS) ||
231 MUSIC::IsCDDA(*pItem))
232 { // Nothing found, load tag from file,
233 // always try to load cddb info
234 // get correct tag parser
235 std::unique_ptr<IMusicInfoTagLoader> pLoader (CMusicInfoTagLoaderFactory::CreateLoader(*pItem));
236 if (nullptr != pLoader)
237 // get tag
238 pLoader->Load(pItem->GetPath(), *pItem->GetMusicInfoTag());
239 m_tagReads++;
242 m_strPrevPath = strPath;
246 return true;
249 void CMusicInfoLoader::OnLoaderFinish()
251 // cleanup last loaded songs from database
252 m_songsMap.clear();
254 // cleanup cache loaded from HD
255 m_mapFileItems->Clear();
257 // Save loaded items to HD
258 if (!m_strCacheFileName.empty())
259 SaveCache(m_strCacheFileName, *m_pVecItems);
260 else if (!m_bStop && (m_databaseHits > 1 || m_tagReads > 0))
261 m_pVecItems->Save();
263 m_musicDatabase.Close();
265 if (m_thumbLoader)
266 m_thumbLoader->OnLoaderFinish();
269 void CMusicInfoLoader::UseCacheOnHD(const std::string& strFileName)
271 m_strCacheFileName = strFileName;
274 void CMusicInfoLoader::LoadCache(const std::string& strFileName, CFileItemList& items)
276 CFile file;
278 if (file.Open(strFileName))
280 CArchive ar(&file, CArchive::load);
281 int iSize = 0;
282 ar >> iSize;
283 for (int i = 0; i < iSize; i++)
285 CFileItemPtr pItem(new CFileItem());
286 ar >> *pItem;
287 items.Add(pItem);
289 ar.Close();
290 file.Close();
291 items.SetFastLookup(true);
295 void CMusicInfoLoader::SaveCache(const std::string& strFileName, CFileItemList& items)
297 int iSize = items.Size();
299 if (iSize <= 0)
300 return ;
302 CFile file;
304 if (file.OpenForWrite(strFileName))
306 CArchive ar(&file, CArchive::store);
307 ar << items.Size();
308 for (int i = 0; i < iSize; i++)
310 CFileItemPtr pItem = items[i];
311 ar << *pItem;
313 ar.Close();
314 file.Close();