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