PageRenderTime 63ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 1ms

/xbmc/music/MusicDatabase.cpp

https://github.com/weitao2012/android-1
C++ | 5054 lines | 4206 code | 620 blank | 228 comment | 826 complexity | e2588e40aa2eea637c6b827fc879f208 MD5 | raw file
Possible License(s): GPL-2.0, AGPL-1.0

Large files files are truncated, but you can click here to view the full file

  1. /*
  2. * Copyright (C) 2005-2008 Team XBMC
  3. * http://www.xbmc.org
  4. *
  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)
  8. * any later version.
  9. *
  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.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with XBMC; see the file COPYING. If not, write to
  17. * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  18. * http://www.gnu.org/copyleft/gpl.html
  19. *
  20. */
  21. #include "threads/SystemClock.h"
  22. #include "system.h"
  23. #include "MusicDatabase.h"
  24. #include "network/cddb.h"
  25. #include "filesystem/DirectoryCache.h"
  26. #include "filesystem/MusicDatabaseDirectory/DirectoryNode.h"
  27. #include "filesystem/MusicDatabaseDirectory/QueryParams.h"
  28. #include "filesystem/MusicDatabaseDirectory.h"
  29. #include "filesystem/SpecialProtocol.h"
  30. #include "GUIInfoManager.h"
  31. #include "music/tags/MusicInfoTag.h"
  32. #include "addons/AddonManager.h"
  33. #include "addons/Scraper.h"
  34. #include "addons/Addon.h"
  35. #include "utils/URIUtils.h"
  36. #include "Artist.h"
  37. #include "Album.h"
  38. #include "Song.h"
  39. #include "guilib/GUIWindowManager.h"
  40. #include "dialogs/GUIDialogOK.h"
  41. #include "dialogs/GUIDialogProgress.h"
  42. #include "dialogs/GUIDialogYesNo.h"
  43. #include "dialogs/GUIDialogSelect.h"
  44. #include "filesystem/File.h"
  45. #include "settings/GUISettings.h"
  46. #include "settings/AdvancedSettings.h"
  47. #include "FileItem.h"
  48. #include "Application.h"
  49. #ifdef HAS_KARAOKE
  50. #include "karaoke/karaokelyricsfactory.h"
  51. #endif
  52. #include "storage/MediaManager.h"
  53. #include "settings/Settings.h"
  54. #include "utils/StringUtils.h"
  55. #include "guilib/LocalizeStrings.h"
  56. #include "utils/log.h"
  57. #include "utils/TimeUtils.h"
  58. #include "TextureCache.h"
  59. #include "addons/AddonInstaller.h"
  60. #include "utils/AutoPtrHandle.h"
  61. #include "interfaces/AnnouncementManager.h"
  62. #include "dbwrappers/dataset.h"
  63. #include "utils/XMLUtils.h"
  64. #include "URL.h"
  65. using namespace std;
  66. using namespace AUTOPTR;
  67. using namespace XFILE;
  68. using namespace MUSICDATABASEDIRECTORY;
  69. using ADDON::AddonPtr;
  70. #define RECENTLY_PLAYED_LIMIT 25
  71. #define MIN_FULL_SEARCH_LENGTH 3
  72. #ifdef HAS_DVD_DRIVE
  73. using namespace CDDB;
  74. #endif
  75. CMusicDatabase::CMusicDatabase(void)
  76. {
  77. }
  78. CMusicDatabase::~CMusicDatabase(void)
  79. {
  80. EmptyCache();
  81. }
  82. bool CMusicDatabase::Open()
  83. {
  84. return CDatabase::Open(g_advancedSettings.m_databaseMusic);
  85. }
  86. bool CMusicDatabase::CreateTables()
  87. {
  88. BeginTransaction();
  89. try
  90. {
  91. CDatabase::CreateTables();
  92. CLog::Log(LOGINFO, "create artist table");
  93. m_pDS->exec("CREATE TABLE artist ( idArtist integer primary key, strArtist varchar(256))\n");
  94. CLog::Log(LOGINFO, "create album table");
  95. m_pDS->exec("CREATE TABLE album ( idAlbum integer primary key, strAlbum varchar(256), strArtists text, strGenres text, iYear integer, idThumb integer, bCompilation integer not null default '0' )\n");
  96. CLog::Log(LOGINFO, "create album_artist table");
  97. m_pDS->exec("CREATE TABLE album_artist ( idArtist integer, idAlbum integer, boolFeatured integer, iOrder integer )\n");
  98. CLog::Log(LOGINFO, "create album_genre table");
  99. m_pDS->exec("CREATE TABLE album_genre ( idGenre integer, idAlbum integer, iOrder integer )\n");
  100. CLog::Log(LOGINFO, "create genre table");
  101. m_pDS->exec("CREATE TABLE genre ( idGenre integer primary key, strGenre varchar(256))\n");
  102. CLog::Log(LOGINFO, "create path table");
  103. m_pDS->exec("CREATE TABLE path ( idPath integer primary key, strPath varchar(512), strHash text)\n");
  104. CLog::Log(LOGINFO, "create song table");
  105. m_pDS->exec("CREATE TABLE song ( idSong integer primary key, idAlbum integer, idPath integer, strArtists text, strGenres text, strTitle varchar(512), iTrack integer, iDuration integer, iYear integer, dwFileNameCRC text, strFileName text, strMusicBrainzTrackID text, strMusicBrainzArtistID text, strMusicBrainzAlbumID text, strMusicBrainzAlbumArtistID text, strMusicBrainzTRMID text, iTimesPlayed integer, iStartOffset integer, iEndOffset integer, idThumb integer, lastplayed varchar(20) default NULL, rating char default '0', comment text)\n");
  106. CLog::Log(LOGINFO, "create song_artist table");
  107. m_pDS->exec("CREATE TABLE song_artist ( idArtist integer, idSong integer, boolFeatured integer, iOrder integer )\n");
  108. CLog::Log(LOGINFO, "create song_genre table");
  109. m_pDS->exec("CREATE TABLE song_genre ( idGenre integer, idSong integer, iOrder integer )\n");
  110. CLog::Log(LOGINFO, "create albuminfo table");
  111. m_pDS->exec("CREATE TABLE albuminfo ( idAlbumInfo integer primary key, idAlbum integer, iYear integer, strMoods text, strStyles text, strThemes text, strReview text, strImage text, strLabel text, strType text, iRating integer)\n");
  112. CLog::Log(LOGINFO, "create albuminfosong table");
  113. m_pDS->exec("CREATE TABLE albuminfosong ( idAlbumInfoSong integer primary key, idAlbumInfo integer, iTrack integer, strTitle text, iDuration integer)\n");
  114. CLog::Log(LOGINFO, "create artistnfo table");
  115. m_pDS->exec("CREATE TABLE artistinfo ( idArtistInfo integer primary key, idArtist integer, strBorn text, strFormed text, strGenres text, strMoods text, strStyles text, strInstruments text, strBiography text, strDied text, strDisbanded text, strYearsActive text, strImage text, strFanart text)\n");
  116. CLog::Log(LOGINFO, "create content table");
  117. m_pDS->exec("CREATE TABLE content (strPath text, strScraperPath text, strContent text, strSettings text)\n");
  118. CLog::Log(LOGINFO, "create discography table");
  119. m_pDS->exec("CREATE TABLE discography (idArtist integer, strAlbum text, strYear text)\n");
  120. CLog::Log(LOGINFO, "create karaokedata table");
  121. m_pDS->exec("CREATE TABLE karaokedata ( iKaraNumber integer, idSong integer, iKaraDelay integer, strKaraEncoding text, "
  122. "strKaralyrics text, strKaraLyrFileCRC text )\n");
  123. CLog::Log(LOGINFO, "create album index");
  124. m_pDS->exec("CREATE INDEX idxAlbum ON album(strAlbum)");
  125. CLog::Log(LOGINFO, "create album compilation index");
  126. m_pDS->exec("CREATE INDEX idxAlbum_1 ON album(bCompilation)");
  127. CLog::Log(LOGINFO, "create album_artist indexes");
  128. m_pDS->exec("CREATE UNIQUE INDEX idxAlbumArtist_1 ON album_artist ( idAlbum, idArtist )\n");
  129. m_pDS->exec("CREATE UNIQUE INDEX idxAlbumArtist_2 ON album_artist ( idArtist, idAlbum )\n");
  130. m_pDS->exec("CREATE INDEX idxAlbumArtist_3 ON album_artist ( boolFeatured )\n");
  131. CLog::Log(LOGINFO, "create album_genre indexes");
  132. m_pDS->exec("CREATE UNIQUE INDEX idxAlbumGenre_1 ON album_genre ( idAlbum, idGenre )\n");
  133. m_pDS->exec("CREATE UNIQUE INDEX idxAlbumGenre_2 ON album_genre ( idGenre, idAlbum )\n");
  134. CLog::Log(LOGINFO, "create genre index");
  135. m_pDS->exec("CREATE INDEX idxGenre ON genre(strGenre)");
  136. CLog::Log(LOGINFO, "create artist index");
  137. m_pDS->exec("CREATE INDEX idxArtist ON artist(strArtist)");
  138. CLog::Log(LOGINFO, "create path index");
  139. m_pDS->exec("CREATE INDEX idxPath ON path(strPath)");
  140. CLog::Log(LOGINFO, "create song index");
  141. m_pDS->exec("CREATE INDEX idxSong ON song(strTitle)");
  142. CLog::Log(LOGINFO, "create song index1");
  143. m_pDS->exec("CREATE INDEX idxSong1 ON song(iTimesPlayed)");
  144. CLog::Log(LOGINFO, "create song index2");
  145. m_pDS->exec("CREATE INDEX idxSong2 ON song(lastplayed)");
  146. CLog::Log(LOGINFO, "create song index3");
  147. m_pDS->exec("CREATE INDEX idxSong3 ON song(idAlbum)");
  148. CLog::Log(LOGINFO, "create song index6");
  149. m_pDS->exec("CREATE INDEX idxSong6 ON song(idPath)");
  150. CLog::Log(LOGINFO, "create song_artist indexes");
  151. m_pDS->exec("CREATE UNIQUE INDEX idxSongArtist_1 ON song_artist ( idSong, idArtist )\n");
  152. m_pDS->exec("CREATE UNIQUE INDEX idxSongArtist_2 ON song_artist ( idArtist, idSong )\n");
  153. m_pDS->exec("CREATE INDEX idxSongArtist_3 ON song_artist ( boolFeatured )\n");
  154. CLog::Log(LOGINFO, "create song_genre indexes");
  155. m_pDS->exec("CREATE UNIQUE INDEX idxSongGenre_1 ON song_genre ( idSong, idGenre )\n");
  156. m_pDS->exec("CREATE UNIQUE INDEX idxSongGenre_2 ON song_genre ( idGenre, idSong )\n");
  157. //m_pDS->exec("CREATE INDEX idxSong ON song(dwFileNameCRC)");
  158. CLog::Log(LOGINFO, "create artistinfo index");
  159. m_pDS->exec("CREATE INDEX idxArtistInfo on artistinfo(idArtist)");
  160. CLog::Log(LOGINFO, "create albuminfo index");
  161. m_pDS->exec("CREATE INDEX idxAlbumInfo on albuminfo(idAlbum)");
  162. CLog::Log(LOGINFO, "create karaokedata index");
  163. m_pDS->exec("CREATE INDEX idxKaraNumber on karaokedata(iKaraNumber)");
  164. m_pDS->exec("CREATE INDEX idxKarSong on karaokedata(idSong)");
  165. // Trigger
  166. CLog::Log(LOGINFO, "create albuminfo trigger");
  167. m_pDS->exec("CREATE TRIGGER tgrAlbumInfo AFTER delete ON albuminfo FOR EACH ROW BEGIN delete from albuminfosong where albuminfosong.idAlbumInfo=old.idAlbumInfo; END");
  168. CLog::Log(LOGINFO, "create art table, index and triggers");
  169. m_pDS->exec("CREATE TABLE art(art_id INTEGER PRIMARY KEY, media_id INTEGER, media_type TEXT, type TEXT, url TEXT)");
  170. m_pDS->exec("CREATE INDEX ix_art ON art(media_id, media_type(20), type(20))");
  171. m_pDS->exec("CREATE TRIGGER delete_song AFTER DELETE ON song FOR EACH ROW BEGIN DELETE FROM art WHERE media_id=old.idSong AND media_type='song'; END");
  172. m_pDS->exec("CREATE TRIGGER delete_album AFTER DELETE ON album FOR EACH ROW BEGIN DELETE FROM art WHERE media_id=old.idAlbum AND media_type='album'; END");
  173. m_pDS->exec("CREATE TRIGGER delete_artist AFTER DELETE ON artist FOR EACH ROW BEGIN DELETE FROM art WHERE media_id=old.idArtist AND media_type='artist'; END");
  174. // we create views last to ensure all indexes are rolled in
  175. CreateViews();
  176. // Add 'Karaoke' genre
  177. AddGenre( "Karaoke" );
  178. }
  179. catch (...)
  180. {
  181. CLog::Log(LOGERROR, "%s unable to create tables:%i", __FUNCTION__, (int)GetLastError());
  182. RollbackTransaction();
  183. return false;
  184. }
  185. CommitTransaction();
  186. return true;
  187. }
  188. void CMusicDatabase::CreateViews()
  189. {
  190. CLog::Log(LOGINFO, "create song view");
  191. m_pDS->exec("DROP VIEW IF EXISTS songview");
  192. m_pDS->exec("CREATE VIEW songview AS SELECT "
  193. " song.idSong AS idSong, "
  194. " song.strArtists AS strArtists,"
  195. " song.strGenres AS strGenres,"
  196. " strTitle, iTrack, iDuration,"
  197. " song.iYear AS iYear, dwFileNameCRC, strFileName, strMusicBrainzTrackID,"
  198. " strMusicBrainzArtistID, strMusicBrainzAlbumID, strMusicBrainzAlbumArtistID,"
  199. " strMusicBrainzTRMID, iTimesPlayed, iStartOffset, iEndOffset, lastplayed,"
  200. " rating, comment, song.idAlbum AS idAlbum, strAlbum, strPath,"
  201. " iKaraNumber, iKaraDelay, strKaraEncoding,"
  202. " album.bCompilation AS bCompilation "
  203. "FROM song"
  204. " JOIN album ON"
  205. " song.idAlbum=album.idAlbum"
  206. " JOIN path ON"
  207. " song.idPath=path.idPath"
  208. " LEFT OUTER JOIN karaokedata ON"
  209. " song.idSong=karaokedata.idSong");
  210. CLog::Log(LOGINFO, "create album view");
  211. m_pDS->exec("DROP VIEW IF EXISTS albumview");
  212. m_pDS->exec("CREATE VIEW albumview AS SELECT"
  213. " album.idAlbum AS idAlbum, strAlbum, "
  214. " album.strArtists AS strArtists,"
  215. " album.strGenres AS strGenres, "
  216. " album.iYear AS iYear,"
  217. " idAlbumInfo, strMoods, strStyles, strThemes,"
  218. " strReview, strLabel, strType, strImage, iRating, "
  219. " bCompilation "
  220. "FROM album "
  221. " LEFT OUTER JOIN albuminfo ON"
  222. " album.idAlbum=albuminfo.idAlbum");
  223. CLog::Log(LOGINFO, "create artist view");
  224. m_pDS->exec("DROP VIEW IF EXISTS artistview");
  225. m_pDS->exec("CREATE VIEW artistview AS SELECT"
  226. " artist.idArtist AS idArtist, strArtist, "
  227. " strBorn, strFormed, strGenres,"
  228. " strMoods, strStyles, strInstruments, "
  229. " strBiography, strDied, strDisbanded, "
  230. " strYearsActive, strImage, strFanart "
  231. "FROM artist "
  232. " LEFT OUTER JOIN artistinfo ON"
  233. " artist.idArtist = artistinfo.idArtist");
  234. }
  235. int CMusicDatabase::AddAlbum(const CAlbum &album, vector<int> &songIDs)
  236. {
  237. // add the album
  238. int idAlbum = AddAlbum(album.strAlbum, StringUtils::Join(album.artist, g_advancedSettings.m_musicItemSeparator), StringUtils::Join(album.genre, g_advancedSettings.m_musicItemSeparator), album.iYear, album.bCompilation);
  239. SetArtForItem(idAlbum, "album", album.art);
  240. // add the songs
  241. for (VECSONGS::const_iterator i = album.songs.begin(); i != album.songs.end(); ++i)
  242. songIDs.push_back(AddSong(*i, false, idAlbum));
  243. return idAlbum;
  244. }
  245. int CMusicDatabase::AddSong(const CSong& song, bool bCheck, int idAlbum)
  246. {
  247. int idSong = -1;
  248. CStdString strSQL;
  249. try
  250. {
  251. // We need at least the title
  252. if (song.strTitle.IsEmpty())
  253. return -1;
  254. CStdString strPath, strFileName;
  255. URIUtils::Split(song.strFileName, strPath, strFileName);
  256. if (NULL == m_pDB.get()) return -1;
  257. if (NULL == m_pDS.get()) return -1;
  258. int idPath = AddPath(strPath);
  259. if (idAlbum < 0)
  260. {
  261. if (!song.albumArtist.empty()) // have an album artist
  262. idAlbum = AddAlbum(song.strAlbum, StringUtils::Join(song.albumArtist, g_advancedSettings.m_musicItemSeparator), StringUtils::Join(song.genre, g_advancedSettings.m_musicItemSeparator), song.iYear, song.bCompilation);
  263. else
  264. idAlbum = AddAlbum(song.strAlbum, StringUtils::Join(song.artist, g_advancedSettings.m_musicItemSeparator), StringUtils::Join(song.genre, g_advancedSettings.m_musicItemSeparator), song.iYear, song.bCompilation);
  265. }
  266. DWORD crc = ComputeCRC(song.strFileName);
  267. bool bInsert = true;
  268. bool bHasKaraoke = false;
  269. #ifdef HAS_KARAOKE
  270. bHasKaraoke = CKaraokeLyricsFactory::HasLyrics( song.strFileName );
  271. #endif
  272. if (bCheck)
  273. {
  274. strSQL=PrepareSQL("select * from song where idAlbum=%i and dwFileNameCRC='%ul' and strTitle='%s'",
  275. idAlbum, crc, song.strTitle.c_str());
  276. if (!m_pDS->query(strSQL.c_str()))
  277. return -1;
  278. if (m_pDS->num_rows() != 0)
  279. {
  280. idSong = m_pDS->fv("idSong").get_asInt();
  281. bInsert = false;
  282. }
  283. m_pDS->close();
  284. }
  285. if (bInsert)
  286. {
  287. CStdString strSQL1;
  288. CStdString strIdSong;
  289. if (song.idSong < 0)
  290. strIdSong = "NULL";
  291. else
  292. strIdSong.Format("%d", song.idSong);
  293. // we use replace because it can handle both inserting a new song
  294. // and replacing an existing song's record if the given idSong already exists
  295. strSQL=PrepareSQL("replace into song (idSong,idAlbum,idPath,strArtists,strGenres,strTitle,iTrack,iDuration,iYear,dwFileNameCRC,strFileName,strMusicBrainzTrackID,strMusicBrainzArtistID,strMusicBrainzAlbumID,strMusicBrainzAlbumArtistID,strMusicBrainzTRMID,iTimesPlayed,iStartOffset,iEndOffset,lastplayed,rating,comment) values (%s,%i,%i,'%s','%s','%s',%i,%i,%i,'%ul','%s','%s','%s','%s','%s','%s'",
  296. strIdSong.c_str(),
  297. idAlbum, idPath,
  298. StringUtils::Join(song.artist, g_advancedSettings.m_musicItemSeparator).c_str(),
  299. StringUtils::Join(song.genre, g_advancedSettings.m_musicItemSeparator).c_str(),
  300. song.strTitle.c_str(),
  301. song.iTrack, song.iDuration, song.iYear,
  302. crc, strFileName.c_str(),
  303. song.strMusicBrainzTrackID.c_str(),
  304. song.strMusicBrainzArtistID.c_str(),
  305. song.strMusicBrainzAlbumID.c_str(),
  306. song.strMusicBrainzAlbumArtistID.c_str(),
  307. song.strMusicBrainzTRMID.c_str());
  308. if (song.lastPlayed.IsValid())
  309. strSQL1=PrepareSQL(",%i,%i,%i,'%s','%c','%s')",
  310. song.iTimesPlayed, song.iStartOffset, song.iEndOffset, song.lastPlayed.GetAsDBDateTime().c_str(), song.rating, song.strComment.c_str());
  311. else
  312. strSQL1=PrepareSQL(",%i,%i,%i,NULL,'%c','%s')",
  313. song.iTimesPlayed, song.iStartOffset, song.iEndOffset, song.rating, song.strComment.c_str());
  314. strSQL+=strSQL1;
  315. m_pDS->exec(strSQL.c_str());
  316. if (song.idSong < 0)
  317. idSong = (int)m_pDS->lastinsertid();
  318. else
  319. idSong = song.idSong;
  320. }
  321. if (!song.strThumb.empty())
  322. SetArtForItem(idSong, "song", "thumb", song.strThumb);
  323. for (unsigned int index = 0; index < song.albumArtist.size(); index++)
  324. {
  325. int idAlbumArtist = AddArtist(song.albumArtist[index]);
  326. AddAlbumArtist(idAlbumArtist, idAlbum, index > 0 ? true : false, index);
  327. }
  328. for (unsigned int index = 0; index < song.artist.size(); index++)
  329. {
  330. int idArtist = AddArtist(song.artist[index]);
  331. AddSongArtist(idArtist, idSong, index > 0 ? true : false, index);
  332. }
  333. unsigned int index = 0;
  334. // If this is karaoke song, change the genre to 'Karaoke' (and add it if it's not there)
  335. if ( bHasKaraoke && g_advancedSettings.m_karaokeChangeGenreForKaraokeSongs )
  336. {
  337. int idGenre = AddGenre("Karaoke");
  338. AddSongGenre(idGenre, idSong, index);
  339. AddAlbumGenre(idGenre, idAlbum, index++);
  340. }
  341. for (vector<string>::const_iterator i = song.genre.begin(); i != song.genre.end(); ++i)
  342. {
  343. // index will be wrong for albums, but ordering is not all that relevant
  344. // for genres anyway
  345. int idGenre = AddGenre(*i);
  346. AddSongGenre(idGenre, idSong, index);
  347. AddAlbumGenre(idGenre, idAlbum, index++);
  348. }
  349. // Add karaoke information (if any)
  350. if ( bHasKaraoke )
  351. AddKaraokeData(idSong, song );
  352. AnnounceUpdate("song", idSong);
  353. }
  354. catch (...)
  355. {
  356. CLog::Log(LOGERROR, "musicdatabase:unable to addsong (%s)", strSQL.c_str());
  357. }
  358. return idSong;
  359. }
  360. int CMusicDatabase::UpdateSong(const CSong& song, int idSong /* = -1 */)
  361. {
  362. CStdString sql;
  363. if (idSong < 0)
  364. idSong = song.idSong;
  365. if (idSong < 0)
  366. return -1;
  367. // delete linked songs
  368. // we don't delete from the song table here because
  369. // AddSong will update the existing record
  370. sql.Format("delete from song_artist where idSong=%d", idSong);
  371. ExecuteQuery(sql);
  372. sql.Format("delete from song_genre where idSong=%d", idSong);
  373. ExecuteQuery(sql);
  374. sql.Format("delete from karaokedata where idSong=%d", idSong);
  375. ExecuteQuery(sql);
  376. CSong newSong = song;
  377. // Make sure newSong.idSong has a valid value (> 0)
  378. newSong.idSong = idSong;
  379. // re-add the song
  380. newSong.idSong = AddSong(newSong, false);
  381. if (newSong.idSong < 0)
  382. return -1;
  383. return newSong.idSong;
  384. }
  385. int CMusicDatabase::AddAlbum(const CStdString& strAlbum1, const CStdString &strArtist, const CStdString& strGenre, int year, bool bCompilation)
  386. {
  387. CStdString strSQL;
  388. try
  389. {
  390. CStdString strAlbum=strAlbum1;
  391. strAlbum.TrimLeft(" ");
  392. strAlbum.TrimRight(" ");
  393. if (NULL == m_pDB.get()) return -1;
  394. if (NULL == m_pDS.get()) return -1;
  395. map <CStdString, CAlbumCache>::const_iterator it;
  396. it = m_albumCache.find(strAlbum + strArtist);
  397. if (it != m_albumCache.end())
  398. return it->second.idAlbum;
  399. strSQL=PrepareSQL("select * from album where strArtists='%s' and strAlbum like '%s'", strArtist.c_str(), strAlbum.c_str());
  400. m_pDS->query(strSQL.c_str());
  401. if (m_pDS->num_rows() == 0)
  402. {
  403. m_pDS->close();
  404. // doesnt exists, add it
  405. strSQL=PrepareSQL("insert into album (idAlbum, strAlbum, strArtists, strGenres, iYear, bCompilation) values( NULL, '%s', '%s', '%s', %i, %i)", strAlbum.c_str(), strArtist.c_str(), strGenre.c_str(), year, bCompilation);
  406. m_pDS->exec(strSQL.c_str());
  407. CAlbumCache album;
  408. album.idAlbum = (int)m_pDS->lastinsertid();
  409. album.strAlbum = strAlbum;
  410. album.artist = StringUtils::Split(strArtist, g_advancedSettings.m_musicItemSeparator);
  411. m_albumCache.insert(pair<CStdString, CAlbumCache>(album.strAlbum + strArtist, album));
  412. return album.idAlbum;
  413. }
  414. else
  415. {
  416. // exists in our database and not scanned during this scan, so we should update it as the details
  417. // may have changed (there's a reason we're rescanning, afterall!)
  418. CAlbumCache album;
  419. album.idAlbum = m_pDS->fv("idAlbum").get_asInt();
  420. album.strAlbum = strAlbum;
  421. album.artist = StringUtils::Split(strArtist, g_advancedSettings.m_musicItemSeparator);
  422. m_albumCache.insert(pair<CStdString, CAlbumCache>(album.strAlbum + strArtist, album));
  423. m_pDS->close();
  424. strSQL=PrepareSQL("update album set strGenres='%s', iYear=%i where idAlbum=%i", strGenre.c_str(), year, album.idAlbum);
  425. m_pDS->exec(strSQL.c_str());
  426. // and clear the link tables - these are updated in AddSong()
  427. strSQL=PrepareSQL("delete from album_artist where idAlbum=%i", album.idAlbum);
  428. m_pDS->exec(strSQL.c_str());
  429. strSQL=PrepareSQL("delete from album_genre where idAlbum=%i", album.idAlbum);
  430. m_pDS->exec(strSQL.c_str());
  431. return album.idAlbum;
  432. }
  433. }
  434. catch (...)
  435. {
  436. CLog::Log(LOGERROR, "%s failed with query (%s)", __FUNCTION__, strSQL.c_str());
  437. }
  438. return -1;
  439. }
  440. int CMusicDatabase::AddGenre(const CStdString& strGenre1)
  441. {
  442. CStdString strSQL;
  443. try
  444. {
  445. CStdString strGenre = strGenre1;
  446. strGenre.TrimLeft(" ");
  447. strGenre.TrimRight(" ");
  448. if (strGenre.IsEmpty())
  449. strGenre=g_localizeStrings.Get(13205); // Unknown
  450. if (NULL == m_pDB.get()) return -1;
  451. if (NULL == m_pDS.get()) return -1;
  452. map <CStdString, int>::const_iterator it;
  453. it = m_genreCache.find(strGenre);
  454. if (it != m_genreCache.end())
  455. return it->second;
  456. strSQL=PrepareSQL("select * from genre where strGenre like '%s'", strGenre.c_str());
  457. m_pDS->query(strSQL.c_str());
  458. if (m_pDS->num_rows() == 0)
  459. {
  460. m_pDS->close();
  461. // doesnt exists, add it
  462. strSQL=PrepareSQL("insert into genre (idGenre, strGenre) values( NULL, '%s' )", strGenre.c_str());
  463. m_pDS->exec(strSQL.c_str());
  464. int idGenre = (int)m_pDS->lastinsertid();
  465. m_genreCache.insert(pair<CStdString, int>(strGenre1, idGenre));
  466. return idGenre;
  467. }
  468. else
  469. {
  470. int idGenre = m_pDS->fv("idGenre").get_asInt();
  471. m_genreCache.insert(pair<CStdString, int>(strGenre1, idGenre));
  472. m_pDS->close();
  473. return idGenre;
  474. }
  475. }
  476. catch (...)
  477. {
  478. CLog::Log(LOGERROR, "musicdatabase:unable to addgenre (%s)", strSQL.c_str());
  479. }
  480. return -1;
  481. }
  482. int CMusicDatabase::AddArtist(const CStdString& strArtist1)
  483. {
  484. CStdString strSQL;
  485. try
  486. {
  487. CStdString strArtist = strArtist1;
  488. strArtist.TrimLeft(" ");
  489. strArtist.TrimRight(" ");
  490. if (strArtist.IsEmpty())
  491. strArtist=g_localizeStrings.Get(13205); // Unknown
  492. if (NULL == m_pDB.get()) return -1;
  493. if (NULL == m_pDS.get()) return -1;
  494. map <CStdString, int>::const_iterator it;
  495. it = m_artistCache.find(strArtist);
  496. if (it != m_artistCache.end())
  497. return it->second;//.idArtist;
  498. strSQL=PrepareSQL("select * from artist where strArtist like '%s'", strArtist.c_str());
  499. m_pDS->query(strSQL.c_str());
  500. if (m_pDS->num_rows() == 0)
  501. {
  502. m_pDS->close();
  503. // doesnt exists, add it
  504. strSQL=PrepareSQL("insert into artist (idArtist, strArtist) values( NULL, '%s' )", strArtist.c_str());
  505. m_pDS->exec(strSQL.c_str());
  506. int idArtist = (int)m_pDS->lastinsertid();
  507. m_artistCache.insert(pair<CStdString, int>(strArtist1, idArtist));
  508. return idArtist;
  509. }
  510. else
  511. {
  512. int idArtist = (int)m_pDS->fv("idArtist").get_asInt();
  513. m_artistCache.insert(pair<CStdString, int>(strArtist1, idArtist));
  514. m_pDS->close();
  515. return idArtist;
  516. }
  517. }
  518. catch (...)
  519. {
  520. CLog::Log(LOGERROR, "musicdatabase:unable to addartist (%s)", strSQL.c_str());
  521. }
  522. return -1;
  523. }
  524. bool CMusicDatabase::AddSongArtist(int idArtist, int idSong, bool featured, int iOrder)
  525. {
  526. CStdString strSQL;
  527. strSQL=PrepareSQL("replace into song_artist (idArtist, idSong, boolFeatured, iOrder) values(%i,%i,%i,%i)",
  528. idArtist, idSong, featured == true ? 1 : 0, iOrder);
  529. return ExecuteQuery(strSQL);
  530. };
  531. bool CMusicDatabase::AddAlbumArtist(int idArtist, int idAlbum, bool featured, int iOrder)
  532. {
  533. CStdString strSQL;
  534. strSQL=PrepareSQL("replace into album_artist (idArtist, idAlbum, boolFeatured, iOrder) values(%i,%i,%i,%i)",
  535. idArtist, idAlbum, featured == true ? 1 : 0, iOrder);
  536. return ExecuteQuery(strSQL);
  537. };
  538. bool CMusicDatabase::AddSongGenre(int idGenre, int idSong, int iOrder)
  539. {
  540. if (idGenre == -1 || idSong == -1)
  541. return true;
  542. CStdString strSQL;
  543. strSQL=PrepareSQL("replace into song_genre (idGenre, idSong, iOrder) values(%i,%i,%i)",
  544. idGenre, idSong, iOrder);
  545. return ExecuteQuery(strSQL);};
  546. bool CMusicDatabase::AddAlbumGenre(int idGenre, int idAlbum, int iOrder)
  547. {
  548. if (idGenre == -1 || idAlbum == -1)
  549. return true;
  550. CStdString strSQL;
  551. strSQL=PrepareSQL("replace into album_genre (idGenre, idAlbum, iOrder) values(%i,%i,%i)",
  552. idGenre, idAlbum, iOrder);
  553. return ExecuteQuery(strSQL);
  554. };
  555. bool CMusicDatabase::GetAlbumsByArtist(int idArtist, bool includeFeatured, std::vector<long> &albums)
  556. {
  557. try
  558. {
  559. CStdString strSQL, strPrepSQL;
  560. strPrepSQL = "select idAlbum from album_artist where idArtist=%i";
  561. if (includeFeatured == false)
  562. strPrepSQL += " AND boolFeatured = 0";
  563. strSQL=PrepareSQL(strPrepSQL, idArtist);
  564. if (!m_pDS->query(strSQL.c_str()))
  565. return false;
  566. if (m_pDS->num_rows() == 0)
  567. {
  568. m_pDS->close();
  569. return false;
  570. }
  571. while (!m_pDS->eof())
  572. {
  573. albums.push_back(m_pDS->fv("idAlbum").get_asInt());
  574. m_pDS->next();
  575. }
  576. m_pDS->close();
  577. return true;
  578. }
  579. catch (...)
  580. {
  581. CLog::Log(LOGERROR, "%s(%i) failed", __FUNCTION__, idArtist);
  582. }
  583. return false;
  584. }
  585. bool CMusicDatabase::GetArtistsByAlbum(int idAlbum, bool includeFeatured, std::vector<long> &artists)
  586. {
  587. try
  588. {
  589. CStdString strSQL, strPrepSQL;
  590. strPrepSQL = "select idArtist from album_artist where idAlbum=%i";
  591. if (includeFeatured == false)
  592. strPrepSQL += " AND boolFeatured = 0";
  593. strSQL=PrepareSQL(strPrepSQL, idAlbum);
  594. if (!m_pDS->query(strSQL.c_str()))
  595. return false;
  596. if (m_pDS->num_rows() == 0)
  597. {
  598. m_pDS->close();
  599. return false;
  600. }
  601. while (!m_pDS->eof())
  602. {
  603. artists.push_back(m_pDS->fv("idArtist").get_asInt());
  604. m_pDS->next();
  605. }
  606. m_pDS->close();
  607. return true;
  608. }
  609. catch (...)
  610. {
  611. CLog::Log(LOGERROR, "%s(%i) failed", __FUNCTION__, idAlbum);
  612. }
  613. return false;
  614. }
  615. bool CMusicDatabase::GetSongsByArtist(int idArtist, bool includeFeatured, std::vector<long> &songs)
  616. {
  617. try
  618. {
  619. CStdString strSQL, strPrepSQL;
  620. strPrepSQL = "select idSong from song_artist where idArtist=%i";
  621. if (includeFeatured == false)
  622. strPrepSQL += " AND boolFeatured = 0";
  623. strSQL=PrepareSQL(strPrepSQL, idArtist);
  624. if (!m_pDS->query(strSQL.c_str()))
  625. return false;
  626. if (m_pDS->num_rows() == 0)
  627. {
  628. m_pDS->close();
  629. return false;
  630. }
  631. while (!m_pDS->eof())
  632. {
  633. songs.push_back(m_pDS->fv("idSong").get_asInt());
  634. m_pDS->next();
  635. }
  636. m_pDS->close();
  637. return true;
  638. }
  639. catch (...)
  640. {
  641. CLog::Log(LOGERROR, "%s(%i) failed", __FUNCTION__, idArtist);
  642. }
  643. return false;
  644. };
  645. bool CMusicDatabase::GetArtistsBySong(int idSong, bool includeFeatured, std::vector<long> &artists)
  646. {
  647. try
  648. {
  649. CStdString strSQL, strPrepSQL;
  650. strPrepSQL = "select idArtist from song_artist where idSong=%i";
  651. if (includeFeatured == false)
  652. strPrepSQL += " AND boolFeatured = 0";
  653. strSQL=PrepareSQL(strPrepSQL, idSong);
  654. if (!m_pDS->query(strSQL.c_str()))
  655. return false;
  656. if (m_pDS->num_rows() == 0)
  657. {
  658. m_pDS->close();
  659. return false;
  660. }
  661. while (!m_pDS->eof())
  662. {
  663. artists.push_back(m_pDS->fv("idArtist").get_asInt());
  664. m_pDS->next();
  665. }
  666. m_pDS->close();
  667. return true;
  668. }
  669. catch (...)
  670. {
  671. CLog::Log(LOGERROR, "%s(%i) failed", __FUNCTION__, idSong);
  672. }
  673. return false;
  674. };
  675. int CMusicDatabase::AddPath(const CStdString& strPath1)
  676. {
  677. CStdString strSQL;
  678. try
  679. {
  680. CStdString strPath(strPath1);
  681. if (!URIUtils::HasSlashAtEnd(strPath))
  682. URIUtils::AddSlashAtEnd(strPath);
  683. if (NULL == m_pDB.get()) return -1;
  684. if (NULL == m_pDS.get()) return -1;
  685. map <CStdString, int>::const_iterator it;
  686. it = m_pathCache.find(strPath);
  687. if (it != m_pathCache.end())
  688. return it->second;
  689. strSQL=PrepareSQL( "select * from path where strPath='%s'", strPath.c_str());
  690. m_pDS->query(strSQL.c_str());
  691. if (m_pDS->num_rows() == 0)
  692. {
  693. m_pDS->close();
  694. // doesnt exists, add it
  695. strSQL=PrepareSQL("insert into path (idPath, strPath) values( NULL, '%s' )", strPath.c_str());
  696. m_pDS->exec(strSQL.c_str());
  697. int idPath = (int)m_pDS->lastinsertid();
  698. m_pathCache.insert(pair<CStdString, int>(strPath, idPath));
  699. return idPath;
  700. }
  701. else
  702. {
  703. int idPath = m_pDS->fv("idPath").get_asInt();
  704. m_pathCache.insert(pair<CStdString, int>(strPath, idPath));
  705. m_pDS->close();
  706. return idPath;
  707. }
  708. }
  709. catch (...)
  710. {
  711. CLog::Log(LOGERROR, "musicdatabase:unable to addpath (%s)", strSQL.c_str());
  712. }
  713. return -1;
  714. }
  715. CSong CMusicDatabase::GetSongFromDataset(bool bWithMusicDbPath/*=false*/)
  716. {
  717. CSong song;
  718. song.idSong = m_pDS->fv(song_idSong).get_asInt();
  719. // get the full artist string
  720. song.artist = StringUtils::Split(m_pDS->fv(song_strArtists).get_asString(), g_advancedSettings.m_musicItemSeparator);
  721. // and the full genre string
  722. song.genre = StringUtils::Split(m_pDS->fv(song_strGenres).get_asString(), g_advancedSettings.m_musicItemSeparator);
  723. // and the rest...
  724. song.strAlbum = m_pDS->fv(song_strAlbum).get_asString();
  725. song.iAlbumId = m_pDS->fv(song_idAlbum).get_asInt();
  726. song.iTrack = m_pDS->fv(song_iTrack).get_asInt() ;
  727. song.iDuration = m_pDS->fv(song_iDuration).get_asInt() ;
  728. song.iYear = m_pDS->fv(song_iYear).get_asInt() ;
  729. song.strTitle = m_pDS->fv(song_strTitle).get_asString();
  730. song.iTimesPlayed = m_pDS->fv(song_iTimesPlayed).get_asInt();
  731. song.lastPlayed.SetFromDBDateTime(m_pDS->fv(song_lastplayed).get_asString());
  732. song.iStartOffset = m_pDS->fv(song_iStartOffset).get_asInt();
  733. song.iEndOffset = m_pDS->fv(song_iEndOffset).get_asInt();
  734. song.strMusicBrainzTrackID = m_pDS->fv(song_strMusicBrainzTrackID).get_asString();
  735. song.strMusicBrainzArtistID = m_pDS->fv(song_strMusicBrainzArtistID).get_asString();
  736. song.strMusicBrainzAlbumID = m_pDS->fv(song_strMusicBrainzAlbumID).get_asString();
  737. song.strMusicBrainzAlbumArtistID = m_pDS->fv(song_strMusicBrainzAlbumArtistID).get_asString();
  738. song.strMusicBrainzTRMID = m_pDS->fv(song_strMusicBrainzTRMID).get_asString();
  739. song.rating = m_pDS->fv(song_rating).get_asChar();
  740. song.strComment = m_pDS->fv(song_comment).get_asString();
  741. song.iKaraokeNumber = m_pDS->fv(song_iKarNumber).get_asInt();
  742. song.strKaraokeLyrEncoding = m_pDS->fv(song_strKarEncoding).get_asString();
  743. song.iKaraokeDelay = m_pDS->fv(song_iKarDelay).get_asInt();
  744. song.bCompilation = m_pDS->fv(song_bCompilation).get_asInt() == 1;
  745. // Get filename with full path
  746. if (!bWithMusicDbPath)
  747. URIUtils::AddFileToFolder(m_pDS->fv(song_strPath).get_asString(), m_pDS->fv(song_strFileName).get_asString(), song.strFileName);
  748. else
  749. {
  750. CStdString strFileName=m_pDS->fv(song_strFileName).get_asString();
  751. CStdString strExt=URIUtils::GetExtension(strFileName);
  752. song.strFileName.Format("musicdb://3/%ld/%ld%s", m_pDS->fv(song_idAlbum).get_asInt(), m_pDS->fv(song_idSong).get_asInt(), strExt.c_str());
  753. }
  754. return song;
  755. }
  756. void CMusicDatabase::GetFileItemFromDataset(CFileItem* item, const CStdString& strMusicDBbasePath)
  757. {
  758. return GetFileItemFromDataset(m_pDS->get_sql_record(), item, strMusicDBbasePath);
  759. }
  760. void CMusicDatabase::GetFileItemFromDataset(const dbiplus::sql_record* const record, CFileItem* item, const CStdString& strMusicDBbasePath)
  761. {
  762. // get the full artist string
  763. item->GetMusicInfoTag()->SetArtist(StringUtils::Split(record->at(song_strArtists).get_asString(), g_advancedSettings.m_musicItemSeparator));
  764. // and the full genre string
  765. item->GetMusicInfoTag()->SetGenre(record->at(song_strGenres).get_asString());
  766. // and the rest...
  767. item->GetMusicInfoTag()->SetAlbum(record->at(song_strAlbum).get_asString());
  768. item->GetMusicInfoTag()->SetAlbumId(record->at(song_idAlbum).get_asInt());
  769. item->GetMusicInfoTag()->SetTrackAndDiskNumber(record->at(song_iTrack).get_asInt());
  770. item->GetMusicInfoTag()->SetDuration(record->at(song_iDuration).get_asInt());
  771. item->GetMusicInfoTag()->SetDatabaseId(record->at(song_idSong).get_asInt(), "song");
  772. SYSTEMTIME stTime;
  773. stTime.wYear = (WORD)record->at(song_iYear).get_asInt();
  774. item->GetMusicInfoTag()->SetReleaseDate(stTime);
  775. item->GetMusicInfoTag()->SetTitle(record->at(song_strTitle).get_asString());
  776. item->SetLabel(record->at(song_strTitle).get_asString());
  777. item->m_lStartOffset = record->at(song_iStartOffset).get_asInt();
  778. item->SetProperty("item_start", item->m_lStartOffset);
  779. item->m_lEndOffset = record->at(song_iEndOffset).get_asInt();
  780. item->GetMusicInfoTag()->SetMusicBrainzTrackID(record->at(song_strMusicBrainzTrackID).get_asString());
  781. item->GetMusicInfoTag()->SetMusicBrainzArtistID(record->at(song_strMusicBrainzArtistID).get_asString());
  782. item->GetMusicInfoTag()->SetMusicBrainzAlbumID(record->at(song_strMusicBrainzAlbumID).get_asString());
  783. item->GetMusicInfoTag()->SetMusicBrainzAlbumArtistID(record->at(song_strMusicBrainzAlbumArtistID).get_asString());
  784. item->GetMusicInfoTag()->SetMusicBrainzTRMID(record->at(song_strMusicBrainzTRMID).get_asString());
  785. item->GetMusicInfoTag()->SetRating(record->at(song_rating).get_asChar());
  786. item->GetMusicInfoTag()->SetComment(record->at(song_comment).get_asString());
  787. item->GetMusicInfoTag()->SetPlayCount(record->at(song_iTimesPlayed).get_asInt());
  788. item->GetMusicInfoTag()->SetLastPlayed(record->at(song_lastplayed).get_asString());
  789. CStdString strRealPath;
  790. URIUtils::AddFileToFolder(record->at(song_strPath).get_asString(), record->at(song_strFileName).get_asString(), strRealPath);
  791. item->GetMusicInfoTag()->SetURL(strRealPath);
  792. item->GetMusicInfoTag()->SetCompilation(m_pDS->fv(song_bCompilation).get_asInt() == 1);
  793. item->GetMusicInfoTag()->SetLoaded(true);
  794. // Get filename with full path
  795. if (strMusicDBbasePath.IsEmpty())
  796. item->SetPath(strRealPath);
  797. else
  798. {
  799. CStdString strFileName = record->at(song_strFileName).get_asString();
  800. CStdString strExt = URIUtils::GetExtension(strFileName);
  801. CStdString path; path.Format("%s%ld%s", strMusicDBbasePath.c_str(), record->at(song_idSong).get_asInt(), strExt.c_str());
  802. item->SetPath(path);
  803. }
  804. }
  805. CAlbum CMusicDatabase::GetAlbumFromDataset(dbiplus::Dataset* pDS, bool imageURL /* = false*/)
  806. {
  807. return GetAlbumFromDataset(pDS->get_sql_record(), imageURL);
  808. }
  809. CAlbum CMusicDatabase::GetAlbumFromDataset(const dbiplus::sql_record* const record, bool imageURL /* = false*/)
  810. {
  811. CAlbum album;
  812. album.idAlbum = record->at(album_idAlbum).get_asInt();
  813. album.strAlbum = record->at(album_strAlbum).get_asString();
  814. if (album.strAlbum.IsEmpty())
  815. album.strAlbum = g_localizeStrings.Get(1050);
  816. album.artist = StringUtils::Split(record->at(album_strArtists).get_asString(), g_advancedSettings.m_musicItemSeparator);
  817. album.genre = StringUtils::Split(record->at(album_strGenres).get_asString(), g_advancedSettings.m_musicItemSeparator);
  818. album.iYear = record->at(album_iYear).get_asInt();
  819. if (imageURL)
  820. album.thumbURL.ParseString(record->at(album_strThumbURL).get_asString());
  821. album.iRating = record->at(album_iRating).get_asInt();
  822. album.iYear = record->at(album_iYear).get_asInt();
  823. album.strReview = record->at(album_strReview).get_asString();
  824. album.styles = StringUtils::Split(record->at(album_strStyles).get_asString(), g_advancedSettings.m_musicItemSeparator);
  825. album.moods = StringUtils::Split(record->at(album_strMoods).get_asString(), g_advancedSettings.m_musicItemSeparator);
  826. album.themes = StringUtils::Split(record->at(album_strThemes).get_asString(), g_advancedSettings.m_musicItemSeparator);
  827. album.strLabel = record->at(album_strLabel).get_asString();
  828. album.strType = record->at(album_strType).get_asString();
  829. album.bCompilation = record->at(album_bCompilation).get_asInt() == 1;
  830. return album;
  831. }
  832. CArtist CMusicDatabase::GetArtistFromDataset(dbiplus::Dataset* pDS, bool needThumb)
  833. {
  834. CArtist artist;
  835. artist.idArtist = pDS->fv(artist_idArtist).get_asInt();
  836. artist.strArtist = pDS->fv(artist_strArtist).get_asString();
  837. artist.genre = StringUtils::Split(pDS->fv(artist_strGenres).get_asString(), g_advancedSettings.m_musicItemSeparator);
  838. artist.strBiography = pDS->fv(artist_strBiography).get_asString();
  839. artist.styles = StringUtils::Split(pDS->fv(artist_strStyles).get_asString(), g_advancedSettings.m_musicItemSeparator);
  840. artist.moods = StringUtils::Split(pDS->fv(artist_strMoods).get_asString(), g_advancedSettings.m_musicItemSeparator);
  841. artist.strBorn = pDS->fv(artist_strBorn).get_asString();
  842. artist.strFormed = pDS->fv(artist_strFormed).get_asString();
  843. artist.strDied = pDS->fv(artist_strDied).get_asString();
  844. artist.strDisbanded = pDS->fv(artist_strDisbanded).get_asString();
  845. artist.yearsActive = StringUtils::Split(pDS->fv(artist_strYearsActive).get_asString(), g_advancedSettings.m_musicItemSeparator);
  846. artist.instruments = StringUtils::Split(pDS->fv(artist_strInstruments).get_asString(), g_advancedSettings.m_musicItemSeparator);
  847. if (needThumb)
  848. {
  849. artist.fanart.m_xml = pDS->fv(artist_strFanart).get_asString();
  850. artist.fanart.Unpack();
  851. artist.thumbURL.ParseString(pDS->fv(artist_strImage).get_asString());
  852. }
  853. return artist;
  854. }
  855. bool CMusicDatabase::GetSongByFileName(const CStdString& strFileName, CSong& song, int startOffset)
  856. {
  857. try
  858. {
  859. song.Clear();
  860. CURL url(strFileName);
  861. if (url.GetProtocol()=="musicdb")
  862. {
  863. CStdString strFile = URIUtils::GetFileName(strFileName);
  864. URIUtils::RemoveExtension(strFile);
  865. return GetSongById(atol(strFile.c_str()), song);
  866. }
  867. CStdString strPath;
  868. URIUtils::GetDirectory(strFileName, strPath);
  869. URIUtils::AddSlashAtEnd(strPath);
  870. if (NULL == m_pDB.get()) return false;
  871. if (NULL == m_pDS.get()) return false;
  872. DWORD crc = ComputeCRC(strFileName);
  873. CStdString strSQL=PrepareSQL("select * from songview "
  874. "where dwFileNameCRC='%ul' and strPath='%s'"
  875. , crc,
  876. strPath.c_str());
  877. if (startOffset)
  878. strSQL += PrepareSQL(" AND iStartOffset=%i", startOffset);
  879. if (!m_pDS->query(strSQL.c_str())) return false;
  880. int iRowsFound = m_pDS->num_rows();
  881. if (iRowsFound == 0)
  882. {
  883. m_pDS->close();
  884. return false;
  885. }
  886. song = GetSongFromDataset();
  887. m_pDS->close(); // cleanup recordset data
  888. return true;
  889. }
  890. catch (...)
  891. {
  892. CLog::Log(LOGERROR, "%s(%s) failed", __FUNCTION__, strFileName.c_str());
  893. }
  894. return false;
  895. }
  896. int CMusicDatabase::GetAlbumIdByPath(const CStdString& strPath)
  897. {
  898. try
  899. {
  900. CStdString strSQL=PrepareSQL("select distinct idAlbum from song join path on song.idPath = path.idPath where path.strPath='%s'", strPath.c_str());
  901. m_pDS->query(strSQL.c_str());
  902. if (m_pDS->eof())
  903. return -1;
  904. int idAlbum = m_pDS->fv(0).get_asInt();
  905. m_pDS->close();
  906. return idAlbum;
  907. }
  908. catch (...)
  909. {
  910. CLog::Log(LOGERROR, "%s(%s) failed", __FUNCTION__, strPath.c_str());
  911. }
  912. return false;
  913. }
  914. int CMusicDatabase::GetSongByArtistAndAlbumAndTitle(const CStdString& strArtist, const CStdString& strAlbum, const CStdString& strTitle)
  915. {
  916. try
  917. {
  918. CStdString strSQL=PrepareSQL("select idSong from songview "
  919. "where strArtist like '%s' and strAlbum like '%s' and "
  920. "strTitle like '%s'",strArtist.c_str(),strAlbum.c_str(),strTitle.c_str());
  921. if (!m_pDS->query(strSQL.c_str())) return false;
  922. int iRowsFound = m_pDS->num_rows();
  923. if (iRowsFound == 0)
  924. {
  925. m_pDS->close();
  926. return -1;
  927. }
  928. int lResult = m_pDS->fv(0).get_asInt();
  929. m_pDS->close(); // cleanup recordset data
  930. return lResult;
  931. }
  932. catch (...)
  933. {
  934. CLog::Log(LOGERROR, "%s (%s,%s,%s) failed", __FUNCTION__, strArtist.c_str(),strAlbum.c_str(),strTitle.c_str());
  935. }
  936. return -1;
  937. }
  938. bool CMusicDatabase::GetSongById(int idSong, CSong& song)
  939. {
  940. try
  941. {
  942. song.Clear();
  943. if (NULL == m_pDB.get()) return false;
  944. if (NULL == m_pDS.get()) return false;
  945. CStdString strSQL=PrepareSQL("select * from songview "
  946. "where idSong=%i"
  947. , idSong);
  948. if (!m_pDS->query(strSQL.c_str())) return false;
  949. int iRowsFound = m_pDS->num_rows();
  950. if (iRowsFound == 0)
  951. {
  952. m_pDS->close();
  953. return false;
  954. }
  955. song = GetSongFromDataset();
  956. m_pDS->close(); // cleanup recordset data
  957. return true;
  958. }
  959. catch (...)
  960. {
  961. CLog::Log(LOGERROR, "%s(%i) failed", __FUNCTION__, idSong);
  962. }
  963. return false;
  964. }
  965. bool CMusicDatabase::SearchArtists(const CStdString& search, CFileItemList &artists)
  966. {
  967. try
  968. {
  969. if (NULL == m_pDB.get()) return false;
  970. if (NULL == m_pDS.get()) return false;
  971. // Exclude "Various Artists"
  972. int idVariousArtist = AddArtist(g_localizeStrings.Get(340));
  973. CStdString strSQL;
  974. if (search.GetLength() >= MIN_FULL_SEARCH_LENGTH)
  975. strSQL=PrepareSQL("select * from artist "
  976. "where (strArtist like '%s%%' or strArtist like '%% %s%%') and idArtist <> %i "
  977. , search.c_str(), search.c_str(), idVariousArtist );
  978. else
  979. strSQL=PrepareSQL("select * from artist "
  980. "where strArtist like '%s%%' and idArtist <> %i "
  981. , search.c_str(), idVariousArtist );
  982. if (!m_pDS->query(strSQL.c_str())) return false;
  983. if (m_pDS->num_rows() == 0)
  984. {
  985. m_pDS->close();
  986. return false;
  987. }
  988. CStdString artistLabel(g_localizeStrings.Get(557)); // Artist
  989. while (!m_pDS->eof())
  990. {
  991. CStdString path;
  992. path.Format("musicdb://2/%ld/", m_pDS->fv(0).get_asInt());
  993. CFileItemPtr pItem(new CFileItem(path, true));
  994. CStdString label;
  995. label.Format("[%s] %s", artistLabel.c_str(), m_pDS->fv(1).get_asString());
  996. pItem->SetLabel(label);
  997. label.Format("A %s", m_pDS->fv(1).get_asString()); // sort label is stored in the title tag
  998. pItem->GetMusicInfoTag()->SetTitle(label);
  999. pItem->GetMusicInfoTag()->SetDatabaseId(m_pDS->fv(0).get_asInt(), "artist");
  1000. artists.Add(pItem);
  1001. m_pDS->next();
  1002. }
  1003. m_pDS->close(); // cleanup recordset data
  1004. return true;
  1005. }
  1006. catch (...)
  1007. {
  1008. CLog::Log(LOGERROR, "%s failed", __FUNCTION__);
  1009. }
  1010. return false;
  1011. }
  1012. bool CMusicDatabase::GetArbitraryQuery(const CStdString& strQuery, const CStdString& strOpenRecordSet, const CStdString& strCloseRecordSet,
  1013. const CStdString& strOpenRecord, const CStdString& strCloseRecord, const CStdString& strOpenField,
  1014. const CStdString& strCloseField, CStdString& strResult)
  1015. {
  1016. try
  1017. {
  1018. strResult = "";
  1019. if (NULL == m_pDB.get()) return false;
  1020. if (NULL == m_pDS.get()) return false;
  1021. CStdString strSQL=strQuery;
  1022. if (!m_pDS->query(strSQL.c_str()))
  1023. {
  1024. strResult = m_pDB->getErrorMsg();
  1025. return false;
  1026. }
  1027. strResult=strOpenRecordSet;
  1028. while (!m_pDS->eof())
  1029. {
  1030. strResult += strOpenRecord;
  1031. for (int i=0; i<m_pDS->fieldCount(); i++)
  1032. {
  1033. strResult += strOpenField;
  1034. strResult += m_pDS->fv(i).get_asString();
  1035. strResult += strCloseField;
  1036. }
  1037. strResult += strCloseRecord;
  1038. m_pDS->next();
  1039. }
  1040. strResult += strCloseRecordSet;
  1041. m_pDS->close();
  1042. return true;
  1043. }
  1044. catch (...)
  1045. {
  1046. CLog::Log(LOGERROR, "%s(%s) failed", __FUNCTION__, strQuery.c_str());
  1047. }
  1048. try
  1049. {
  1050. if (NULL == m_pDB.get()) return false;
  1051. strResult = m_pDB->getErrorMsg();
  1052. }
  1053. catch (...)
  1054. {
  1055. }
  1056. return false;
  1057. }
  1058. bool CMusicDatabase::ArbitraryExec(const CStdString& strExec)
  1059. {
  1060. try
  1061. {
  1062. if (NULL == m_pDB.get()) return false;
  1063. if (NULL == m_pDS.get()) return false;
  1064. CStdString strSQL = strExec;
  1065. m_pDS->exec(strSQL.c_str());
  1066. m_pDS->close();
  1067. return true;
  1068. }
  1069. catch (...)
  1070. {
  1071. CLog::Log(LOGERROR, "%s failed", __FUNCTION__);
  1072. }
  1073. return false;
  1074. }
  1075. bool CMusicDatabase::GetAlbumInfo(int idAlbum, CAlbum &info, VECSONGS* songs)
  1076. {
  1077. try
  1078. {
  1079. if (idAlbum == -1)
  1080. return false; // not in the database
  1081. CStdString strSQL=PrepareSQL("select * from albumview where idAlbum = %ld", idAlbum);
  1082. if (!m_pDS2->query(strSQL.c_str())) return false;
  1083. int iRowsFound = m_pDS2->num_rows();
  1084. if (iRowsFound != 0)
  1085. {
  1086. info = GetAlbumFromDataset(m_pDS2.get(), true); // true to grab the thumburl rather than the thumb
  1087. int idAlbumInfo = m_pDS2->fv(album_idAlbumInfo).get_asInt();
  1088. m_pDS2->close(); // cleanup recordset data
  1089. if (songs)
  1090. GetAlbumInfoSongs(idAlbumInfo, *songs);
  1091. return true;
  1092. }
  1093. m_pDS2->close();
  1094. return false;
  1095. }
  1096. catch (...)
  1097. {
  1098. CLog::Log(LOGERROR, "%s(%i) failed", __FUNCTION__, idAlbum);
  1099. }
  1100. return false;
  1101. }
  1102. bool CMusicDatabase::HasAlbumInfo(int idAlbum)
  1103. {
  1104. try
  1105. {
  1106. if (idAlbum == -1)
  1107. return false; // not in the database
  1108. CStdString strSQL=PrepareSQL("select * from albuminfo where idAlbum = %ld", idAlbum);
  1109. if (!m_pDS2->query(strSQL.c_str())) return false;
  1110. int iRowsFound = m_pDS2->num_rows();
  1111. m_pDS2->close();
  1112. return iRowsFound > 0;
  1113. }
  1114. catch (...)
  1115. {
  1116. CLog::Log(LOGERROR, "%s(%i) failed", __FUNCTION__, idAlbum);
  1117. }
  1118. return false;
  1119. }
  1120. bool CMusicDatabase::DeleteAlbumInfo(int idAlbum)
  1121. {
  1122. try
  1123. {
  1124. if (idAlbum == -1)
  1125. return false; // not in the database
  1126. CStdString strSQL = PrepareSQL("delete from albuminfo where idAlbum=%i",idAlbum);
  1127. if (!m_pDS2->exec(strSQL.c_str()))
  1128. return false;
  1129. return true;
  1130. }
  1131. catch (...)
  1132. {
  1133. CLog::Log(LOGERROR, "%s - (%i) failed", __FUNCTION__, idAlbum);
  1134. }
  1135. return false;
  1136. }
  1137. bool CMusicDatabase::GetArtistInfo(int idArtist, CArtist &info, bool needAll)
  1138. {
  1139. try
  1140. {
  1141. if (idArtist == -1)
  1142. return false; // not in the database
  1143. CStdString strSQL=PrepareSQL("SELECT artist.idArtist AS idArtist, strArtist, "
  1144. " strBorn, strFormed, strGenres,"
  1145. " strMoods, strStyles, strInstruments, "
  1146. " strBiography, strDied, strDisbanded, "
  1147. " strYearsActive, strImage, strFanart "
  1148. " FROM artist "
  1149. " JOIN artistinfo "
  1150. " ON artist.idArtist = artistinfo.idArtist "
  1151. " WHERE artistinfo.idArtist = %i"
  1152. , idArtist);
  1153. if (!m_pDS2->query(strSQL.c_str())) return false;
  1154. int iRowsFound = m_pDS2->num_rows();
  1155. if (iRowsFound != 0)
  1156. {
  1157. info = GetArtistFromDataset(m_pDS2.get(),needAll);
  1158. if (needAll)
  1159. {
  1160. strSQL=PrepareSQL("select * from discography where idArtist=%i",idArtist);
  1161. m_pDS2->query(strSQL.c_str());
  1162. while (!m_pDS2->eof())
  1163. {
  1164. info.discography.push_back(make_pair(m_pDS2->fv("strAlbum").get_asString(),m_pDS2->fv("strYear").get_asString()));
  1165. m_pDS2->next();
  1166. }
  1167. }
  1168. m_pDS2->close(); // cleanup recordset data
  1169. return true;
  1170. }
  1171. m_pDS2->close();
  1172. return false;
  1173. }
  1174. catch (...)
  1175. {
  1176. CLog::Log(LOGERROR, "%s - (%i) failed", __FUNCTION__, idArtist);
  1177. }
  1178. return false;
  1179. }
  1180. bool CMusicDatabase::DeleteArtistInfo(int idArtist)
  1181. {
  1182. try
  1183. {
  1184. if (idArtist == -1)
  1185. return false; // not in the database
  1186. CStdString strSQL = PrepareSQL("delete from artistinfo where idArtist=%i",idArtist);
  1187. if (!m_pDS2->exec(strSQL.c_str()))
  1188. return false;
  1189. return true;
  1190. }
  1191. catch (...)
  1192. {
  1193. CLog::Log(LOGERROR, "%s - (%i) failed", __FUNCTION__, idArtist);
  1194. }
  1195. return false;
  1196. }
  1197. bool CMusicDatabase::GetAlbumInfoSongs(int idAlbumInfo, VECSONGS& songs)
  1198. {
  1199. try
  1200. {
  1201. CStdString strSQL=PrepareSQL("select * from albuminfosong "
  1202. "where idAlbumInfo=%i "
  1203. "order by iTrack", idAlbumInfo);
  1204. if (!m_pDS2->query(strSQL.c_str())) return false;
  1205. int iRowsFound = m_pDS2->num_rows();
  1206. if (iRowsFound == 0) return false;
  1207. while (!m_pDS2->eof())
  1208. {
  1209. CSong song;
  1210. song.iTrack = m_pDS2->fv("iTrack").get_asInt();
  1211. song.strTitle = m_pDS2->fv("strTitle").get_asString();
  1212. song.iDuration = m_pDS2->fv("iDuration").get_asInt();
  1213. songs.push_back(song);
  1214. m_pDS2->next();
  1215. }
  1216. m_pDS2->close(); // cleanup recordset data
  1217. return true;
  1218. }
  1219. catch (...)
  1220. {
  1221. CLog::Log(LOGERROR, "%s(%i) failed", __FUNCTION__, idAlbumInfo);
  1222. }
  1223. return false;
  1224. }
  1225. bool CMusicDatabase::GetTop100(const CStdString& strBaseDir, CFileItemList& items)
  1226. {
  1227. try
  1228. {
  1229. if (NULL == m_pDB.get()) return false;
  1230. if (NULL == m_pDS.get()) return false;
  1231. CStdString strSQL="select * from songview "
  1232. "where iTimesPlayed>0 "
  1233. "order by iTimesPlayed desc "
  1234. "limit 100";
  1235. CLog::Log(LOGDEBUG, "%s query: %…

Large files files are truncated, but you can click here to view the full file