2 * Copyright (C) 2005-2013 Team XBMC
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, see
17 * <http://www.gnu.org/licenses/>.
25 #include "dbwrappers/Database.h"
27 #include "addons/Scraper.h"
28 #include "utils/SortUtils.h"
29 #include "MusicDbUrl.h"
37 typedef std::vector<field_value> sql_record;
42 // return codes of Cleaning up the Database
43 // numbers are strings from strings.xml
45 #define ERROR_CANCEL 0
46 #define ERROR_DATABASE 315
47 #define ERROR_REORG_SONGS 319
48 #define ERROR_REORG_ARTIST 321
49 #define ERROR_REORG_GENRE 323
50 #define ERROR_REORG_PATH 325
51 #define ERROR_REORG_ALBUM 327
52 #define ERROR_WRITING_CHANGES 329
53 #define ERROR_COMPRESSING 332
55 #define NUM_SONGS_BEFORE_COMMIT 500
59 \brief A set of CStdString objects, used for CMusicDatabase
60 \sa ISETPATHES, CMusicDatabase
62 typedef std::set<CStdString> SETPATHES;
66 \brief The SETPATHES iterator
67 \sa SETPATHES, CMusicDatabase
69 typedef std::set<CStdString>::iterator ISETPATHES;
71 class CGUIDialogProgress;
76 \brief Class to store and read tag information
78 CMusicDatabase can be used to read and store
79 tag information for faster access. It is based on
80 sqlite (http://www.sqlite.org).
82 Here is the database layout:
83 \image html musicdatabase.png
85 \sa CAlbum, CSong, VECSONGS, CMapSong, VECARTISTS, VECALBUMS, VECGENRES
87 class CMusicDatabase : public CDatabase
89 friend class DatabaseUtils;
90 friend class TestDatabaseUtilsHelper;
94 virtual ~CMusicDatabase(void);
97 virtual bool CommitTransaction();
100 int Cleanup(CGUIDialogProgress *pDlgProgress=NULL);
101 bool LookupCDDBInfo(bool bRequery=false);
102 void DeleteCDDBInfo();
104 /////////////////////////////////////////////////
106 /////////////////////////////////////////////////
107 /*! \brief Add a song to the database
108 \param idAlbum [in] the database ID of the album for the song
109 \param strTitle [in] the title of the song (required to be non-empty)
110 \param strMusicBrainzTrackID [in] the MusicBrainz track ID of the song
111 \param strPathAndFileName [in] the path and filename to the song
112 \param strComment [in] the ids of the added songs
113 \param strThumb [in] the ids of the added songs
114 \param artistString [in] the assembled artist string, denormalized from CONCAT(strArtist||strJoinPhrase)
115 \param genres [in] a vector of genres to which this song belongs
116 \param iTrack [in] the track number and disc number of the song
117 \param iDuration [in] the duration of the song
118 \param iYear [in] the year of the song
119 \param iTimesPlayed [in] the number of times the song has been played
120 \param iStartOffset [in] the start offset of the song (when using a single audio file with a .cue)
121 \param iEndOffset [in] the end offset of the song (when using a single audio file with .cue)
122 \param dtLastPlayed [in] the time the song was last played
123 \param rating [in] a rating for the song
124 \param iKaraokeNumber [in] the karaoke id of the song
125 \return the id of the song
127 int AddSong(const int idAlbum,
128 const CStdString& strTitle,
129 const CStdString& strMusicBrainzTrackID,
130 const CStdString& strPathAndFileName,
131 const CStdString& strComment,
132 const CStdString& strThumb,
133 const std::string &artistString, const std::vector<std::string>& genres,
134 int iTrack, int iDuration, int iYear,
135 const int iTimesPlayed, int iStartOffset, int iEndOffset,
136 const CDateTime& dtLastPlayed,
137 char rating, int iKaraokeNumber);
138 bool GetSong(int idSong, CSong& song);
140 /*! \brief Update a song in the database.
142 NOTE: This function assumes that song.artist contains the artist string to be concatenated.
143 Most internal functions should instead use the long-form function as the artist string
144 should be constructed from the artist credits.
145 This function will eventually be demised.
147 \param idSong the database ID of the song to update
149 \return the id of the song.
151 int UpdateSong(int idSong, const CSong &song);
153 /*! \brief Update a song in the database
154 \param idSong [in] the database ID of the song to update
155 \param strTitle [in] the title of the song (required to be non-empty)
156 \param strMusicBrainzTrackID [in] the MusicBrainz track ID of the song
157 \param strPathAndFileName [in] the path and filename to the song
158 \param strComment [in] the ids of the added songs
159 \param strThumb [in] the ids of the added songs
160 \param artistString [in] the full artist string, denormalized from CONCAT(song_artist.strArtist || song_artist.strJoinPhrase)
161 \param genres [in] a vector of genres to which this song belongs
162 \param iTrack [in] the track number and disc number of the song
163 \param iDuration [in] the duration of the song
164 \param iYear [in] the year of the song
165 \param iTimesPlayed [in] the number of times the song has been played
166 \param iStartOffset [in] the start offset of the song (when using a single audio file with a .cue)
167 \param iEndOffset [in] the end offset of the song (when using a single audio file with .cue)
168 \param dtLastPlayed [in] the time the song was last played
169 \param rating [in] a rating for the song
170 \param iKaraokeNumber [in] the karaoke id of the song
171 \return the id of the song
173 int UpdateSong(int idSong,
174 const CStdString& strTitle, const CStdString& strMusicBrainzTrackID,
175 const CStdString& strPathAndFileName, const CStdString& strComment,
176 const CStdString& strThumb,
177 const std::string& artistString, const std::vector<std::string>& genres,
178 int iTrack, int iDuration, int iYear,
179 int iTimesPlayed, int iStartOffset, int iEndOffset,
180 const CDateTime& dtLastPlayed,
181 char rating, int iKaraokeNumber);
182 // bool DeleteSong(int idSong);
185 bool GetSongByFileName(const CStdString& strFileName, CSong& song, int startOffset = 0);
186 bool GetSongsByPath(const CStdString& strPath, MAPSONGS& songs, bool bAppendToMap = false);
187 bool Search(const CStdString& search, CFileItemList &items);
188 bool RemoveSongsFromPath(const CStdString &path, MAPSONGS& songs, bool exact=true);
189 bool SetSongRating(const CStdString &filePath, char rating);
190 int GetSongByArtistAndAlbumAndTitle(const CStdString& strArtist, const CStdString& strAlbum, const CStdString& strTitle);
192 /////////////////////////////////////////////////
194 /////////////////////////////////////////////////
195 bool AddAlbum(CAlbum& album);
196 /*! \brief Update an album and all its nested entities (artists, songs, infoSongs, etc)
197 \param album the album to update
198 \return true or false
200 bool UpdateAlbum(CAlbum& album);
202 /*! \brief Add an album and all its songs to the database
203 \param album the album to add
204 \param songIDs [out] the ids of the added songs
205 \return the id of the album
207 int AddAlbum(const CStdString& strAlbum, const CStdString& strMusicBrainzAlbumID,
208 const CStdString& strArtist, const CStdString& strGenre,
209 int year, bool bCompilation);
210 /*! \brief retrieve an album, optionally with all songs.
211 \param idAlbum the database id of the album.
212 \param album [out] the album to fill.
213 \param getSongs whether or not to retrieve songs, defaults to true.
214 \return true if the album is retrieved, false otherwise.
216 bool GetAlbum(int idAlbum, CAlbum& album, bool getSongs = true);
217 int UpdateAlbum(int idAlbum, const CAlbum &album);
218 int UpdateAlbum(int idAlbum,
219 const CStdString& strAlbum, const CStdString& strMusicBrainzAlbumID,
220 const CStdString& strArtist, const CStdString& strGenre,
221 const CStdString& strMoods, const CStdString& strStyles,
222 const CStdString& strThemes, const CStdString& strReview,
223 const CStdString& strImage, const CStdString& strLabel,
224 const CStdString& strType,
225 int iRating, int iYear, bool bCompilation);
226 bool DeleteAlbum(int idAlbum);
227 bool ClearAlbumLastScrapedTime(int idAlbum);
228 bool HasAlbumBeenScraped(int idAlbum);
229 int AddAlbumInfoSong(int idAlbum, const CSong& song);
231 /*! \brief Checks if the given path is inside a folder that has already been scanned into the library
232 \param path the path we want to check
234 bool InsideScannedPath(const CStdString& path);
237 int GetAlbumIdByPath(const CStdString& path);
238 bool GetAlbumFromSong(int idSong, CAlbum &album);
239 int GetAlbumByName(const CStdString& strAlbum, const CStdString& strArtist="");
240 int GetAlbumByName(const CStdString& strAlbum, const std::vector<std::string>& artist);
241 CStdString GetAlbumById(int id);
243 /////////////////////////////////////////////////
245 /////////////////////////////////////////////////
246 bool UpdateArtist(const CArtist& artist);
248 int AddArtist(const CStdString& strArtist, const CStdString& strMusicBrainzArtistID);
249 bool GetArtist(int idArtist, CArtist& artist, bool fetchAll = true);
250 int UpdateArtist(int idArtist,
251 const CStdString& strArtist, const CStdString& strMusicBrainzArtistID,
252 const CStdString& strBorn, const CStdString& strFormed,
253 const CStdString& strGenres, const CStdString& strMoods,
254 const CStdString& strStyles, const CStdString& strInstruments,
255 const CStdString& strBiography, const CStdString& strDied,
256 const CStdString& strDisbanded, const CStdString& strYearsActive,
257 const CStdString& strImage, const CStdString& strFanart);
258 bool DeleteArtist(int idArtist);
259 bool HasArtistBeenScraped(int idArtist);
260 bool ClearArtistLastScrapedTime(int idArtist);
261 int AddArtistDiscography(int idArtist, const CStdString& strAlbum, const CStdString& strYear);
262 bool DeleteArtistDiscography(int idArtist);
264 CStdString GetArtistById(int id);
265 int GetArtistByName(const CStdString& strArtist);
267 /////////////////////////////////////////////////
269 /////////////////////////////////////////////////
270 int AddPath(const CStdString& strPath);
272 bool GetPaths(std::set<std::string> &paths);
273 bool SetPathHash(const CStdString &path, const CStdString &hash);
274 bool GetPathHash(const CStdString &path, CStdString &hash);
275 bool GetAlbumPath(int idAlbum, CStdString &path);
276 bool GetArtistPath(int idArtist, CStdString &path);
278 /////////////////////////////////////////////////
280 /////////////////////////////////////////////////
281 int AddGenre(const CStdString& strGenre);
282 CStdString GetGenreById(int id);
283 int GetGenreByName(const CStdString& strGenre);
285 /////////////////////////////////////////////////
287 /////////////////////////////////////////////////
288 bool AddAlbumArtist(int idArtist, int idAlbum, std::string strArtist, std::string joinPhrase, bool featured, int iOrder);
289 bool GetAlbumsByArtist(int idArtist, bool includeFeatured, std::vector<int>& albums);
290 bool GetArtistsByAlbum(int idAlbum, bool includeFeatured, std::vector<int>& artists);
291 bool DeleteAlbumArtistsByAlbum(int idAlbum);
293 bool AddSongArtist(int idArtist, int idSong, std::string strArtist, std::string joinPhrase, bool featured, int iOrder);
294 bool GetSongsByArtist(int idArtist, bool includeFeatured, std::vector<int>& songs);
295 bool GetArtistsBySong(int idSong, bool includeFeatured, std::vector<int>& artists);
296 bool DeleteSongArtistsBySong(int idSong);
298 bool AddSongGenre(int idGenre, int idSong, int iOrder);
299 bool GetGenresBySong(int idSong, std::vector<int>& genres);
300 bool DeleteSongGenresBySong(int idSong);
302 bool AddAlbumGenre(int idGenre, int idAlbum, int iOrder);
303 bool GetGenresByAlbum(int idAlbum, std::vector<int>& genres);
304 bool DeleteAlbumGenresByAlbum(int idAlbum);
306 /////////////////////////////////////////////////
308 /////////////////////////////////////////////////
309 bool GetTop100(const CStdString& strBaseDir, CFileItemList& items);
310 bool GetTop100Albums(VECALBUMS& albums);
311 bool GetTop100AlbumSongs(const CStdString& strBaseDir, CFileItemList& item);
313 /////////////////////////////////////////////////
315 /////////////////////////////////////////////////
316 bool GetRecentlyAddedAlbums(VECALBUMS& albums, unsigned int limit=0);
317 bool GetRecentlyAddedAlbumSongs(const CStdString& strBaseDir, CFileItemList& item, unsigned int limit=0);
318 bool GetRecentlyPlayedAlbums(VECALBUMS& albums);
319 bool GetRecentlyPlayedAlbumSongs(const CStdString& strBaseDir, CFileItemList& item);
321 /////////////////////////////////////////////////
323 /////////////////////////////////////////////////
324 bool GetCompilationAlbums(const CStdString& strBaseDir, CFileItemList& items);
325 bool GetCompilationSongs(const CStdString& strBaseDir, CFileItemList& items);
326 int GetCompilationAlbumsCount();
327 bool GetVariousArtistsAlbums(const CStdString& strBaseDir, CFileItemList& items);
328 bool GetVariousArtistsAlbumsSongs(const CStdString& strBaseDir, CFileItemList& items);
329 int GetVariousArtistsAlbumsCount();
331 /*! \brief Increment the playcount of an item
332 Increments the playcount and updates the last played date
333 \param item CFileItem to increment the playcount for
335 void IncrementPlayCount(const CFileItem &item);
336 bool CleanupOrphanedItems();
338 /////////////////////////////////////////////////
340 /////////////////////////////////////////////////
341 bool GetGenresNav(const CStdString& strBaseDir, CFileItemList& items, const Filter &filter = Filter(), bool countOnly = false);
342 bool GetYearsNav(const CStdString& strBaseDir, CFileItemList& items, const Filter &filter = Filter());
343 bool GetArtistsNav(const CStdString& strBaseDir, CFileItemList& items, bool albumArtistsOnly = false, int idGenre = -1, int idAlbum = -1, int idSong = -1, const Filter &filter = Filter(), const SortDescription &sortDescription = SortDescription(), bool countOnly = false);
344 bool GetCommonNav(const CStdString &strBaseDir, const CStdString &table, const CStdString &labelField, CFileItemList &items, const Filter &filter /* = Filter() */, bool countOnly /* = false */);
345 bool GetAlbumTypesNav(const CStdString &strBaseDir, CFileItemList &items, const Filter &filter = Filter(), bool countOnly = false);
346 bool GetMusicLabelsNav(const CStdString &strBaseDir, CFileItemList &items, const Filter &filter = Filter(), bool countOnly = false);
347 bool GetAlbumsNav(const CStdString& strBaseDir, CFileItemList& items, int idGenre = -1, int idArtist = -1, const Filter &filter = Filter(), const SortDescription &sortDescription = SortDescription(), bool countOnly = false);
348 bool GetAlbumsByYear(const CStdString &strBaseDir, CFileItemList& items, int year);
349 bool GetSongsNav(const CStdString& strBaseDir, CFileItemList& items, int idGenre, int idArtist,int idAlbum, const SortDescription &sortDescription = SortDescription());
350 bool GetSongsByYear(const CStdString& baseDir, CFileItemList& items, int year);
351 bool GetSongsByWhere(const CStdString &baseDir, const Filter &filter, CFileItemList& items, const SortDescription &sortDescription = SortDescription());
352 bool GetAlbumsByWhere(const CStdString &baseDir, const Filter &filter, CFileItemList &items, const SortDescription &sortDescription = SortDescription(), bool countOnly = false);
353 bool GetArtistsByWhere(const CStdString& strBaseDir, const Filter &filter, CFileItemList& items, const SortDescription &sortDescription = SortDescription(), bool countOnly = false);
354 bool GetRandomSong(CFileItem* item, int& idSong, const Filter &filter);
355 int GetSongsCount(const Filter &filter = Filter());
356 unsigned int GetSongIDs(const Filter &filter, std::vector<std::pair<int,int> > &songIDs);
357 virtual bool GetFilter(CDbUrl &musicUrl, Filter &filter, SortDescription &sorting);
359 /////////////////////////////////////////////////
361 /////////////////////////////////////////////////
362 bool SetScraperForPath(const CStdString& strPath, const ADDON::ScraperPtr& info);
363 bool GetScraperForPath(const CStdString& strPath, ADDON::ScraperPtr& info, const ADDON::TYPE &type);
365 /*! \brief Check whether a given scraper is in use.
366 \param scraperID the scraper to check for.
367 \return true if the scraper is in use, false otherwise.
369 bool ScraperInUse(const CStdString &scraperID) const;
371 /////////////////////////////////////////////////
373 /////////////////////////////////////////////////
374 void AddKaraokeData(int idSong, int iKaraokeNumber, DWORD crc);
375 bool GetSongByKaraokeNumber( int number, CSong& song );
376 bool SetKaraokeSongDelay( int idSong, int delay );
377 int GetKaraokeSongsCount();
378 void ExportKaraokeInfo(const CStdString &outFile, bool asHTML );
379 void ImportKaraokeInfo(const CStdString &inputFile );
381 /////////////////////////////////////////////////
383 /////////////////////////////////////////////////
384 bool GetItems(const CStdString &strBaseDir, CFileItemList &items, const Filter &filter = Filter(), const SortDescription &sortDescription = SortDescription());
385 bool GetItems(const CStdString &strBaseDir, const CStdString &itemType, CFileItemList &items, const Filter &filter = Filter(), const SortDescription &sortDescription = SortDescription());
386 CStdString GetItemById(const CStdString &itemType, int id);
388 /////////////////////////////////////////////////
390 /////////////////////////////////////////////////
391 void ExportToXML(const CStdString &xmlFile, bool singleFiles = false, bool images=false, bool overwrite=false);
392 void ImportFromXML(const CStdString &xmlFile);
394 /////////////////////////////////////////////////
396 /////////////////////////////////////////////////
397 void SetPropertiesForFileItem(CFileItem& item);
398 static void SetPropertiesFromArtist(CFileItem& item, const CArtist& artist);
399 static void SetPropertiesFromAlbum(CFileItem& item, const CAlbum& album);
401 /////////////////////////////////////////////////
403 /////////////////////////////////////////////////
404 bool SaveAlbumThumb(int idAlbum, const CStdString &thumb);
405 /*! \brief Sets art for a database item.
406 Sets a single piece of art for a database item.
407 \param mediaId the id in the media (song/artist/album) table.
408 \param mediaType the type of media, which corresponds to the table the item resides in (song/artist/album).
409 \param artType the type of art to set, e.g. "thumb", "fanart"
410 \param url the url to the art (this is the original url, not a cached url).
413 void SetArtForItem(int mediaId, const std::string &mediaType, const std::string &artType, const std::string &url);
415 /*! \brief Sets art for a database item.
416 Sets multiple pieces of art for a database item.
417 \param mediaId the id in the media (song/artist/album) table.
418 \param mediaType the type of media, which corresponds to the table the item resides in (song/artist/album).
419 \param art a map of <type, url> where type is "thumb", "fanart", etc. and url is the original url of the art.
422 void SetArtForItem(int mediaId, const std::string &mediaType, const std::map<std::string, std::string> &art);
424 /*! \brief Fetch art for a database item.
425 Fetches multiple pieces of art for a database item.
426 \param mediaId the id in the media (song/artist/album) table.
427 \param mediaType the type of media, which corresponds to the table the item resides in (song/artist/album).
428 \param art [out] a map of <type, url> where type is "thumb", "fanart", etc. and url is the original url of the art.
429 \return true if art is retrieved, false if no art is found.
432 bool GetArtForItem(int mediaId, const std::string &mediaType, std::map<std::string, std::string> &art);
434 /*! \brief Fetch art for a database item.
435 Fetches a single piece of art for a database item.
436 \param mediaId the id in the media (song/artist/album) table.
437 \param mediaType the type of media, which corresponds to the table the item resides in (song/artist/album).
438 \param artType the type of art to retrieve, eg "thumb", "fanart".
439 \return the original URL to the piece of art, if available.
442 std::string GetArtForItem(int mediaId, const std::string &mediaType, const std::string &artType);
444 /*! \brief Fetch artist art for a song or album item.
445 Fetches the art associated with the primary artist for the song or album.
446 \param mediaId the id in the media (song/album) table.
447 \param mediaType the type of media, which corresponds to the table the item resides in (song/album).
448 \param art [out] the art map <type, url> of artist art.
449 \return true if artist art is found, false otherwise.
452 bool GetArtistArtForItem(int mediaId, const std::string &mediaType, std::map<std::string, std::string> &art);
454 /*! \brief Fetch artist art for a song or album item.
455 Fetches a single piece of art associated with the primary artist for the song or album.
456 \param mediaId the id in the media (song/album) table.
457 \param mediaType the type of media, which corresponds to the table the item resides in (song/album).
458 \param artType the type of art to retrieve, eg "thumb", "fanart".
459 \return the original URL to the piece of art, if available.
462 std::string GetArtistArtForItem(int mediaId, const std::string &mediaType, const std::string &artType);
465 std::map<CStdString, int> m_artistCache;
466 std::map<CStdString, int> m_genreCache;
467 std::map<CStdString, int> m_pathCache;
468 std::map<CStdString, int> m_thumbCache;
469 std::map<CStdString, CAlbum> m_albumCache;
471 virtual bool CreateTables();
472 virtual int GetMinVersion() const;
474 const char *GetBaseDBName() const { return "MyMusic"; };
478 /*! \brief (Re)Create the generic database views for songs and albums
480 virtual void CreateViews();
482 void SplitString(const CStdString &multiString, std::vector<std::string> &vecStrings, CStdString &extraStrings);
483 CSong GetSongFromDataset();
484 CSong GetSongFromDataset(const dbiplus::sql_record* const record, int offset = 0);
485 CArtist GetArtistFromDataset(dbiplus::Dataset* pDS, int offset = 0, bool needThumb = true);
486 CArtist GetArtistFromDataset(const dbiplus::sql_record* const record, int offset = 0, bool needThumb = true);
487 CAlbum GetAlbumFromDataset(dbiplus::Dataset* pDS, int offset = 0, bool imageURL = false);
488 CAlbum GetAlbumFromDataset(const dbiplus::sql_record* const record, int offset = 0, bool imageURL = false);
489 CArtistCredit GetArtistCreditFromDataset(const dbiplus::sql_record* const record, int offset = 0);
490 void GetFileItemFromDataset(CFileItem* item, const CMusicDbUrl &baseUrl);
491 void GetFileItemFromDataset(const dbiplus::sql_record* const record, CFileItem* item, const CMusicDbUrl &baseUrl);
492 CSong GetAlbumInfoSongFromDataset(const dbiplus::sql_record* const record, int offset = 0);
494 bool CleanupSongsByIds(const CStdString &strSongIds);
496 bool CleanupAlbums();
497 bool CleanupArtists();
498 bool CleanupGenres();
499 virtual bool UpdateOldVersion(int version);
500 bool SearchArtists(const CStdString& search, CFileItemList &artists);
501 bool SearchAlbums(const CStdString& search, CFileItemList &albums);
502 bool SearchSongs(const CStdString& strSearch, CFileItemList &songs);
503 int GetSongIDFromPath(const CStdString &filePath);
505 // Fields should be ordered as they
506 // appear in the songview
518 song_strMusicBrainzTrackID,
532 song_strAlbumArtists,
533 song_enumCount // end of the enum, do not add past here
536 // Fields should be ordered as they
537 // appear in the albumview
542 album_strMusicBrainzAlbumID,
556 album_enumCount // end of the enum, do not add past here
559 enum _ArtistCreditFields
561 // used for GetAlbum to get the cascaded album/song artist credits
562 artistCredit_idEntity = 0, // can be idSong or idAlbum depending on context
563 artistCredit_idArtist,
564 artistCredit_strArtist,
565 artistCredit_strMusicBrainzArtistID,
566 artistCredit_bFeatured,
567 artistCredit_strJoinPhrase,
569 artistCredit_enumCount
570 } ArtistCreditFields;
576 artist_strMusicBrainzArtistID,
582 artist_strInstruments,
586 artist_strYearsActive,
589 artist_enumCount // end of the enum, do not add past here
592 enum _AlbumInfoSongFields
594 albumInfoSong_idAlbumInfoSong=0,
595 albumInfoSong_idAlbumInfo,
596 albumInfoSong_iTrack,
597 albumInfoSong_strTitle,
598 albumInfoSong_iDuration,
599 albumInfoSong_enumCount // end of the enum, do not add past here
600 } AlbumInfoSongFields;