1 /* 2 * Copyright (C) 2005-2018 Team Kodi 3 * This file is part of Kodi - https://kodi.tv 4 * 5 * SPDX-License-Identifier: GPL-2.0-or-later 6 * See LICENSES/README.md for more information. 7 */ 8 9 #pragma once 10 11 #include "InfoScanner.h" 12 #include "MusicAlbumInfo.h" 13 #include "MusicInfoScraper.h" 14 #include "music/MusicDatabase.h" 15 #include "threads/IRunnable.h" 16 #include "threads/Thread.h" 17 #include "utils/ScraperUrl.h" 18 19 class CAlbum; 20 class CArtist; 21 class CGUIDialogProgressBarHandle; 22 23 namespace MUSIC_INFO 24 { 25 26 class CMusicInfoScanner : public IRunnable, public CInfoScanner 27 { 28 public: 29 /*! \brief Flags for controlling the scanning process 30 */ 31 enum SCAN_FLAGS { SCAN_NORMAL = 0, 32 SCAN_ONLINE = 1 << 0, 33 SCAN_BACKGROUND = 1 << 1, 34 SCAN_RESCAN = 1 << 2, 35 SCAN_ARTISTS = 1 << 3, 36 SCAN_ALBUMS = 1 << 4 }; 37 38 CMusicInfoScanner(); 39 ~CMusicInfoScanner() override; 40 41 void Start(const std::string& strDirectory, int flags); 42 void FetchAlbumInfo(const std::string& strDirectory, bool refresh = false); 43 void FetchArtistInfo(const std::string& strDirectory, bool refresh = false); 44 void Stop(); 45 46 /*! \brief Categorize FileItems into Albums, Songs, and Artists 47 This takes a list of FileItems and turns it into a tree of Albums, 48 Artists, and Songs. 49 Albums are defined uniquely by the album name and album artist. 50 51 \param songs [in/out] list of songs to categorise - albumartist field may be altered. 52 \param albums [out] albums found within these songs. 53 */ 54 static void FileItemsToAlbums(CFileItemList& items, VECALBUMS& albums, MAPSONGS* songsMap = NULL); 55 56 /*! \brief Scrape additional album information and update the music database with it. 57 Given an album, search for it using the given scraper. 58 If info is found, update the database and artwork with the new 59 information. 60 \param album [in/out] the album to update 61 \param scraper [in] the album scraper to use 62 \param bAllowSelection [in] should we allow the user to manually override the info with a GUI if the album is not found? 63 \param pDialog [in] a progress dialog which this and downstream functions can update with status, if required 64 */ 65 INFO_RET UpdateAlbumInfo(CAlbum& album, const ADDON::ScraperPtr& scraper, bool bAllowSelection, CGUIDialogProgress* pDialog = NULL); 66 67 /*! \brief Scrape additional artist information and update the music database with it. 68 Given an artist, search for it using the given scraper. 69 If info is found, update the database and artwork with the new 70 information. 71 \param artist [in/out] the artist to update 72 \param scraper [in] the artist scraper to use 73 \param bAllowSelection [in] should we allow the user to manually override the info with a GUI if the album is not found? 74 \param pDialog [in] a progress dialog which this and downstream functions can update with status, if required 75 */ 76 INFO_RET UpdateArtistInfo(CArtist& artist, const ADDON::ScraperPtr& scraper, bool bAllowSelection, CGUIDialogProgress* pDialog = NULL); 77 78 protected: 79 virtual void Process(); 80 bool DoScan(const std::string& strDirectory) override; 81 82 83 /*! \brief Find art for albums 84 Based on the albums in the folder, finds whether we have unique album art 85 and assigns to the album if we do. 86 87 In order of priority: 88 1. If there is a single album in the folder, then the folder art is assigned to the album. 89 2. We find the art for each song. A .tbn file takes priority over embedded art. 90 3. If we have a unique piece of art for all songs in the album, we assign that to the album 91 and remove that art from each song so that they inherit from the album. 92 4. If there is not a unique piece of art for each song, then no art is assigned 93 to the album. 94 95 \param albums [in/out] list of albums to categorise - art field may be altered. 96 \param path [in] path containing albums. 97 */ 98 static void FindArtForAlbums(VECALBUMS &albums, const std::string &path); 99 100 /*! \brief Scrape additional album information and update the database. 101 Search for the given album using the given scraper. 102 If info is found, update the database and artwork with the new 103 information. 104 \param album [in/out] the album to update 105 \param scraper [in] the album scraper to use 106 \param bAllowSelection [in] should we allow the user to manually override the info with a GUI if the album is not found? 107 \param pDialog [in] a progress dialog which this and downstream functions can update with status, if required 108 */ 109 INFO_RET UpdateDatabaseAlbumInfo(CAlbum& album, const ADDON::ScraperPtr& scraper, bool bAllowSelection, CGUIDialogProgress* pDialog = NULL); 110 111 /*! \brief Scrape additional artist information and update the database. 112 Search for the given artist using the given scraper. 113 If info is found, update the database and artwork with the new 114 information. 115 \param artist [in/out] the artist to update 116 \param scraper [in] the artist scraper to use 117 \param bAllowSelection [in] should we allow the user to manually override the info with a GUI if the album is not found? 118 \param pDialog [in] a progress dialog which this and downstream functions can update with status, if required 119 */ 120 INFO_RET UpdateDatabaseArtistInfo(CArtist& artist, const ADDON::ScraperPtr& scraper, bool bAllowSelection, CGUIDialogProgress* pDialog = NULL); 121 122 /*! \brief Using the scrapers download metadata for an album 123 Given a CAlbum style struct containing some data about an album, query 124 the scrapers to try and get more information about the album. The responsibility 125 is with the caller to do something with that information. It will be passed back 126 in a MusicInfo struct, which you can save, display to the user or throw away. 127 \param album [in] a partially or fully filled out album structure containing the search query 128 \param scraper [in] the scraper to query, usually the default or the relevant scraper for the musicdb path 129 \param albumInfo [in/out] a CMusicAlbumInfo struct which will be populated with the output of the scraper 130 \param bUseScrapedMBID [in] should scraper use any previously scraped mbid to identify the artist, or use artist name? 131 \param pDialog [in] a progress dialog which this and downstream functions can update with status, if required 132 */ 133 INFO_RET DownloadAlbumInfo(const CAlbum& album, const ADDON::ScraperPtr& scraper, MUSIC_GRABBER::CMusicAlbumInfo& albumInfo, bool bUseScrapedMBID, CGUIDialogProgress* pDialog = NULL); 134 135 /*! \brief Using the scrapers download metadata for an artist 136 Given a CAlbum style struct containing some data about an artist, query 137 the scrapers to try and get more information about the artist. The responsibility 138 is with the caller to do something with that information. It will be passed back 139 in a MusicInfo struct, which you can save, display to the user or throw away. 140 \param artist [in] a partially or fully filled out artist structure containing the search query 141 \param scraper [in] the scraper to query, usually the default or the relevant scraper for the musicdb path 142 \param artistInfo [in/out] a CMusicAlbumInfo struct which will be populated with the output of the scraper 143 \param bUseScrapedMBID [in] should scraper use any previously scraped mbid to identify the album, or use album and artist name? 144 \param pDialog [in] a progress dialog which this and downstream functions can update with status, if required 145 */ 146 INFO_RET DownloadArtistInfo(const CArtist& artist, const ADDON::ScraperPtr& scraper, MUSIC_GRABBER::CMusicArtistInfo& artistInfo, bool bUseScrapedMBID, CGUIDialogProgress* pDialog = NULL); 147 148 /*! \brief Get the types of art for an artist or album that are to be 149 automatically fetched from local files during scanning 150 \param mediaType [in] artist or album 151 \param iArtLevel [in] art level 152 \return vector of art types that are to be fetched during scanning 153 */ 154 std::vector<CVariant> GetArtWhitelist(const MediaType& mediaType, int iArtLevel); 155 156 /*! \brief Add extra local artwork for albums and artists 157 This common utility scans the given folder for local (non-thumb) art. 158 The art types checked are determined by whitelist and usealllocalart settings. 159 \param art [in/out] map of art type and file location (URL or path) pairs 160 \param mediaType [in] artist or album 161 \param mediaName [in] artist or album name that may be stripped from image file names 162 \param artfolder [in] path of folder containing local image files 163 \return true when art is added 164 */ 165 bool AddLocalArtwork(std::map<std::string, std::string>& art, 166 const std::string& mediaType, 167 const std::string& mediaName, 168 const std::string& artfolder, 169 int discnum = 0); 170 171 /*! \brief Add extra remote artwork for albums and artists 172 This common utility fills the gaps in artwork using the first available art of each type from the 173 possibile art URL results of previous scraping. 174 The art types applied are determined by whitelist and usealllocalart settings. 175 \param art [in/out] map of art type and file location (URL or path) pairs 176 \param mediaType [in] artist or album 177 \param thumbURL [in] URLs for potential remote artwork (provided by scrapers) 178 \return true when art is added 179 */ 180 bool AddRemoteArtwork(std::map<std::string, std::string>& art, 181 const std::string& mediaType, 182 const CScraperUrl& thumbURL); 183 184 /*! \brief Add art for an artist 185 This scans the given folder for local art and/or applies the first available art of each type 186 from the possibile art URLs previously scraped. Art is added to any already stored by previous 187 scanning etc.The art types processed are determined by whitelist and other art settings. 188 When usealllocalart is enabled then all local image files are applied as art (providing name is 189 valid for an art type), and then the URL list of remote art is checked adding the first available 190 image of each art type not yet in the art map. 191 Art found is saved in the album structure and the music database. The images found are cached. 192 \param artist [in/out] an artist, the art is set 193 \param artfolder [in] path of the location to search for local art files 194 \return true when art is added 195 */ 196 bool AddArtistArtwork(CArtist& artist, const std::string& artfolder); 197 198 /*! \brief Add art for an album 199 This scans the album folder, and any disc set subfolders, for local art and/or applies the first 200 available art of each type from the possibile art URLs previously scraped. Only those subfolders 201 beneath the album folder containing music files tagged with same unique disc number are scanned. 202 Art is added to any already stored by previous scanning, only "thumb" is optionally replaced. 203 The art types processed are determined by whitelist and other art settings. When usealllocalart is 204 enabled then all local image files are applied as art (providing name is valid for an art type), 205 and then the URL list of remote art is checked adding the first available image of each art type 206 not yet in the art map. 207 Art found is saved in the album structure and the music database. The images found are cached. 208 \param artist [in/out] an album, the art is set 209 \return true when art is added 210 */ 211 bool AddAlbumArtwork(CAlbum& album); 212 213 /*! \brief Scan in the ID3/Ogg/FLAC tags for a bunch of FileItems 214 Given a list of FileItems, scan in the tags for those FileItems 215 and populate a new FileItemList with the files that were successfully scanned. 216 Add album to library, populate a list of album ids added for possible scraping later. 217 Any files which couldn't be scanned (no/bad tags) are discarded in the process. 218 \param items [in] list of FileItems to scan 219 \param scannedItems [in] list to populate with the scannedItems 220 */ 221 int RetrieveMusicInfo(const std::string& strDirectory, CFileItemList& items); 222 223 void RetrieveLocalArt(); 224 void ScrapeInfoAddedAlbums(); 225 226 /*! \brief Scan in the ID3/Ogg/FLAC tags for a bunch of FileItems 227 Given a list of FileItems, scan in the tags for those FileItems 228 and populate a new FileItemList with the files that were successfully scanned. 229 Any files which couldn't be scanned (no/bad tags) are discarded in the process. 230 \param items [in] list of FileItems to scan 231 \param scannedItems [in] list to populate with the scannedItems 232 */ 233 INFO_RET ScanTags(const CFileItemList& items, CFileItemList& scannedItems); 234 int GetPathHash(const CFileItemList &items, std::string &hash); 235 236 void Run() override; 237 int CountFiles(const CFileItemList& items, bool recursive); 238 int CountFilesRecursively(const std::string& strPath); 239 240 /*! \brief Resolve a MusicBrainzID to a URL 241 If we have a MusicBrainz ID for an artist or album, 242 resolve it to an MB URL and set up the scrapers accordingly. 243 244 \param preferredScraper [in] A ScraperPtr to the preferred album/artist scraper. 245 \param musicBrainzURL [out] will be populated with the MB URL for the artist/album. 246 */ 247 bool ResolveMusicBrainz(const std::string &strMusicBrainzID, const ADDON::ScraperPtr &preferredScraper, CScraperUrl &musicBrainzURL); 248 249 void ScannerWait(unsigned int milliseconds); 250 251 int m_currentItem; 252 int m_itemCount; 253 bool m_bStop; 254 bool m_needsCleanup = false; 255 int m_scanType = 0; // 0 - load from files, 1 - albums, 2 - artists 256 int m_idSourcePath; 257 CMusicDatabase m_musicDatabase; 258 259 std::set<int> m_albumsAdded; 260 261 std::set<std::string> m_seenPaths; 262 int m_flags; 263 CThread m_fileCountReader; 264 }; 265 } 266