aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xlanguage/English/strings.po14
-rw-r--r--system/settings/settings.xml5
-rw-r--r--xbmc/interfaces/json-rpc/AudioLibrary.cpp15
-rw-r--r--xbmc/music/Album.cpp62
-rw-r--r--xbmc/music/Album.h5
-rw-r--r--xbmc/music/Artist.cpp28
-rw-r--r--xbmc/music/Artist.h4
-rw-r--r--xbmc/music/MusicDatabase.cpp1725
-rw-r--r--xbmc/music/MusicDatabase.h170
-rw-r--r--xbmc/music/MusicInfoLoader.cpp4
-rw-r--r--xbmc/music/Song.cpp13
-rw-r--r--xbmc/music/Song.h1
-rw-r--r--xbmc/music/dialogs/GUIDialogMusicInfo.cpp25
-rw-r--r--xbmc/music/infoscanner/MusicAlbumInfo.h2
-rw-r--r--xbmc/music/infoscanner/MusicInfoScanner.cpp332
-rw-r--r--xbmc/music/infoscanner/MusicInfoScanner.h28
-rw-r--r--xbmc/music/windows/GUIWindowMusicBase.cpp42
-rw-r--r--xbmc/music/windows/GUIWindowMusicNav.cpp4
-rw-r--r--xbmc/network/upnp/UPnPServer.cpp4
19 files changed, 1418 insertions, 1065 deletions
diff --git a/language/English/strings.po b/language/English/strings.po
index 504bd77a42..80c02aadca 100755
--- a/language/English/strings.po
+++ b/language/English/strings.po
@@ -9635,8 +9635,20 @@ msgctxt "#20199"
msgid "Downloading artist info failed"
msgstr ""
-#empty strings from id 20200 to 20239
#string id's 20200 thru 20211 are reserved for speedstrings (LocalizeStrings.cpp)
+#empty strings from id 20212 to 20219
+
+#: system/settings/settings.xml
+msgctxt "#20220"
+msgid "Override song tags with online information"
+msgstr ""
+
+#: system/settings/settings.xml
+msgctxt "#20221"
+msgid "With this enabled, any information that is downloaded for albums and artists will override anything you have set in your song tags, such as genres, year, song artists etc. Useful if you have MusicBrainz identifiers in your song tags."
+msgstr ""
+
+#empty strings from id 20222 to 20239
#: xbmc/dialogs/GUIDialogMediaSource.cpp
msgctxt "#20240"
diff --git a/system/settings/settings.xml b/system/settings/settings.xml
index ab1d267438..799fe161e8 100644
--- a/system/settings/settings.xml
+++ b/system/settings/settings.xml
@@ -1312,6 +1312,11 @@
</constraints>
<control type="button" format="addon" />
</setting>
+ <setting id="musiclibrary.overridetags" type="boolean" label="20220" help="20221">
+ <level>1</level>
+ <default>false</default>
+ <control type="toggle" />
+ </setting>
<setting id="musiclibrary.updateonstartup" type="boolean" label="22000" help="36259">
<level>1</level>
<default>false</default>
diff --git a/xbmc/interfaces/json-rpc/AudioLibrary.cpp b/xbmc/interfaces/json-rpc/AudioLibrary.cpp
index bbc5c0daa4..3c030f0666 100644
--- a/xbmc/interfaces/json-rpc/AudioLibrary.cpp
+++ b/xbmc/interfaces/json-rpc/AudioLibrary.cpp
@@ -179,7 +179,7 @@ JSONRPC_STATUS CAudioLibrary::GetAlbumDetails(const CStdString &method, ITranspo
return InternalError;
CAlbum album;
- if (!musicdatabase.GetAlbumInfo(albumID, album, NULL))
+ if (!musicdatabase.GetAlbum(albumID, album, false))
return InvalidParams;
CStdString path;
@@ -397,7 +397,7 @@ JSONRPC_STATUS CAudioLibrary::SetArtistDetails(const CStdString &method, ITransp
return InternalError;
CArtist artist;
- if (!musicdatabase.GetArtistInfo(id, artist) || artist.idArtist <= 0)
+ if (!musicdatabase.GetArtist(id, artist) || artist.idArtist <= 0)
return InvalidParams;
if (ParameterNotNull(parameterObject, "artist"))
@@ -423,7 +423,7 @@ JSONRPC_STATUS CAudioLibrary::SetArtistDetails(const CStdString &method, ITransp
if (ParameterNotNull(parameterObject, "yearsactive"))
CopyStringArray(parameterObject["yearsactive"], artist.yearsActive);
- if (musicdatabase.SetArtistInfo(id, artist) <= 0)
+ if (musicdatabase.UpdateArtist(artist) <= 0)
return InternalError;
CJSONRPCUtils::NotifyItemUpdated();
@@ -439,8 +439,7 @@ JSONRPC_STATUS CAudioLibrary::SetAlbumDetails(const CStdString &method, ITranspo
return InternalError;
CAlbum album;
- VECSONGS songs;
- if (!musicdatabase.GetAlbumInfo(id, album, &songs) || album.idAlbum <= 0)
+ if (!musicdatabase.GetAlbum(id, album) || album.idAlbum <= 0)
return InvalidParams;
if (ParameterNotNull(parameterObject, "title"))
@@ -466,7 +465,7 @@ JSONRPC_STATUS CAudioLibrary::SetAlbumDetails(const CStdString &method, ITranspo
if (ParameterNotNull(parameterObject, "year"))
album.iYear = (int)parameterObject["year"].asInteger();
- if (musicdatabase.SetAlbumInfo(id, album, songs) <= 0)
+ if (musicdatabase.UpdateAlbum(album) <= 0)
return InternalError;
CJSONRPCUtils::NotifyItemUpdated();
@@ -510,7 +509,7 @@ JSONRPC_STATUS CAudioLibrary::SetSongDetails(const CStdString &method, ITranspor
if (ParameterNotNull(parameterObject, "musicbrainztrackid"))
song.strMusicBrainzTrackID = parameterObject["musicbrainztrackid"].asString();
- if (musicdatabase.UpdateSong(id, song.strTitle, song.strMusicBrainzTrackID, song.strFileName, song.strComment, song.strThumb, song.artist, song.genre, song.iTrack, song.iDuration, song.iYear, song.iTimesPlayed, song.iStartOffset, song.iEndOffset, song.lastPlayed, song.rating, song.iKaraokeNumber) <= 0)
+ if (musicdatabase.UpdateSong(id, song) <= 0)
return InternalError;
CJSONRPCUtils::NotifyItemUpdated();
@@ -563,7 +562,7 @@ bool CAudioLibrary::FillFileItem(const CStdString &strFilename, CFileItemPtr &it
{
CAlbum album;
int albumid = musicdatabase.GetAlbumIdByPath(strFilename);
- if (musicdatabase.GetAlbumInfo(albumid, album, NULL))
+ if (musicdatabase.GetAlbum(albumid, album, false))
{
item->SetFromAlbum(album);
diff --git a/xbmc/music/Album.cpp b/xbmc/music/Album.cpp
index 3580901f7d..66d1b2524e 100644
--- a/xbmc/music/Album.cpp
+++ b/xbmc/music/Album.cpp
@@ -53,6 +53,60 @@ CAlbum::CAlbum(const CFileItem& item)
iTimesPlayed = 0;
}
+void CAlbum::MergeScrapedAlbum(const CAlbum& source, bool override /* = true */)
+{
+ /*
+ We don't merge musicbrainz album ID so that a refresh of album information
+ allows a lookup based on name rather than directly (re)using musicbrainz.
+ In future, we may wish to be able to override lookup by musicbrainz so
+ this might be dropped.
+ */
+// strMusicBrainzAlbumID = source.strMusicBrainzAlbumID;
+ if ((override && !source.genre.empty()) || genre.empty())
+ genre = source.genre;
+ if ((override && !source.strAlbum.empty()) || strAlbum.empty())
+ strAlbum = source.strAlbum;
+ if ((override && source.iYear > 0) || iYear == 0)
+ iYear = source.iYear;
+ if (override)
+ bCompilation = source.bCompilation;
+ // iTimesPlayed = source.iTimesPlayed; // times played is derived from songs
+ for (std::map<std::string, std::string>::const_iterator i = source.art.begin(); i != source.art.end(); ++i)
+ {
+ if (override || art.find(i->first) == art.end())
+ art[i->first] = i->second;
+ }
+ strLabel = source.strLabel;
+ thumbURL = source.thumbURL;
+ moods = source.moods;
+ styles = source.styles;
+ themes = source.themes;
+ strReview = source.strReview;
+ strType = source.strType;
+// strPath = source.strPath; // don't merge the path
+ m_strDateOfRelease = source.m_strDateOfRelease;
+ iRating = source.iRating;
+ if (override)
+ {
+ artistCredits = source.artistCredits;
+ artist = source.artist; // artist information is read-only from the database. artistCredits is what counts on scan
+ }
+ else if (source.artistCredits.size() > artistCredits.size())
+ artistCredits.insert(artistCredits.end(), source.artistCredits.begin()+artistCredits.size(), source.artistCredits.end());
+ if (!strMusicBrainzAlbumID.empty())
+ {
+ /* update local songs with MB information */
+ for (VECSONGS::iterator song = songs.begin(); song != songs.end(); ++song)
+ {
+ if (!song->strMusicBrainzTrackID.empty())
+ for (VECSONGS::const_iterator sourceSong = source.infoSongs.begin(); sourceSong != source.infoSongs.end(); ++sourceSong)
+ if (sourceSong->strMusicBrainzTrackID == song->strMusicBrainzTrackID)
+ song->MergeScrapedSong(*sourceSong, override);
+ }
+ }
+ infoSongs = source.infoSongs;
+}
+
CStdString CAlbum::GetArtistString() const
{
return StringUtils::Join(artist, g_advancedSettings.m_musicItemSeparator);
@@ -173,7 +227,7 @@ bool CAlbum::Load(const TiXmlElement *album, bool append, bool prioritise)
const TiXmlElement* node = album->FirstChildElement("track");
if (node)
- songs.clear(); // this means that the tracks can't be spread over separate pages
+ infoSongs.clear(); // this means that the tracks can't be spread over separate pages
// but this is probably a reasonable limitation
bool bIncrement = false;
while (node)
@@ -198,7 +252,7 @@ bool CAlbum::Load(const TiXmlElement *album, bool append, bool prioritise)
song.artistCredits.push_back(artistCredit);
}
- songArtistCreditsNode = songArtistCreditsNode->NextSiblingElement("albumArtistCredits");
+ songArtistCreditsNode = songArtistCreditsNode->NextSiblingElement("songArtistCredits");
}
XMLUtils::GetString(node, "musicBrainzTrackID", song.strMusicBrainzTrackID);
@@ -215,7 +269,7 @@ bool CAlbum::Load(const TiXmlElement *album, bool append, bool prioritise)
if (bIncrement)
song.iTrack = song.iTrack + 1;
- songs.push_back(song);
+ infoSongs.push_back(song);
}
node = node->NextSiblingElement("track");
}
@@ -274,7 +328,7 @@ bool CAlbum::Save(TiXmlNode *node, const CStdString &tag, const CStdString& strP
XMLUtils::SetString(albumArtistCreditsNode, "featuring", artistCredit->GetArtist());
}
- for( VECSONGS::const_iterator song = songs.begin(); song != songs.end(); ++song)
+ for( VECSONGS::const_iterator song = infoSongs.begin(); song != infoSongs.end(); ++song)
{
// add a <song> tag
TiXmlElement cast("track");
diff --git a/xbmc/music/Album.h b/xbmc/music/Album.h
index 2cd331ea67..116aa08841 100644
--- a/xbmc/music/Album.h
+++ b/xbmc/music/Album.h
@@ -38,6 +38,7 @@ public:
CAlbum(const CFileItem& item);
CAlbum() { idAlbum = 0; iRating = 0; iYear = 0; iTimesPlayed = 0; };
bool operator<(const CAlbum &a) const;
+ void MergeScrapedAlbum(const CAlbum& album, bool override = true);
void Reset()
{
@@ -62,6 +63,7 @@ public:
bCompilation = false;
iTimesPlayed = 0;
songs.clear();
+ infoSongs.clear();
}
CStdString GetArtistString() const;
@@ -97,7 +99,8 @@ public:
int iYear;
bool bCompilation;
int iTimesPlayed;
- VECSONGS songs;
+ VECSONGS songs; ///< Local songs
+ VECSONGS infoSongs; ///< Scraped songs
};
typedef std::vector<CAlbum> VECALBUMS;
diff --git a/xbmc/music/Artist.cpp b/xbmc/music/Artist.cpp
index b718b9a2e8..e864fd82ae 100644
--- a/xbmc/music/Artist.cpp
+++ b/xbmc/music/Artist.cpp
@@ -24,6 +24,34 @@
using namespace std;
+void CArtist::MergeScrapedArtist(const CArtist& source, bool override /* = true */)
+{
+ /*
+ We don't merge musicbrainz artist ID so that a refresh of artist information
+ allows a lookup based on name rather than directly (re)using musicbrainz.
+ In future, we may wish to be able to override lookup by musicbrainz so
+ this might be dropped.
+ */
+ // strMusicBrainzArtistID = source.strMusicBrainzArtistID;
+ if ((override && !source.strArtist.empty()) || strArtist.empty())
+ strArtist = source.strArtist;
+
+ genre = source.genre;
+ strBiography = source.strBiography;
+ styles = source.styles;
+ moods = source.moods;
+ instruments = source.instruments;
+ strBorn = source.strBorn;
+ strFormed = source.strFormed;
+ strDied = source.strDied;
+ strDisbanded = source.strDisbanded;
+ yearsActive = source.yearsActive;
+ thumbURL = source.thumbURL;
+ fanart = source.fanart;
+ discography = source.discography;
+}
+
+
bool CArtist::Load(const TiXmlElement *artist, bool append, bool prioritise)
{
if (!artist) return false;
diff --git a/xbmc/music/Artist.h b/xbmc/music/Artist.h
index e43634bb28..daa28a079b 100644
--- a/xbmc/music/Artist.h
+++ b/xbmc/music/Artist.h
@@ -47,6 +47,8 @@ public:
if (strMusicBrainzArtistID > a.strMusicBrainzArtistID) return false;
return false;
}
+
+ void MergeScrapedArtist(const CArtist& source, bool override = true);
void Reset()
{
@@ -122,9 +124,11 @@ public:
std::string GetArtist() const { return m_strArtist; }
std::string GetMusicBrainzArtistID() const { return m_strMusicBrainzArtistID; }
std::string GetJoinPhrase() const { return m_strJoinPhrase; }
+ int GetArtistId() const { return idArtist; }
void SetArtist(const std::string &strArtist) { m_strArtist = strArtist; }
void SetMusicBrainzArtistID(const std::string &strMusicBrainzArtistID) { m_strMusicBrainzArtistID = strMusicBrainzArtistID; }
void SetJoinPhrase(const std::string &strJoinPhrase) { m_strJoinPhrase = strJoinPhrase; }
+ void SetArtistId(int idArtist) { this->idArtist = idArtist; }
private:
long idArtist;
diff --git a/xbmc/music/MusicDatabase.cpp b/xbmc/music/MusicDatabase.cpp
index 6eacb19b61..65dcf3510f 100644
--- a/xbmc/music/MusicDatabase.cpp
+++ b/xbmc/music/MusicDatabase.cpp
@@ -118,11 +118,28 @@ bool CMusicDatabase::CreateTables()
CDatabase::CreateTables();
CLog::Log(LOGINFO, "create artist table");
- m_pDS->exec("CREATE TABLE artist ( idArtist integer primary key, strArtist varchar(256), strMusicBrainzArtistID text)\n");
+ m_pDS->exec("CREATE TABLE artist ( idArtist integer primary key, "
+ " strArtist varchar(256), strMusicBrainzArtistID text, "
+ " strBorn text, strFormed text, strGenres text, strMoods text, "
+ " strStyles text, strInstruments text, strBiography text, "
+ " strDied text, strDisbanded text, strYearsActive text, "
+ " strImage text, strFanart text, "
+ " lastScraped varchar(20) default NULL, "
+ " dateAdded varchar (20) default NULL)");
CLog::Log(LOGINFO, "create album table");
- 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', strMusicBrainzAlbumID text )\n");
+ m_pDS->exec("CREATE TABLE album (idAlbum integer primary key, "
+ " strAlbum varchar(256), strMusicBrainzAlbumID text, "
+ " strArtists text, strGenres text, "
+ " iYear integer, idThumb integer, "
+ " bCompilation integer not null default '0', "
+ " strMoods text, strStyles text, strThemes text, "
+ " strReview text, strImage text, strLabel text, "
+ " strType text, "
+ " iRating integer, "
+ " lastScraped varchar(20) default NULL, "
+ " dateAdded varchar (20) default NULL)");
CLog::Log(LOGINFO, "create album_artist table");
- m_pDS->exec("CREATE TABLE album_artist ( idArtist integer, idAlbum integer, strJoinPhrase text, boolFeatured integer, iOrder integer )\n");
+ m_pDS->exec("CREATE TABLE album_artist ( idArtist integer, idAlbum integer, strJoinPhrase text, boolFeatured integer, iOrder integer, strArtist text )\n");
CLog::Log(LOGINFO, "create album_genre table");
m_pDS->exec("CREATE TABLE album_genre ( idGenre integer, idAlbum integer, iOrder integer )\n");
@@ -131,18 +148,24 @@ bool CMusicDatabase::CreateTables()
CLog::Log(LOGINFO, "create path table");
m_pDS->exec("CREATE TABLE path ( idPath integer primary key, strPath varchar(512), strHash text)\n");
CLog::Log(LOGINFO, "create song table");
- 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, iTimesPlayed integer, iStartOffset integer, iEndOffset integer, idThumb integer, lastplayed varchar(20) default NULL, rating char default '0', comment text)\n");
+ 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, "
+ " iTimesPlayed integer, iStartOffset integer, iEndOffset integer, "
+ " idThumb integer, "
+ " lastplayed varchar(20) default NULL, "
+ " rating char default '0', comment text)");
CLog::Log(LOGINFO, "create song_artist table");
- m_pDS->exec("CREATE TABLE song_artist ( idArtist integer, idSong integer, strJoinPhrase text, boolFeatured integer, iOrder integer )\n");
+ m_pDS->exec("CREATE TABLE song_artist ( idArtist integer, idSong integer, strJoinPhrase text, boolFeatured integer, iOrder integer, strArtist text )\n");
CLog::Log(LOGINFO, "create song_genre table");
m_pDS->exec("CREATE TABLE song_genre ( idGenre integer, idSong integer, iOrder integer )\n");
- CLog::Log(LOGINFO, "create albuminfo table");
- 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");
CLog::Log(LOGINFO, "create albuminfosong table");
m_pDS->exec("CREATE TABLE albuminfosong ( idAlbumInfoSong integer primary key, idAlbumInfo integer, iTrack integer, strTitle text, iDuration integer)\n");
- CLog::Log(LOGINFO, "create artistnfo table");
- 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");
+
CLog::Log(LOGINFO, "create content table");
m_pDS->exec("CREATE TABLE content (strPath text, strScraperPath text, strContent text, strSettings text)\n");
CLog::Log(LOGINFO, "create discography table");
@@ -199,20 +222,34 @@ bool CMusicDatabase::CreateTables()
CLog::Log(LOGINFO, "create song_genre indexes");
m_pDS->exec("CREATE UNIQUE INDEX idxSongGenre_1 ON song_genre ( idSong, idGenre )\n");
m_pDS->exec("CREATE UNIQUE INDEX idxSongGenre_2 ON song_genre ( idGenre, idSong )\n");
-
//m_pDS->exec("CREATE INDEX idxSong ON song(dwFileNameCRC)");
- CLog::Log(LOGINFO, "create artistinfo index");
- m_pDS->exec("CREATE INDEX idxArtistInfo on artistinfo(idArtist)");
- CLog::Log(LOGINFO, "create albuminfo index");
- m_pDS->exec("CREATE INDEX idxAlbumInfo on albuminfo(idAlbum)");
+
+ CLog::Log(LOGINFO, "create albuminfosong indexes");
+ m_pDS->exec("CREATE INDEX idxAlbumInfoSong_1 ON albuminfosong ( idAlbumInfo )\n");
CLog::Log(LOGINFO, "create karaokedata index");
m_pDS->exec("CREATE INDEX idxKaraNumber on karaokedata(iKaraNumber)");
m_pDS->exec("CREATE INDEX idxKarSong on karaokedata(idSong)");
+ CLog::Log(LOGINFO, "create discography indexes");
+ m_pDS->exec("CREATE INDEX idxDiscography_1 ON discography ( idArtist )\n");
+
// Trigger
- CLog::Log(LOGINFO, "create albuminfo trigger");
- m_pDS->exec("CREATE TRIGGER tgrAlbumInfo AFTER delete ON albuminfo FOR EACH ROW BEGIN delete from albuminfosong where albuminfosong.idAlbumInfo=old.idAlbumInfo; END");
+ CLog::Log(LOGINFO, "create album triggers");
+ m_pDS->exec("CREATE TRIGGER tgrAlbumSong AFTER delete ON album FOR EACH ROW BEGIN delete from song where song.idAlbum = old.idAlbum; END");
+ m_pDS->exec("CREATE TRIGGER tgrAlbumArtist AFTER delete ON album FOR EACH ROW BEGIN delete from album_artist where album_artist.idAlbum = old.idAlbum; END");
+ m_pDS->exec("CREATE TRIGGER tgrAlbumGenre AFTER delete ON album FOR EACH ROW BEGIN delete from album_genre where album_genre.idAlbum = old.idAlbum; END");
+ m_pDS->exec("CREATE TRIGGER tgrAlbumInfoSong AFTER delete ON album FOR EACH ROW BEGIN delete from albuminfosong where albuminfosong.idAlbumInfo = old.idAlbum; END");
+
+ CLog::Log(LOGINFO, "create artist triggers");
+ m_pDS->exec("CREATE TRIGGER tgrArtistAlbum AFTER delete ON artist FOR EACH ROW BEGIN delete from album_artist where album_artist.idArtist = old.idArtist; END");
+ m_pDS->exec("CREATE TRIGGER tgrArtistSong AFTER delete ON artist FOR EACH ROW BEGIN delete from song_artist where song_artist.idArtist = old.idArtist; END");
+ m_pDS->exec("CREATE TRIGGER tgrArtistDiscography AFTER delete ON artist FOR EACH ROW BEGIN delete from discography where discography.idArtist = old.idArtist; END");
+
+ CLog::Log(LOGINFO, "create song triggers");
+ m_pDS->exec("CREATE TRIGGER tgrSongArtist AFTER delete ON song FOR EACH ROW BEGIN delete from song_artist where song_artist.idSong = old.idSong; END");
+ m_pDS->exec("CREATE TRIGGER tgrSongGenre AFTER delete ON song FOR EACH ROW BEGIN delete from song_genre where song_genre.idSong = old.idSong; END");
+ m_pDS->exec("CREATE TRIGGER tgrSongKaraokedata AFTER delete ON song FOR EACH ROW BEGIN delete from karaokedata where karaokedata.idSong = old.idSong; END");
CLog::Log(LOGINFO, "create art table, index and triggers");
m_pDS->exec("CREATE TABLE art(art_id INTEGER PRIMARY KEY, media_id INTEGER, media_type TEXT, type TEXT, url TEXT)");
@@ -242,16 +279,23 @@ void CMusicDatabase::CreateViews()
CLog::Log(LOGINFO, "create song view");
m_pDS->exec("DROP VIEW IF EXISTS songview");
m_pDS->exec("CREATE VIEW songview AS SELECT "
- " song.idSong AS idSong, "
- " song.strArtists AS strArtists,"
- " song.strGenres AS strGenres,"
- " strTitle, iTrack, iDuration,"
- " song.iYear AS iYear, dwFileNameCRC, strFileName, strMusicBrainzTrackID,"
- " iTimesPlayed, iStartOffset, iEndOffset, lastplayed,"
- " rating, comment, song.idAlbum AS idAlbum, strAlbum, strPath,"
- " iKaraNumber, iKaraDelay, strKaraEncoding,"
- " album.bCompilation AS bCompilation,"
- " album.strArtists AS strAlbumArtists "
+ " song.idSong AS idSong, "
+ " song.strArtists AS strArtists,"
+ " song.strGenres AS strGenres,"
+ " strTitle, "
+ " iTrack, iDuration, "
+ " song.iYear AS iYear, "
+ " dwFileNameCRC, "
+ " strFileName, "
+ " strMusicBrainzTrackID, "
+ " iTimesPlayed, iStartOffset, iEndOffset, "
+ " lastplayed, rating, comment, "
+ " song.idAlbum AS idAlbum, "
+ " strAlbum, "
+ " strPath, "
+ " iKaraNumber, iKaraDelay, strKaraEncoding,"
+ " album.bCompilation AS bCompilation,"
+ " album.strArtists AS strAlbumArtists "
"FROM song"
" JOIN album ON"
" song.idAlbum=album.idAlbum"
@@ -262,83 +306,228 @@ void CMusicDatabase::CreateViews()
CLog::Log(LOGINFO, "create album view");
m_pDS->exec("DROP VIEW IF EXISTS albumview");
- if (m_sqlite)
- {
- m_pDS->exec("CREATE VIEW albumview AS SELECT "
- " album.idAlbum AS idAlbum, "
- " strAlbum, "
- " strMusicBrainzAlbumID, "
- " GROUP_CONCAT(strArtist || strJoinPhrase, '') as strArtists, "
- " album.strGenres AS strGenres, "
- " album.iYear AS iYear, "
- " idAlbumInfo, "
- " strMoods, "
- " strStyles, "
- " strThemes, "
- " strReview, "
- " strLabel, "
- " strType, "
- " strImage, "
- " iRating, "
- " bCompilation, "
- " (SELECT MIN(iTimesPlayed) AS iTimesPlayed FROM song WHERE song.idAlbum = album.idAlbum)"
- " FROM album "
- " LEFT OUTER JOIN "
- " albuminfo ON album.idAlbum = albuminfo.idAlbum "
- " LEFT OUTER JOIN album_artist ON "
- " album.idAlbum = album_artist.idAlbum "
- " LEFT OUTER JOIN artist ON "
- " album_artist.idArtist = artist.idArtist "
- " GROUP BY album.idAlbum");
- }
- else
- {
- m_pDS->exec("CREATE VIEW albumview AS SELECT "
- " album.idAlbum AS idAlbum, "
- " strAlbum, "
- " strMusicBrainzAlbumID, "
- " GROUP_CONCAT(strArtist, strJoinPhrase ORDER BY iOrder SEPARATOR '') as strArtists, "
- " album.strGenres AS strGenres, "
- " album.iYear AS iYear, "
- " idAlbumInfo, "
- " strMoods, "
- " strStyles, "
- " strThemes, "
- " strReview, "
- " strLabel, "
- " strType, "
- " strImage, "
- " iRating, "
- " bCompilation, "
- " (SELECT MIN(iTimesPlayed) AS iTimesPlayed FROM song WHERE song.idAlbum = album.idAlbum)"
- " FROM album "
- " LEFT OUTER JOIN "
- " albuminfo ON album.idAlbum = albuminfo.idAlbum "
- " LEFT OUTER JOIN album_artist ON "
- " album.idAlbum = album_artist.idAlbum "
- " LEFT OUTER JOIN artist ON "
- " album_artist.idArtist = artist.idArtist "
- " GROUP BY album.idAlbum");
- }
+ m_pDS->exec("CREATE VIEW albumview AS SELECT "
+ " album.idAlbum AS idAlbum, "
+ " strAlbum, "
+ " strMusicBrainzAlbumID, "
+ " album.strArtists AS strArtists, "
+ " album.strGenres AS strGenres, "
+ " album.iYear AS iYear, "
+ " album.strMoods AS strMoods, "
+ " album.strStyles AS strStyles, "
+ " strThemes, "
+ " strReview, "
+ " strLabel, "
+ " strType, "
+ " album.strImage as strImage, "
+ " iRating, "
+ " bCompilation, "
+ " (SELECT MIN(iTimesPlayed) AS iTimesPlayed FROM song WHERE song.idAlbum = album.idAlbum)"
+ " FROM album ");
CLog::Log(LOGINFO, "create artist view");
m_pDS->exec("DROP VIEW IF EXISTS artistview");
m_pDS->exec("CREATE VIEW artistview AS SELECT"
- " artist.idArtist AS idArtist, strArtist, "
- " artist.strMusicBrainzArtistID AS strMusicBrainzArtistID, "
+ " idArtist, strArtist, "
+ " strMusicBrainzArtistID, "
" strBorn, strFormed, strGenres,"
" strMoods, strStyles, strInstruments, "
" strBiography, strDied, strDisbanded, "
" strYearsActive, strImage, strFanart "
- "FROM artist "
- " LEFT OUTER JOIN artistinfo ON"
- " artist.idArtist = artistinfo.idArtist");
+ "FROM artist");
+
+ CLog::Log(LOGINFO, "create albumartistview");
+ m_pDS->exec("DROP VIEW IF EXISTS albumartistview");
+ m_pDS->exec("CREATE VIEW albumartistview AS SELECT"
+ " album_artist.idAlbum AS idAlbum, "
+ " album_artist.idArtist AS idArtist, "
+ " artist.strArtist AS strArtist, "
+ " artist.strMusicBrainzArtistID AS strMusicBrainzArtistID, "
+ " album_artist.boolFeatured AS boolFeatured, "
+ " album_artist.strJoinPhrase AS strJoinPhrase, "
+ " album_artist.iOrder AS iOrder "
+ "FROM album_artist "
+ "JOIN artist ON "
+ " album_artist.idArtist = artist.idArtist");
+ CLog::Log(LOGINFO, "create songartistview");
+ m_pDS->exec("DROP VIEW IF EXISTS songartistview");
+ m_pDS->exec("CREATE VIEW songartistview AS SELECT"
+ " song_artist.idSong AS idSong, "
+ " song_artist.idArtist AS idArtist, "
+ " artist.strArtist AS strArtist, "
+ " artist.strMusicBrainzArtistID AS strMusicBrainzArtistID, "
+ " song_artist.boolFeatured AS boolFeatured, "
+ " song_artist.strJoinPhrase AS strJoinPhrase, "
+ " song_artist.iOrder AS iOrder "
+ "FROM song_artist "
+ "JOIN artist ON "
+ " song_artist.idArtist = artist.idArtist");
+}
+
+int CMusicDatabase::AddAlbumInfoSong(int idAlbum, const CSong& song)
+{
+ CStdString strSQL = PrepareSQL("SELECT idAlbumInfoSong FROM albuminfosong WHERE idAlbumInfo = %i and iTrack = %i", idAlbum, song.iTrack);
+ int idAlbumInfoSong = (int)strtol(GetSingleValue(strSQL).c_str(), NULL, 10);
+ if (idAlbumInfoSong > 0)
+ {
+ strSQL = PrepareSQL("UPDATE albuminfosong SET strTitle = '%s', iDuration = %i WHERE idAlbumInfoSong = %i", song.strTitle.c_str(), song.iDuration, idAlbumInfoSong);
+ return ExecuteQuery(strSQL);
+ }
+ else
+ {
+ strSQL = PrepareSQL("INSERT INTO albuminfosong (idAlbumInfoSong,idAlbumInfo,iTrack,strTitle,iDuration) VALUES (NULL,%i,%i,'%s',%i)",
+ idAlbum,
+ song.iTrack,
+ song.strTitle.c_str(),
+ song.iDuration);
+ return ExecuteQuery(strSQL);
+ }
+}
+
+std::string GetArtistString(const VECARTISTCREDITS &credits)
+{
+ std::string artistString;
+ for (VECARTISTCREDITS::const_iterator i = credits.begin(); i != credits.end(); ++i)
+ artistString += i->GetArtist() + i->GetJoinPhrase();
+ return artistString;
+}
+
+bool CMusicDatabase::AddAlbum(CAlbum& album)
+{
+ BeginTransaction();
+
+ album.idAlbum = AddAlbum(album.strAlbum,
+ album.strMusicBrainzAlbumID,
+ GetArtistString(album.artistCredits),
+ album.GetGenreString(),
+ album.iYear,
+ album.bCompilation);
+
+ // Add the album artists
+ for (VECARTISTCREDITS::iterator artistCredit = album.artistCredits.begin(); artistCredit != album.artistCredits.end(); ++artistCredit)
+ {
+ artistCredit->idArtist = AddArtist(artistCredit->GetArtist(), artistCredit->GetMusicBrainzArtistID());
+ AddAlbumArtist(artistCredit->idArtist,
+ album.idAlbum,
+ artistCredit->GetArtist(),
+ artistCredit->GetJoinPhrase(),
+ artistCredit == album.artistCredits.begin() ? false : true,
+ std::distance(album.artistCredits.begin(), artistCredit));
+ }
+
+ for (VECSONGS::iterator song = album.songs.begin(); song != album.songs.end(); ++song)
+ {
+ song->idAlbum = album.idAlbum;
+ song->idSong = AddSong(song->idAlbum,
+ song->strTitle, song->strMusicBrainzTrackID,
+ song->strFileName, song->strComment,
+ song->strThumb,
+ GetArtistString(song->artistCredits), song->genre,
+ song->iTrack, song->iDuration, song->iYear,
+ song->iTimesPlayed, song->iStartOffset,
+ song->iEndOffset,
+ song->lastPlayed,
+ song->rating,
+ song->iKaraokeNumber);
+ for (VECARTISTCREDITS::iterator artistCredit = song->artistCredits.begin(); artistCredit != song->artistCredits.end(); ++artistCredit)
+ {
+ artistCredit->idArtist = AddArtist(artistCredit->GetArtist(),
+ artistCredit->GetMusicBrainzArtistID());
+ AddSongArtist(artistCredit->idArtist,
+ song->idSong,
+ artistCredit->GetArtist(),
+ artistCredit->GetJoinPhrase(), // we don't have song artist breakdowns from scrapers, yet
+ artistCredit == song->artistCredits.begin() ? false : true,
+ std::distance(song->artistCredits.begin(), artistCredit));
+ }
+ }
+ for (VECSONGS::const_iterator infoSong = album.infoSongs.begin(); infoSong != album.infoSongs.end(); ++infoSong)
+ AddAlbumInfoSong(album.idAlbum, *infoSong);
+
+ for (std::map<std::string, std::string>::const_iterator albumArt = album.art.begin();
+ albumArt != album.art.end();
+ ++albumArt)
+ SetArtForItem(album.idAlbum, "album", albumArt->first, albumArt->second);
+
+ CommitTransaction();
+ return true;
+}
+
+bool CMusicDatabase::UpdateAlbum(CAlbum& album)
+{
+ BeginTransaction();
+
+ UpdateAlbum(album.idAlbum,
+ album.strAlbum, album.strMusicBrainzAlbumID,
+ GetArtistString(album.artistCredits), album.GetGenreString(),
+ StringUtils::Join(album.moods, g_advancedSettings.m_musicItemSeparator).c_str(),
+ StringUtils::Join(album.styles, g_advancedSettings.m_musicItemSeparator).c_str(),
+ StringUtils::Join(album.themes, g_advancedSettings.m_musicItemSeparator).c_str(),
+ album.strReview,
+ album.thumbURL.m_xml.c_str(),
+ album.strLabel, album.strType,
+ album.iRating, album.iYear, album.bCompilation);
+
+ // Add the album artists
+ DeleteAlbumArtistsByAlbum(album.idAlbum);
+ for (VECARTISTCREDITS::iterator artistCredit = album.artistCredits.begin(); artistCredit != album.artistCredits.end(); ++artistCredit)
+ {
+ artistCredit->idArtist = AddArtist(artistCredit->GetArtist(),
+ artistCredit->GetMusicBrainzArtistID());
+ AddAlbumArtist(artistCredit->idArtist,
+ album.idAlbum,
+ artistCredit->GetArtist(),
+ artistCredit->GetJoinPhrase(),
+ artistCredit == album.artistCredits.begin() ? false : true,
+ std::distance(album.artistCredits.begin(), artistCredit));
+ }
+
+ for (VECSONGS::iterator song = album.songs.begin(); song != album.songs.end(); ++song)
+ {
+ UpdateSong(song->idSong,
+ song->strTitle,
+ song->strMusicBrainzTrackID,
+ song->strFileName,
+ song->strComment,
+ song->strThumb,
+ GetArtistString(song->artistCredits),
+ song->genre,
+ song->iTrack,
+ song->iDuration,
+ song->iYear,
+ song->iTimesPlayed,
+ song->iStartOffset,
+ song->iEndOffset,
+ song->lastPlayed,
+ song->rating,
+ song->iKaraokeNumber);
+ DeleteSongArtistsBySong(song->idSong);
+ for (VECARTISTCREDITS::iterator artistCredit = song->artistCredits.begin(); artistCredit != song->artistCredits.end(); ++artistCredit)
+ {
+ artistCredit->idArtist = AddArtist(artistCredit->GetArtist(),
+ artistCredit->GetMusicBrainzArtistID());
+ AddSongArtist(artistCredit->idArtist,
+ song->idSong,
+ artistCredit->GetArtist(),
+ artistCredit->GetJoinPhrase(),
+ artistCredit == song->artistCredits.begin() ? false : true,
+ std::distance(song->artistCredits.begin(), artistCredit));
+ }
+ }
+ for (VECSONGS::const_iterator infoSong = album.infoSongs.begin(); infoSong != album.infoSongs.end(); ++infoSong)
+ AddAlbumInfoSong(album.idAlbum, *infoSong);
+
+ if (!album.art.empty())
+ SetArtForItem(album.idAlbum, "album", album.art);
+
+ CommitTransaction();
+ return true;
}
int CMusicDatabase::AddSong(const int idAlbum,
const CStdString& strTitle, const CStdString& strMusicBrainzTrackID,
const CStdString& strPathAndFileName, const CStdString& strComment, const CStdString& strThumb,
- const std::vector<std::string>& artists, const std::vector<std::string>& genres,
+ const std::string &artistString, const std::vector<std::string>& genres,
int iTrack, int iDuration, int iYear,
const int iTimesPlayed, int iStartOffset, int iEndOffset,
const CDateTime& dtLastPlayed, char rating, int iKaraokeNumber)
@@ -383,7 +572,7 @@ int CMusicDatabase::AddSong(const int idAlbum,
strSQL=PrepareSQL("INSERT INTO song (idSong,idAlbum,idPath,strArtists,strGenres,strTitle,iTrack,iDuration,iYear,dwFileNameCRC,strFileName,strMusicBrainzTrackID,iTimesPlayed,iStartOffset,iEndOffset,lastplayed,rating,comment) values (NULL, %i, %i, '%s', '%s', '%s', %i, %i, %i, '%ul', '%s'",
idAlbum,
idPath,
- StringUtils::Join(artists, g_advancedSettings.m_musicItemSeparator).c_str(),
+ artistString.c_str(),
StringUtils::Join(genres, g_advancedSettings.m_musicItemSeparator).c_str(),
strTitle.c_str(),
iTrack, iDuration, iYear,
@@ -407,7 +596,7 @@ int CMusicDatabase::AddSong(const int idAlbum,
{
idSong = m_pDS->fv("idSong").get_asInt();
m_pDS->close();
- UpdateSong(idSong, strTitle, strMusicBrainzTrackID, strPathAndFileName, strComment, strThumb, artists, genres, iTrack, iDuration, iYear, iTimesPlayed, iStartOffset, iEndOffset, dtLastPlayed, rating, iKaraokeNumber);
+ UpdateSong(idSong, strTitle, strMusicBrainzTrackID, strPathAndFileName, strComment, strThumb, artistString, genres, iTrack, iDuration, iYear, iTimesPlayed, iStartOffset, iEndOffset, dtLastPlayed, rating, iKaraokeNumber);
}
if (!strThumb.empty())
@@ -443,51 +632,116 @@ int CMusicDatabase::AddSong(const int idAlbum,
return idSong;
}
+bool CMusicDatabase::GetSong(int idSong, CSong& song)
+{
+ try
+ {
+ song.Clear();
+
+ if (NULL == m_pDB.get()) return false;
+ if (NULL == m_pDS.get()) return false;
+
+ CStdString strSQL=PrepareSQL("SELECT songview.*,songartistview.* FROM songview "
+ " JOIN songartistview ON songview.idSong = songartistview.idSong "
+ " WHERE songview.idSong = %i", idSong);
+
+ if (!m_pDS->query(strSQL.c_str())) return false;
+ int iRowsFound = m_pDS->num_rows();
+ if (iRowsFound == 0)
+ {
+ m_pDS->close();
+ return false;
+ }
+
+ int songArtistOffset = song_enumCount;
+
+ set<int> artistcredits;
+ song = GetSongFromDataset(m_pDS.get()->get_sql_record());
+ while (!m_pDS->eof())
+ {
+ const dbiplus::sql_record* const record = m_pDS.get()->get_sql_record();
+
+ int idSongArtist = record->at(songArtistOffset + artistCredit_idArtist).get_asInt();
+ if (artistcredits.find(idSongArtist) == artistcredits.end())
+ {
+ song.artistCredits.push_back(GetArtistCreditFromDataset(record, songArtistOffset));
+ artistcredits.insert(idSongArtist);
+ }
+
+ m_pDS->next();
+ }
+ m_pDS->close(); // cleanup recordset data
+ return true;
+ }
+ catch (...)
+ {
+ CLog::Log(LOGERROR, "%s(%i) failed", __FUNCTION__, idSong);
+ }
+
+ return false;
+}
+
+int CMusicDatabase::UpdateSong(int idSong, const CSong &song)
+{
+ return UpdateSong(idSong,
+ song.strTitle,
+ song.strMusicBrainzTrackID,
+ song.strFileName,
+ song.strComment,
+ song.strThumb,
+ StringUtils::Join(song.artist, g_advancedSettings.m_musicItemSeparator), // NOTE: Don't call this function internally!!!
+ song.genre,
+ song.iTrack,
+ song.iDuration,
+ song.iYear,
+ song.iTimesPlayed,
+ song.iStartOffset,
+ song.iEndOffset,
+ song.lastPlayed,
+ song.rating,
+ song.iKaraokeNumber);
+}
+
int CMusicDatabase::UpdateSong(int idSong,
const CStdString& strTitle, const CStdString& strMusicBrainzTrackID,
const CStdString& strPathAndFileName, const CStdString& strComment, const CStdString& strThumb,
- const std::vector<std::string>& artists, const std::vector<std::string>& genres,
+ const std::string& artistString, const std::vector<std::string>& genres,
int iTrack, int iDuration, int iYear,
int iTimesPlayed, int iStartOffset, int iEndOffset,
const CDateTime& dtLastPlayed, char rating, int iKaraokeNumber)
{
- CStdString sql;
if (idSong < 0)
return -1;
-
+
CStdString strSQL;
- try
- {
- CStdString strPath, strFileName;
- URIUtils::Split(strPathAndFileName, strPath, strFileName);
- int idPath = AddPath(strPath);
- DWORD crc = ComputeCRC(strFileName);
-
- strSQL = PrepareSQL("UPDATE song SET idPath = %i, strArtists = '%s', strGenres = '%s', strTitle = '%s', iTrack = %i, iDuration = %i, iYear = %i, dwFileNameCRC = '%ul', strFileName = '%s'",
- idPath,
- StringUtils::Join(artists, g_advancedSettings.m_musicItemSeparator).c_str(),
- StringUtils::Join(genres, g_advancedSettings.m_musicItemSeparator).c_str(),
- strTitle.c_str(),
- iTrack, iDuration, iYear,
- crc, strFileName.c_str());
- if (strMusicBrainzTrackID.empty())
- strSQL += PrepareSQL(", strMusicBrainzTrackID = NULL");
- else
- strSQL += PrepareSQL(", strMusicBrainzTrackID = '%s'", strMusicBrainzTrackID.c_str());
-
- if (dtLastPlayed.IsValid())
- strSQL += PrepareSQL(", iTimesPlayed = %i, iStartOffset = %i, iEndOffset = %i, lastplayed = '%s', rating = '%c', comment = '%s'",
- iTimesPlayed, iStartOffset, iEndOffset, dtLastPlayed.GetAsDBDateTime().c_str(), rating, strComment.c_str());
- else
- strSQL += PrepareSQL(", iTimesPlayed = %i, iStartOffset = %i, iEndOffset = %i, lastplayed = NULL, rating = '%c', comment = '%s'",
- iTimesPlayed, iStartOffset, iEndOffset, rating, strComment.c_str());
- strSQL += PrepareSQL(" WHERE idSong = %i", idSong);
- m_pDS->exec(strSQL.c_str());
- }
- catch (...)
- {
- CLog::Log(LOGERROR, "musicdatabase:unable to addsong (%s)", strSQL.c_str());
- }
+ CStdString strPath, strFileName;
+ URIUtils::Split(strPathAndFileName, strPath, strFileName);
+ int idPath = AddPath(strPath);
+ DWORD crc = ComputeCRC(strFileName);
+
+ strSQL = PrepareSQL("UPDATE song SET idPath = %i, strArtists = '%s', strGenres = '%s', strTitle = '%s', iTrack = %i, iDuration = %i, iYear = %i, dwFileNameCRC = '%ul', strFileName = '%s'",
+ idPath,
+ artistString.c_str(),
+ StringUtils::Join(genres, g_advancedSettings.m_musicItemSeparator).c_str(),
+ strTitle.c_str(),
+ iTrack, iDuration, iYear,
+ crc, strFileName.c_str());
+ if (strMusicBrainzTrackID.empty())
+ strSQL += PrepareSQL(", strMusicBrainzTrackID = NULL");
+ else
+ strSQL += PrepareSQL(", strMusicBrainzTrackID = '%s'", strMusicBrainzTrackID.c_str());
+
+ if (dtLastPlayed.IsValid())
+ strSQL += PrepareSQL(", iTimesPlayed = %i, iStartOffset = %i, iEndOffset = %i, lastplayed = '%s', rating = '%c', comment = '%s'",
+ iTimesPlayed, iStartOffset, iEndOffset, dtLastPlayed.GetAsDBDateTime().c_str(), rating, strComment.c_str());
+ else
+ strSQL += PrepareSQL(", iTimesPlayed = %i, iStartOffset = %i, iEndOffset = %i, lastplayed = NULL, rating = '%c', comment = '%s'",
+ iTimesPlayed, iStartOffset, iEndOffset, rating, strComment.c_str());
+ strSQL += PrepareSQL(" WHERE idSong = %i", idSong);
+
+ bool status = ExecuteQuery(strSQL);
+ if (status)
+ AnnounceUpdate("song", idSong);
return idSong;
}
@@ -534,17 +788,34 @@ int CMusicDatabase::AddAlbum(const CStdString& strAlbum, const CStdString& strMu
}
else
{
- // exists in our database and not scanned during this scan, so we should update it as the details
- // may have changed (there's a reason we're rescanning, afterall!)
+ /* Exists in our database and being re-scanned from tags, so we should update it as the details
+ may have changed.
+
+ Note that for multi-folder albums this will mean the last folder scanned will have the information
+ stored for it. Most values here should be the same across all songs anyway, but it does mean
+ that if there's any inconsistencies then only the last folders information will be taken.
+
+ We make sure we clear out the link tables (album artists, album genres) and we reset
+ the last scraped time to make sure that online metadata is re-fetched. */
int idAlbum = m_pDS->fv("idAlbum").get_asInt();
m_pDS->close();
- strSQL=PrepareSQL("update album set strGenres='%s', iYear=%i where idAlbum=%i", strGenre.c_str(), year, idAlbum);
- m_pDS->exec(strSQL.c_str());
- // and clear the link tables - these are updated in AddSong()
- strSQL=PrepareSQL("delete from album_artist where idAlbum=%i", idAlbum);
- m_pDS->exec(strSQL.c_str());
- strSQL=PrepareSQL("delete from album_genre where idAlbum=%i", idAlbum);
+ if (strMusicBrainzAlbumID.empty())
+ strSQL=PrepareSQL("UPDATE album SET strGenres = '%s', iYear=%i, bCompilation=%i, lastScraped = NULL WHERE idAlbum=%i",
+ strGenre.c_str(),
+ year,
+ bCompilation,
+ idAlbum);
+ else
+ strSQL=PrepareSQL("UPDATE album SET strAlbum = '%s', strArtists = '%s', strGenres = '%s', iYear=%i, bCompilation=%i, lastScraped = NULL WHERE idAlbum=%i",
+ strAlbum.c_str(),
+ strArtist.c_str(),
+ strGenre.c_str(),
+ year,
+ bCompilation,
+ idAlbum);
m_pDS->exec(strSQL.c_str());
+ DeleteAlbumArtistsByAlbum(idAlbum);
+ DeleteAlbumGenresByAlbum(idAlbum);
return idAlbum;
}
}
@@ -556,6 +827,160 @@ int CMusicDatabase::AddAlbum(const CStdString& strAlbum, const CStdString& strMu
return -1;
}
+int CMusicDatabase::UpdateAlbum(int idAlbum,
+ const CStdString& strAlbum, const CStdString& strMusicBrainzAlbumID,
+ const CStdString& strArtist, const CStdString& strGenre,
+ const CStdString& strMoods, const CStdString& strStyles,
+ const CStdString& strThemes, const CStdString& strReview,
+ const CStdString& strImage, const CStdString& strLabel,
+ const CStdString& strType,
+ int iRating, int iYear, bool bCompilation)
+{
+ if (idAlbum < 0)
+ return -1;
+
+ CStdString strSQL;
+ strSQL = PrepareSQL("UPDATE album SET "
+ " strAlbum = '%s', strArtists = '%s', strGenres = '%s', "
+ " strMoods = '%s', strStyles = '%s', strThemes = '%s', "
+ " strReview = '%s', strImage = '%s', strLabel = '%s', "
+ " strType = '%s',"
+ " iYear = %i, bCompilation = %i, lastScraped = '%s'",
+ strAlbum.c_str(), strArtist.c_str(), strGenre.c_str(),
+ strMoods.c_str(), strStyles.c_str(), strThemes.c_str(),
+ strReview.c_str(), strImage.c_str(), strLabel.c_str(),
+ strType.c_str(),
+ iYear, bCompilation,
+ CDateTime::GetCurrentDateTime().GetAsDBDateTime().c_str());
+ if (strMusicBrainzAlbumID.empty())
+ strSQL += PrepareSQL(", strMusicBrainzAlbumID = NULL");
+ else
+ strSQL += PrepareSQL(", strMusicBrainzAlbumID = '%s'", strMusicBrainzAlbumID.c_str());
+
+ strSQL += PrepareSQL(" WHERE idAlbum = %i", idAlbum);
+
+ bool status = ExecuteQuery(strSQL);
+ if (status)
+ AnnounceUpdate("album", idAlbum);
+ return idAlbum;
+}
+
+bool CMusicDatabase::GetAlbum(int idAlbum, CAlbum& album, bool getSongs /* = true */)
+{
+ try
+ {
+ if (NULL == m_pDB.get()) return false;
+ if (NULL == m_pDS.get()) return false;
+
+ if (idAlbum == -1)
+ return false; // not in the database
+
+ CStdString sql;
+ if (getSongs)
+ {
+ sql = PrepareSQL("SELECT albumview.*,albumartistview.*,songview.*,songartistview.*,albuminfosong.* "
+ " FROM albumview "
+ " JOIN albumartistview ON albumview.idAlbum = albumartistview.idAlbum "
+ " JOIN songview ON albumview.idAlbum = songview.idAlbum "
+ " JOIN songartistview ON songview.idSong = songartistview.idSong "
+ " LEFT JOIN albuminfosong ON albumview.idAlbum = albuminfosong.idAlbumInfo "
+ " WHERE albumview.idAlbum = %ld "
+ " ORDER BY iOrder, iTrack", idAlbum);
+ }
+ else
+ {
+ sql = PrepareSQL("SELECT albumview.*,albumartistview.* "
+ " FROM albumview "
+ " JOIN albumartistview ON albumview.idAlbum = albumartistview.idAlbum "
+ " WHERE albumview.idAlbum = %ld "
+ " ORDER BY iOrder", idAlbum);
+ }
+
+ CLog::Log(LOGDEBUG, "%s", sql.c_str());
+ if (!m_pDS->query(sql.c_str())) return false;
+ if (m_pDS->num_rows() == 0)
+ {
+ m_pDS->close();
+ return false;
+ }
+
+ int albumArtistOffset = album_enumCount;
+ int songOffset = albumArtistOffset + artistCredit_enumCount;
+ int songArtistOffset = songOffset + song_enumCount;
+ int infoSongOffset = songArtistOffset + artistCredit_enumCount;
+
+ set<int> artistcredits;
+ set<int> songs;
+ set<pair<int, int> > songartistcredits;
+ set<int> infosongs;
+ album = GetAlbumFromDataset(m_pDS.get()->get_sql_record(), 0, true); // true to grab and parse the imageURL
+ while (!m_pDS->eof())
+ {
+ const dbiplus::sql_record* const record = m_pDS->get_sql_record();
+
+ // Because rows repeat in the joined query (cartesian join) we may see each
+ // entity (album artist, song, song artist) multiple times in the result set.
+ // Since there should never be a song with the same artist twice, or an album
+ // with the same song (by id) listed twice, we key on the entity ID and only
+ // create an entity for the first occurence of each entity in the data set.
+ int idAlbumArtist = record->at(albumArtistOffset + artistCredit_idArtist).get_asInt();
+ if (artistcredits.find(idAlbumArtist) == artistcredits.end())
+ {
+ album.artistCredits.push_back(GetArtistCreditFromDataset(record, albumArtistOffset));
+ artistcredits.insert(idAlbumArtist);
+ }
+
+ if (getSongs)
+ {
+ int idSong = record->at(songOffset + song_idSong).get_asInt();
+ if (songs.find(idSong) == songs.end())
+ {
+ album.songs.push_back(GetSongFromDataset(record, songOffset));
+ songs.insert(idSong);
+ }
+
+ int idSongArtistSong = record->at(songArtistOffset + artistCredit_idEntity).get_asInt();
+ int idSongArtistArtist = record->at(songArtistOffset + artistCredit_idArtist).get_asInt();
+ if (songartistcredits.find(make_pair(idSongArtistSong, idSongArtistArtist)) == songartistcredits.end())
+ {
+ for (VECSONGS::iterator si = album.songs.begin(); si != album.songs.end(); ++si)
+ if (si->idSong == idSongArtistSong)
+ si->artistCredits.push_back(GetArtistCreditFromDataset(record, songArtistOffset));
+ songartistcredits.insert(make_pair(idSongArtistSong, idSongArtistArtist));
+ }
+
+ int idAlbumInfoSong = m_pDS.get()->get_sql_record()->at(infoSongOffset + albumInfoSong_idAlbumInfoSong).get_asInt();
+ if (infosongs.find(idAlbumInfoSong) == infosongs.end())
+ {
+ album.infoSongs.push_back(GetAlbumInfoSongFromDataset(record, infoSongOffset));
+ infosongs.insert(idAlbumInfoSong);
+ }
+ }
+ m_pDS->next();
+ }
+ m_pDS->close(); // cleanup recordset data
+ return true;
+ }
+ catch (...)
+ {
+ CLog::Log(LOGERROR, "%s(%i) failed", __FUNCTION__, idAlbum);
+ }
+
+ return false;
+}
+
+bool CMusicDatabase::ClearAlbumLastScrapedTime(int idAlbum)
+{
+ CStdString strSQL = PrepareSQL("UPDATE album SET lastScraped = NULL WHERE idAlbum = %i", idAlbum);
+ return ExecuteQuery(strSQL);
+}
+
+bool CMusicDatabase::HasAlbumBeenScraped(int idAlbum)
+{
+ CStdString strSQL = PrepareSQL("SELECT idAlbum FROM album WHERE idAlbum = %i AND lastScraped IS NULL", idAlbum);
+ return GetSingleValue(strSQL).empty();
+}
+
int CMusicDatabase::AddGenre(const CStdString& strGenre1)
{
CStdString strSQL;
@@ -605,6 +1030,32 @@ int CMusicDatabase::AddGenre(const CStdString& strGenre1)
return -1;
}
+bool CMusicDatabase::UpdateArtist(const CArtist& artist)
+{
+ UpdateArtist(artist.idArtist,
+ artist.strArtist, artist.strMusicBrainzArtistID,
+ artist.strBorn, artist.strFormed,
+ StringUtils::Join(artist.genre, g_advancedSettings.m_musicItemSeparator),
+ StringUtils::Join(artist.moods, g_advancedSettings.m_musicItemSeparator),
+ StringUtils::Join(artist.styles, g_advancedSettings.m_musicItemSeparator),
+ StringUtils::Join(artist.instruments, g_advancedSettings.m_musicItemSeparator),
+ artist.strBiography, artist.strDied,
+ artist.strDisbanded,
+ StringUtils::Join(artist.yearsActive, g_advancedSettings.m_musicItemSeparator).c_str(),
+ artist.thumbURL.m_xml.c_str(),
+ artist.fanart.m_xml.c_str());
+
+ DeleteArtistDiscography(artist.idArtist);
+ for (std::vector<std::pair<CStdString,CStdString> >::const_iterator disc = artist.discography.begin();
+ disc != artist.discography.end();
+ ++disc)
+ {
+ AddArtistDiscography(artist.idArtist, disc->first, disc->second);
+ }
+
+ return true;
+}
+
int CMusicDatabase::AddArtist(const CStdString& strArtist, const CStdString& strMusicBrainzArtistID)
{
CStdString strSQL;
@@ -686,22 +1137,149 @@ int CMusicDatabase::AddArtist(const CStdString& strArtist, const CStdString& str
return -1;
}
-bool CMusicDatabase::AddSongArtist(int idArtist, int idSong, std::string joinPhrase, bool featured, int iOrder)
+int CMusicDatabase::UpdateArtist(int idArtist,
+ const CStdString& strArtist, const CStdString& strMusicBrainzArtistID,
+ const CStdString& strBorn, const CStdString& strFormed,
+ const CStdString& strGenres, const CStdString& strMoods,
+ const CStdString& strStyles, const CStdString& strInstruments,
+ const CStdString& strBiography, const CStdString& strDied,
+ const CStdString& strDisbanded, const CStdString& strYearsActive,
+ const CStdString& strImage, const CStdString& strFanart)
{
+ CScraperUrl thumbURL;
+ CFanart fanart;
+ std::vector<std::pair<CStdString,CStdString> > discography;
+ if (idArtist < 0)
+ return -1;
+
CStdString strSQL;
- strSQL=PrepareSQL("replace into song_artist (idArtist, idSong, strJoinPhrase, boolFeatured, iOrder) values(%i,%i,'%s',%i,%i)",
- idArtist, idSong, joinPhrase.c_str(), featured == true ? 1 : 0, iOrder);
+ strSQL = PrepareSQL("UPDATE artist SET "
+ " strArtist = '%s', "
+ " strBorn = '%s', strFormed = '%s', strGenres = '%s', "
+ " strMoods = '%s', strStyles = '%s', strInstruments = '%s', "
+ " strBiography = '%s', strDied = '%s', strDisbanded = '%s', "
+ " strYearsActive = '%s', strImage = '%s', strFanart = '%s', "
+ " lastScraped = '%s'",
+ strArtist.c_str(), /* strMusicBrainzArtistID.c_str(), */
+ strBorn.c_str(), strFormed.c_str(), strGenres.c_str(),
+ strMoods.c_str(), strStyles.c_str(), strInstruments.c_str(),
+ strBiography.c_str(), strDied.c_str(), strDisbanded.c_str(),
+ strYearsActive.c_str(), strImage.c_str(), strFanart.c_str(),
+ CDateTime::GetCurrentDateTime().GetAsDBDateTime().c_str());
+ if (strMusicBrainzArtistID.empty())
+ strSQL += PrepareSQL(", strMusicBrainzArtistID = NULL");
+ else
+ strSQL += PrepareSQL(", strMusicBrainzArtistID = '%s'", strMusicBrainzArtistID.c_str());
+
+ strSQL += PrepareSQL(" WHERE idArtist = %i", idArtist);
+
+ bool status = ExecuteQuery(strSQL);
+ if (status)
+ AnnounceUpdate("artist", idArtist);
+ return idArtist;
+}
+
+bool CMusicDatabase::GetArtist(int idArtist, CArtist &artist, bool fetchAll /* = false */)
+{
+ try
+ {
+ if (NULL == m_pDB.get()) return false;
+ if (NULL == m_pDS.get()) return false;
+
+ if (idArtist == -1)
+ return false; // not in the database
+
+ CStdString strSQL;
+ if (fetchAll)
+ strSQL = PrepareSQL("SELECT * FROM artistview LEFT JOIN discography ON artistview.idArtist = discography.idArtist WHERE artistview.idArtist = %i", idArtist);
+ else
+ strSQL = PrepareSQL("SELECT * FROM artistview WHERE artistview.idArtist = %i", idArtist);
+
+ if (!m_pDS->query(strSQL.c_str())) return false;
+ if (m_pDS->num_rows() == 0)
+ {
+ m_pDS->close();
+ return false;
+ }
+
+ int discographyOffset = artist_enumCount;
+
+ artist.discography.clear();
+ artist = GetArtistFromDataset(m_pDS.get()->get_sql_record(), 0, fetchAll);
+ if (fetchAll)
+ {
+ while (!m_pDS->eof())
+ {
+ const dbiplus::sql_record* const record = m_pDS.get()->get_sql_record();
+
+ artist.discography.push_back(make_pair(record->at(discographyOffset + 1).get_asString(), record->at(discographyOffset + 2).get_asString()));
+ m_pDS->next();
+ }
+ }
+ m_pDS->close(); // cleanup recordset data
+ return true;
+ }
+ catch (...)
+ {
+ CLog::Log(LOGERROR, "%s(%i) failed", __FUNCTION__, idArtist);
+ }
+
+ return false;
+}
+
+bool CMusicDatabase::HasArtistBeenScraped(int idArtist)
+{
+ CStdString strSQL = PrepareSQL("SELECT idArtist FROM artist WHERE idArtist = %i AND lastScraped IS NULL", idArtist);
+ return GetSingleValue(strSQL).empty();
+}
+
+bool CMusicDatabase::ClearArtistLastScrapedTime(int idArtist)
+{
+ CStdString strSQL = PrepareSQL("UPDATE artist SET lastScraped = NULL WHERE idArtist = %i", idArtist);
+ return ExecuteQuery(strSQL);
+}
+
+int CMusicDatabase::AddArtistDiscography(int idArtist, const CStdString& strAlbum, const CStdString& strYear)
+{
+ CStdString strSQL=PrepareSQL("INSERT INTO discography (idArtist, strAlbum, strYear) values(%i, '%s', '%s')",
+ idArtist,
+ strAlbum.c_str(),
+ strYear.c_str());
+ return ExecuteQuery(strSQL);
+}
+
+bool CMusicDatabase::DeleteArtistDiscography(int idArtist)
+{
+ CStdString strSQL = PrepareSQL("DELETE FROM discography WHERE idArtist = %i", idArtist);
+ return ExecuteQuery(strSQL);
+}
+
+bool CMusicDatabase::AddSongArtist(int idArtist, int idSong, std::string strArtist, std::string joinPhrase, bool featured, int iOrder)
+{
+ CStdString strSQL;
+ strSQL=PrepareSQL("replace into song_artist (idArtist, idSong, strArtist, strJoinPhrase, boolFeatured, iOrder) values(%i,%i,'%s','%s',%i,%i)",
+ idArtist, idSong, strArtist.c_str(), joinPhrase.c_str(), featured == true ? 1 : 0, iOrder);
return ExecuteQuery(strSQL);
};
-bool CMusicDatabase::AddAlbumArtist(int idArtist, int idAlbum, std::string joinPhrase, bool featured, int iOrder)
+bool CMusicDatabase::DeleteSongArtistsBySong(int idSong)
+{
+ return ExecuteQuery(PrepareSQL("DELETE FROM song_artist WHERE idSong = %i", idSong));
+}
+
+bool CMusicDatabase::AddAlbumArtist(int idArtist, int idAlbum, std::string strArtist, std::string joinPhrase, bool featured, int iOrder)
{
CStdString strSQL;
- strSQL=PrepareSQL("replace into album_artist (idArtist, idAlbum, strJoinPhrase, boolFeatured, iOrder) values(%i,%i,'%s',%i,%i)",
- idArtist, idAlbum, joinPhrase.c_str(), featured == true ? 1 : 0, iOrder);
+ strSQL=PrepareSQL("replace into album_artist (idArtist, idAlbum, strArtist, strJoinPhrase, boolFeatured, iOrder) values(%i,%i,'%s','%s',%i,%i)",
+ idArtist, idAlbum, strArtist.c_str(), joinPhrase.c_str(), featured == true ? 1 : 0, iOrder);
return ExecuteQuery(strSQL);
};
+bool CMusicDatabase::DeleteAlbumArtistsByAlbum(int idAlbum)
+{
+ return ExecuteQuery(PrepareSQL("DELETE FROM album_artist WHERE idAlbum = %i", idAlbum));
+}
+
bool CMusicDatabase::AddSongGenre(int idGenre, int idSong, int iOrder)
{
if (idGenre == -1 || idSong == -1)
@@ -710,7 +1288,13 @@ bool CMusicDatabase::AddSongGenre(int idGenre, int idSong, int iOrder)
CStdString strSQL;
strSQL=PrepareSQL("replace into song_genre (idGenre, idSong, iOrder) values(%i,%i,%i)",
idGenre, idSong, iOrder);
- return ExecuteQuery(strSQL);};
+ return ExecuteQuery(strSQL);
+};
+
+bool CMusicDatabase::DeleteSongGenresBySong(int idSong)
+{
+ return ExecuteQuery(PrepareSQL("DELETE FROM song_genre WHERE idSong = %i", idSong));
+}
bool CMusicDatabase::AddAlbumGenre(int idGenre, int idAlbum, int iOrder)
{
@@ -723,6 +1307,11 @@ bool CMusicDatabase::AddAlbumGenre(int idGenre, int idAlbum, int iOrder)
return ExecuteQuery(strSQL);
};
+bool CMusicDatabase::DeleteAlbumGenresByAlbum(int idAlbum)
+{
+ return ExecuteQuery(PrepareSQL("DELETE FROM album_genre WHERE idAlbum = %i", idAlbum));
+}
+
bool CMusicDatabase::GetAlbumsByArtist(int idArtist, bool includeFeatured, std::vector<int> &albums)
{
try
@@ -964,47 +1553,41 @@ int CMusicDatabase::AddPath(const CStdString& strPath1)
return -1;
}
-CSong CMusicDatabase::GetSongFromDataset(bool bWithMusicDbPath/*=false*/)
+CSong CMusicDatabase::GetSongFromDataset()
+{
+ return GetSongFromDataset(m_pDS->get_sql_record());
+}
+
+CSong CMusicDatabase::GetSongFromDataset(const dbiplus::sql_record* const record, int offset /* = 0 */)
{
CSong song;
- song.idSong = m_pDS->fv(song_idSong).get_asInt();
+ song.idSong = record->at(offset + song_idSong).get_asInt();
// get the full artist string
- song.artist = StringUtils::Split(m_pDS->fv(song_strArtists).get_asString(), g_advancedSettings.m_musicItemSeparator);
+ song.artist = StringUtils::Split(record->at(offset + song_strArtists).get_asString(), g_advancedSettings.m_musicItemSeparator);
// and the full genre string
- song.genre = StringUtils::Split(m_pDS->fv(song_strGenres).get_asString(), g_advancedSettings.m_musicItemSeparator);
+ song.genre = StringUtils::Split(record->at(offset + song_strGenres).get_asString(), g_advancedSettings.m_musicItemSeparator);
// and the rest...
- song.strAlbum = m_pDS->fv(song_strAlbum).get_asString();
- song.idAlbum = m_pDS->fv(song_idAlbum).get_asInt();
- song.iTrack = m_pDS->fv(song_iTrack).get_asInt() ;
- song.iDuration = m_pDS->fv(song_iDuration).get_asInt() ;
- song.iYear = m_pDS->fv(song_iYear).get_asInt() ;
- song.strTitle = m_pDS->fv(song_strTitle).get_asString();
- song.iTimesPlayed = m_pDS->fv(song_iTimesPlayed).get_asInt();
- song.lastPlayed.SetFromDBDateTime(m_pDS->fv(song_lastplayed).get_asString());
- song.iStartOffset = m_pDS->fv(song_iStartOffset).get_asInt();
- song.iEndOffset = m_pDS->fv(song_iEndOffset).get_asInt();
- song.strMusicBrainzTrackID = m_pDS->fv(song_strMusicBrainzTrackID).get_asString();
- song.rating = m_pDS->fv(song_rating).get_asChar();
- song.strComment = m_pDS->fv(song_comment).get_asString();
- song.iKaraokeNumber = m_pDS->fv(song_iKarNumber).get_asInt();
- song.strKaraokeLyrEncoding = m_pDS->fv(song_strKarEncoding).get_asString();
- song.iKaraokeDelay = m_pDS->fv(song_iKarDelay).get_asInt();
- song.bCompilation = m_pDS->fv(song_bCompilation).get_asInt() == 1;
- song.albumArtist = StringUtils::Split(m_pDS->fv(song_strAlbumArtists).get_asString(), g_advancedSettings.m_musicItemSeparator);
+ song.strAlbum = record->at(offset + song_strAlbum).get_asString();
+ song.idAlbum = record->at(offset + song_idAlbum).get_asInt();
+ song.iTrack = record->at(offset + song_iTrack).get_asInt() ;
+ song.iDuration = record->at(offset + song_iDuration).get_asInt() ;
+ song.iYear = record->at(offset + song_iYear).get_asInt() ;
+ song.strTitle = record->at(offset + song_strTitle).get_asString();
+ song.iTimesPlayed = record->at(offset + song_iTimesPlayed).get_asInt();
+ song.lastPlayed.SetFromDBDateTime(record->at(offset + song_lastplayed).get_asString());
+ song.iStartOffset = record->at(offset + song_iStartOffset).get_asInt();
+ song.iEndOffset = record->at(offset + song_iEndOffset).get_asInt();
+ song.strMusicBrainzTrackID = record->at(offset + song_strMusicBrainzTrackID).get_asString();
+ song.rating = record->at(offset + song_rating).get_asChar();
+ song.strComment = record->at(offset + song_comment).get_asString();
+ song.iKaraokeNumber = record->at(offset + song_iKarNumber).get_asInt();
+ song.strKaraokeLyrEncoding = record->at(offset + song_strKarEncoding).get_asString();
+ song.iKaraokeDelay = record->at(offset + song_iKarDelay).get_asInt();
+ song.bCompilation = record->at(offset + song_bCompilation).get_asInt() == 1;
+ song.albumArtist = StringUtils::Split(record->at(offset + song_strAlbumArtists).get_asString(), g_advancedSettings.m_musicItemSeparator);
// Get filename with full path
- if (!bWithMusicDbPath)
- song.strFileName = URIUtils::AddFileToFolder(m_pDS->fv(song_strPath).get_asString(), m_pDS->fv(song_strFileName).get_asString());
- else
- {
- CStdString strFileName = m_pDS->fv(song_strFileName).get_asString();
- CStdString strExt = URIUtils::GetExtension(strFileName);
- song.strFileName = StringUtils::Format("musicdb://albums/%ld/%ld%s",
- m_pDS->fv(song_idAlbum).get_asInt(),
- m_pDS->fv(song_idSong).get_asInt(),
- strExt.c_str());
- }
-
+ song.strFileName = URIUtils::AddFileToFolder(record->at(song_strPath).get_asString(), record->at(song_strFileName).get_asString());
return song;
}
@@ -1057,69 +1640,69 @@ void CMusicDatabase::GetFileItemFromDataset(const dbiplus::sql_record* const rec
}
}
-CAlbum CMusicDatabase::GetAlbumFromDataset(dbiplus::Dataset* pDS, bool imageURL /* = false*/)
+CAlbum CMusicDatabase::GetAlbumFromDataset(dbiplus::Dataset* pDS, int offset /* = 0 */, bool imageURL /* = false*/)
{
- return GetAlbumFromDataset(pDS->get_sql_record(), imageURL);
+ return GetAlbumFromDataset(pDS->get_sql_record(), offset, imageURL);
}
-CAlbum CMusicDatabase::GetAlbumFromDataset(const dbiplus::sql_record* const record, bool imageURL /* = false*/)
+CAlbum CMusicDatabase::GetAlbumFromDataset(const dbiplus::sql_record* const record, int offset /* = 0 */, bool imageURL /* = false*/)
{
CAlbum album;
- album.idAlbum = record->at(album_idAlbum).get_asInt();
- album.strAlbum = record->at(album_strAlbum).get_asString();
+ album.idAlbum = record->at(offset + album_idAlbum).get_asInt();
+ album.strAlbum = record->at(offset + album_strAlbum).get_asString();
if (album.strAlbum.empty())
album.strAlbum = g_localizeStrings.Get(1050);
- album.strMusicBrainzAlbumID = record->at(album_strMusicBrainzAlbumID).get_asString();
- album.artist = StringUtils::Split(record->at(album_strArtists).get_asString(), g_advancedSettings.m_musicItemSeparator);
- album.genre = StringUtils::Split(record->at(album_strGenres).get_asString(), g_advancedSettings.m_musicItemSeparator);
- album.iYear = record->at(album_iYear).get_asInt();
+ album.strMusicBrainzAlbumID = record->at(offset + album_strMusicBrainzAlbumID).get_asString();
+ album.artist = StringUtils::Split(record->at(offset + album_strArtists).get_asString(), g_advancedSettings.m_musicItemSeparator);
+ album.genre = StringUtils::Split(record->at(offset + album_strGenres).get_asString(), g_advancedSettings.m_musicItemSeparator);
+ album.iYear = record->at(offset + album_iYear).get_asInt();
if (imageURL)
- album.thumbURL.ParseString(record->at(album_strThumbURL).get_asString());
- album.iRating = record->at(album_iRating).get_asInt();
- album.iYear = record->at(album_iYear).get_asInt();
- album.strReview = record->at(album_strReview).get_asString();
- album.styles = StringUtils::Split(record->at(album_strStyles).get_asString(), g_advancedSettings.m_musicItemSeparator);
- album.moods = StringUtils::Split(record->at(album_strMoods).get_asString(), g_advancedSettings.m_musicItemSeparator);
- album.themes = StringUtils::Split(record->at(album_strThemes).get_asString(), g_advancedSettings.m_musicItemSeparator);
- album.strLabel = record->at(album_strLabel).get_asString();
- album.strType = record->at(album_strType).get_asString();
- album.bCompilation = record->at(album_bCompilation).get_asInt() == 1;
- album.iTimesPlayed = record->at(album_iTimesPlayed).get_asInt();
+ album.thumbURL.ParseString(record->at(offset + album_strThumbURL).get_asString());
+ album.iRating = record->at(offset + album_iRating).get_asInt();
+ album.iYear = record->at(offset + album_iYear).get_asInt();
+ album.strReview = record->at(offset + album_strReview).get_asString();
+ album.styles = StringUtils::Split(record->at(offset + album_strStyles).get_asString(), g_advancedSettings.m_musicItemSeparator);
+ album.moods = StringUtils::Split(record->at(offset + album_strMoods).get_asString(), g_advancedSettings.m_musicItemSeparator);
+ album.themes = StringUtils::Split(record->at(offset + album_strThemes).get_asString(), g_advancedSettings.m_musicItemSeparator);
+ album.strLabel = record->at(offset + album_strLabel).get_asString();
+ album.strType = record->at(offset + album_strType).get_asString();
+ album.bCompilation = record->at(offset + album_bCompilation).get_asInt() == 1;
+ album.iTimesPlayed = record->at(offset + album_iTimesPlayed).get_asInt();
return album;
}
-CArtistCredit CMusicDatabase::GetAlbumArtistCreditFromDataset(const dbiplus::sql_record* const record)
+CArtistCredit CMusicDatabase::GetArtistCreditFromDataset(const dbiplus::sql_record* const record, int offset /* = 0 */)
{
CArtistCredit artistCredit;
- artistCredit.idArtist = record->at(album_idArtist).get_asInt();
- artistCredit.m_strArtist = record->at(album_strArtist).get_asString();
- artistCredit.m_strMusicBrainzArtistID = record->at(album_strMusicBrainzArtistID).get_asString();
- artistCredit.m_boolFeatured = record->at(album_bFeatured).get_asBool();
- artistCredit.m_strJoinPhrase = record->at(album_strJoinPhrase).get_asString();
+ artistCredit.idArtist = record->at(offset + artistCredit_idArtist).get_asInt();
+ artistCredit.m_strArtist = record->at(offset + artistCredit_strArtist).get_asString();
+ artistCredit.m_strMusicBrainzArtistID = record->at(offset + artistCredit_strMusicBrainzArtistID).get_asString();
+ artistCredit.m_boolFeatured = record->at(offset + artistCredit_bFeatured).get_asBool();
+ artistCredit.m_strJoinPhrase = record->at(offset + artistCredit_strJoinPhrase).get_asString();
return artistCredit;
}
-CArtist CMusicDatabase::GetArtistFromDataset(dbiplus::Dataset* pDS, bool needThumb)
+CArtist CMusicDatabase::GetArtistFromDataset(dbiplus::Dataset* pDS, int offset /* = 0 */, bool needThumb /* = true */)
{
- return GetArtistFromDataset(pDS->get_sql_record(), needThumb);
+ return GetArtistFromDataset(pDS->get_sql_record(), offset, needThumb);
}
-CArtist CMusicDatabase::GetArtistFromDataset(const dbiplus::sql_record* const record, bool needThumb /* = true */)
+CArtist CMusicDatabase::GetArtistFromDataset(const dbiplus::sql_record* const record, int offset /* = 0 */, bool needThumb /* = true */)
{
CArtist artist;
- artist.idArtist = record->at(artist_idArtist).get_asInt();
- artist.strArtist = record->at(artist_strArtist).get_asString();
- artist.strMusicBrainzArtistID = record->at(artist_strMusicBrainzArtistID).get_asString();
- artist.genre = StringUtils::Split(record->at(artist_strGenres).get_asString(), g_advancedSettings.m_musicItemSeparator);
- artist.strBiography = record->at(artist_strBiography).get_asString();
- artist.styles = StringUtils::Split(record->at(artist_strStyles).get_asString(), g_advancedSettings.m_musicItemSeparator);
- artist.moods = StringUtils::Split(record->at(artist_strMoods).get_asString(), g_advancedSettings.m_musicItemSeparator);
- artist.strBorn = record->at(artist_strBorn).get_asString();
- artist.strFormed = record->at(artist_strFormed).get_asString();
- artist.strDied = record->at(artist_strDied).get_asString();
- artist.strDisbanded = record->at(artist_strDisbanded).get_asString();
- artist.yearsActive = StringUtils::Split(record->at(artist_strYearsActive).get_asString(), g_advancedSettings.m_musicItemSeparator);
- artist.instruments = StringUtils::Split(record->at(artist_strInstruments).get_asString(), g_advancedSettings.m_musicItemSeparator);
+ artist.idArtist = record->at(offset + artist_idArtist).get_asInt();
+ artist.strArtist = record->at(offset + artist_strArtist).get_asString();
+ artist.strMusicBrainzArtistID = record->at(offset + artist_strMusicBrainzArtistID).get_asString();
+ artist.genre = StringUtils::Split(record->at(offset + artist_strGenres).get_asString(), g_advancedSettings.m_musicItemSeparator);
+ artist.strBiography = record->at(offset + artist_strBiography).get_asString();
+ artist.styles = StringUtils::Split(record->at(offset + artist_strStyles).get_asString(), g_advancedSettings.m_musicItemSeparator);
+ artist.moods = StringUtils::Split(record->at(offset + artist_strMoods).get_asString(), g_advancedSettings.m_musicItemSeparator);
+ artist.strBorn = record->at(offset + artist_strBorn).get_asString();
+ artist.strFormed = record->at(offset + artist_strFormed).get_asString();
+ artist.strDied = record->at(offset + artist_strDied).get_asString();
+ artist.strDisbanded = record->at(offset + artist_strDisbanded).get_asString();
+ artist.yearsActive = StringUtils::Split(record->at(offset + artist_strYearsActive).get_asString(), g_advancedSettings.m_musicItemSeparator);
+ artist.instruments = StringUtils::Split(record->at(offset + artist_strInstruments).get_asString(), g_advancedSettings.m_musicItemSeparator);
if (needThumb)
{
@@ -1131,49 +1714,44 @@ CArtist CMusicDatabase::GetArtistFromDataset(const dbiplus::sql_record* const re
return artist;
}
+CSong CMusicDatabase::GetAlbumInfoSongFromDataset(const dbiplus::sql_record* const record, int offset /* = 0 */)
+{
+ CSong song;
+ song.iTrack = record->at(offset + albumInfoSong_iTrack).get_asInt();
+ song.iDuration = record->at(offset + albumInfoSong_iDuration).get_asInt();
+ song.strTitle = record->at(offset + albumInfoSong_strTitle).get_asString();
+ return song;
+}
+
bool CMusicDatabase::GetSongByFileName(const CStdString& strFileName, CSong& song, int startOffset)
{
- try
+ song.Clear();
+ CURL url(strFileName);
+
+ if (url.GetProtocol()=="musicdb")
{
- song.Clear();
- CURL url(strFileName);
+ CStdString strFile = URIUtils::GetFileName(strFileName);
+ URIUtils::RemoveExtension(strFile);
+ return GetSong(atol(strFile.c_str()), song);
+ }
- if (url.GetProtocol()=="musicdb")
- {
- CStdString strFile = URIUtils::GetFileName(strFileName);
- URIUtils::RemoveExtension(strFile);
- return GetSong(atol(strFile.c_str()), song);
- }
+ CStdString strPath = URIUtils::GetDirectory(strFileName);
+ URIUtils::AddSlashAtEnd(strPath);
- if (NULL == m_pDB.get()) return false;
- if (NULL == m_pDS.get()) return false;
+ if (NULL == m_pDB.get()) return false;
+ if (NULL == m_pDS.get()) return false;
- CStdString strPath = URIUtils::GetDirectory(strFileName);
- URIUtils::AddSlashAtEnd(strPath);
+ DWORD crc = ComputeCRC(strFileName);
- DWORD crc = ComputeCRC(strFileName);
- CStdString strSQL=PrepareSQL("select * from songview "
- "where dwFileNameCRC='%ul' and strPath='%s'"
- , crc,
- strPath.c_str());
- if (startOffset)
- strSQL += PrepareSQL(" AND iStartOffset=%i", startOffset);
+ CStdString strSQL = PrepareSQL("select idSong from songview "
+ "where dwFileNameCRC='%ul' and strPath='%s'",
+ crc, strPath.c_str());
+ if (startOffset)
+ strSQL += PrepareSQL(" AND iStartOffset=%i", startOffset);
- if (!m_pDS->query(strSQL.c_str())) return false;
- int iRowsFound = m_pDS->num_rows();
- if (iRowsFound == 0)
- {
- m_pDS->close();
- return false;
- }
- song = GetSongFromDataset();
- m_pDS->close(); // cleanup recordset data
- return true;
- }
- catch (...)
- {
- CLog::Log(LOGERROR, "%s(%s) failed", __FUNCTION__, strFileName.c_str());
- }
+ int idSong = (int)strtol(GetSingleValue(strSQL).c_str(), NULL, 10);
+ if (idSong > 0)
+ return GetSong(idSong, song);
return false;
}
@@ -1227,38 +1805,6 @@ int CMusicDatabase::GetSongByArtistAndAlbumAndTitle(const CStdString& strArtist,
return -1;
}
-bool CMusicDatabase::GetSong(int idSong, CSong& song)
-{
- try
- {
- song.Clear();
-
- if (NULL == m_pDB.get()) return false;
- if (NULL == m_pDS.get()) return false;
-
- CStdString strSQL=PrepareSQL("select * from songview "
- "where idSong=%i"
- , idSong);
-
- if (!m_pDS->query(strSQL.c_str())) return false;
- int iRowsFound = m_pDS->num_rows();
- if (iRowsFound == 0)
- {
- m_pDS->close();
- return false;
- }
- song = GetSongFromDataset();
- m_pDS->close(); // cleanup recordset data
- return true;
- }
- catch (...)
- {
- CLog::Log(LOGERROR, "%s(%i) failed", __FUNCTION__, idSong);
- }
-
- return false;
-}
-
bool CMusicDatabase::SearchArtists(const CStdString& search, CFileItemList &artists)
{
try
@@ -1309,168 +1855,6 @@ bool CMusicDatabase::SearchArtists(const CStdString& search, CFileItemList &arti
return false;
}
-bool CMusicDatabase::GetAlbumInfo(int idAlbum, CAlbum &info, VECSONGS* songs, bool scrapedInfo /* = false */)
-{
- try
- {
- if (NULL == m_pDB.get()) return false;
- if (NULL == m_pDS2.get()) return false;
-
- if (idAlbum == -1)
- return false; // not in the database
-
- CStdString strSQL=PrepareSQL("SELECT albumview.*, album_artist.idArtist, artist.strArtist, artist.strMusicBrainzArtistID, album_artist.boolFeatured, album_artist.strJoinPhrase FROM albumview JOIN album_artist ON albumview.idAlbum = album_artist.idAlbum JOIN artist ON album_artist.idArtist = artist.idArtist WHERE albumview.idAlbum = %ld", idAlbum);
- if (scrapedInfo) // require additional information
- strSQL += " and idAlbumInfo > 0";
-
- if (!m_pDS2->query(strSQL.c_str())) return false;
- if (m_pDS2->num_rows() == 0)
- {
- m_pDS2->close();
- return false;
- }
-
- info = GetAlbumFromDataset(m_pDS2.get()->get_sql_record(), true); // true to grab the thumburl rather than the thumb
- int idAlbumInfo = m_pDS2->fv(album_idAlbumInfo).get_asInt();
- while (!m_pDS2->eof())
- {
- if (!info.artistCredits.empty() && (m_pDS2->fv(album_idArtist).get_asInt() != info.artistCredits.back().idArtist))
- {
- info.artistCredits.push_back(GetAlbumArtistCreditFromDataset(m_pDS2.get()->get_sql_record()));
- }
- m_pDS2->next();
- }
- if (songs)
- GetAlbumInfoSongs(idAlbumInfo, *songs);
-
- m_pDS2->close(); // cleanup recordset data
- return true;
- }
- catch (...)
- {
- CLog::Log(LOGERROR, "%s(%i) failed", __FUNCTION__, idAlbum);
- }
-
- return false;
-}
-
-bool CMusicDatabase::HasAlbumInfo(int idAlbum)
-{
- try
- {
- if (idAlbum == -1)
- return false; // not in the database
-
- CStdString strSQL=PrepareSQL("select * from albuminfo where idAlbum = %ld", idAlbum);
-
- if (!m_pDS2->query(strSQL.c_str())) return false;
- int iRowsFound = m_pDS2->num_rows();
- m_pDS2->close();
- return iRowsFound > 0;
- }
- catch (...)
- {
- CLog::Log(LOGERROR, "%s(%i) failed", __FUNCTION__, idAlbum);
- }
-
- return false;
-}
-
-bool CMusicDatabase::DeleteAlbumInfo(int idAlbum)
-{
- if (idAlbum == -1)
- return false; // not in the database
- return ExecuteQuery(PrepareSQL("delete from albuminfo where idAlbum=%i",idAlbum));
-}
-
-bool CMusicDatabase::GetArtistInfo(int idArtist, CArtist &info, bool needAll)
-{
- try
- {
- if (NULL == m_pDB.get()) return false;
- if (NULL == m_pDS2.get()) return false;
-
- if (idArtist == -1)
- return false; // not in the database
-
- CStdString strSQL=PrepareSQL("SELECT * FROM artistview WHERE idArtist = %i", idArtist);
-
- if (!m_pDS2->query(strSQL.c_str())) return false;
- int iRowsFound = m_pDS2->num_rows();
- if (iRowsFound != 0)
- {
- info = GetArtistFromDataset(m_pDS2.get(),needAll);
- if (needAll)
- {
- strSQL=PrepareSQL("select * from discography where idArtist=%i",idArtist);
- m_pDS2->query(strSQL.c_str());
- while (!m_pDS2->eof())
- {
- info.discography.push_back(make_pair(m_pDS2->fv("strAlbum").get_asString(),m_pDS2->fv("strYear").get_asString()));
- m_pDS2->next();
- }
- }
- m_pDS2->close(); // cleanup recordset data
- return true;
- }
- m_pDS2->close();
- return false;
- }
- catch (...)
- {
- CLog::Log(LOGERROR, "%s - (%i) failed", __FUNCTION__, idArtist);
- }
-
- return false;
-}
-
-bool CMusicDatabase::HasArtistInfo(int idArtist)
-{
- return strtol(GetSingleValue("artistinfo", "count(idArtist)", PrepareSQL("idArtist = %ld", idArtist)), NULL, 10) > 0;
-}
-
-bool CMusicDatabase::DeleteArtistInfo(int idArtist)
-{
- if (idArtist == -1)
- return false; // not in the database
-
- return ExecuteQuery(PrepareSQL("delete from artistinfo where idArtist=%i",idArtist));
-}
-
-bool CMusicDatabase::GetAlbumInfoSongs(int idAlbumInfo, VECSONGS& songs)
-{
- try
- {
- CStdString strSQL=PrepareSQL("select * from albuminfosong "
- "where idAlbumInfo=%i "
- "order by iTrack", idAlbumInfo);
-
- if (!m_pDS2->query(strSQL.c_str())) return false;
- int iRowsFound = m_pDS2->num_rows();
- if (iRowsFound == 0) return false;
- while (!m_pDS2->eof())
- {
- CSong song;
- song.iTrack = m_pDS2->fv("iTrack").get_asInt();
- song.strTitle = m_pDS2->fv("strTitle").get_asString();
- song.iDuration = m_pDS2->fv("iDuration").get_asInt();
-
- songs.push_back(song);
- m_pDS2->next();
- }
-
- m_pDS2->close(); // cleanup recordset data
-
- return true;
- }
- catch (...)
- {
- CLog::Log(LOGERROR, "%s(%i) failed", __FUNCTION__, idAlbumInfo);
- }
-
- return false;
-}
-
bool CMusicDatabase::GetTop100(const CStdString& strBaseDir, CFileItemList& items)
{
try
@@ -1920,139 +2304,6 @@ bool CMusicDatabase::SearchAlbums(const CStdString& search, CFileItemList &album
return false;
}
-int CMusicDatabase::SetAlbumInfo(int idAlbum, const CAlbum& album, const VECSONGS& songs, bool bTransaction)
-{
- CStdString strSQL;
- try
- {
- if (NULL == m_pDB.get()) return -1;
- if (NULL == m_pDS.get()) return -1;
-
- if (bTransaction)
- BeginTransaction();
-
- // delete any album info we may have
- strSQL=PrepareSQL("delete from albuminfo where idAlbum=%i", idAlbum);
- m_pDS->exec(strSQL.c_str());
-
- // insert the albuminfo
- strSQL=PrepareSQL("insert into albuminfo (idAlbumInfo,idAlbum,strMoods,strStyles,strThemes,strReview,strImage,strLabel,strType,iRating,iYear) values(NULL,%i,'%s','%s','%s','%s','%s','%s','%s',%i,%i)",
- idAlbum,
- StringUtils::Join(album.moods, g_advancedSettings.m_musicItemSeparator).c_str(),
- StringUtils::Join(album.styles, g_advancedSettings.m_musicItemSeparator).c_str(),
- StringUtils::Join(album.themes, g_advancedSettings.m_musicItemSeparator).c_str(),
- album.strReview.c_str(),
- album.thumbURL.m_xml.c_str(),
- album.strLabel.c_str(),
- album.strType.c_str(),
- album.iRating,
- album.iYear);
- m_pDS->exec(strSQL.c_str());
- int idAlbumInfo = (int)m_pDS->lastinsertid();
-
- if (SetAlbumInfoSongs(idAlbumInfo, songs))
- {
- if (bTransaction)
- CommitTransaction();
- }
- else
- {
- if (bTransaction) // icky
- RollbackTransaction();
- idAlbumInfo = -1;
- }
-
- return idAlbumInfo;
- }
- catch (...)
- {
- CLog::Log(LOGERROR, "%s failed with query (%s)", __FUNCTION__, strSQL.c_str());
- }
-
- if (bTransaction)
- RollbackTransaction();
-
- return -1;
-}
-
-int CMusicDatabase::SetArtistInfo(int idArtist, const CArtist& artist)
-{
- CStdString strSQL;
- try
- {
- if (NULL == m_pDB.get()) return -1;
- if (NULL == m_pDS.get()) return -1;
-
- // delete any artist info we may have
- strSQL=PrepareSQL("delete from artistinfo where idArtist=%i", idArtist);
- m_pDS->exec(strSQL.c_str());
- strSQL=PrepareSQL("delete from discography where idArtist=%i", idArtist);
- m_pDS->exec(strSQL.c_str());
-
- // insert the artistinfo
- strSQL=PrepareSQL("insert into artistinfo (idArtistInfo,idArtist,strBorn,strFormed,strGenres,strMoods,strStyles,strInstruments,strBiography,strDied,strDisbanded,strYearsActive,strImage,strFanart) values(NULL,%i,'%s','%s','%s','%s','%s','%s','%s','%s','%s','%s','%s','%s')",
- idArtist, artist.strBorn.c_str(),
- artist.strFormed.c_str(),
- StringUtils::Join(artist.genre, g_advancedSettings.m_musicItemSeparator).c_str(),
- StringUtils::Join(artist.moods, g_advancedSettings.m_musicItemSeparator).c_str(),
- StringUtils::Join(artist.styles, g_advancedSettings.m_musicItemSeparator).c_str(),
- StringUtils::Join(artist.instruments, g_advancedSettings.m_musicItemSeparator).c_str(),
- artist.strBiography.c_str(),
- artist.strDied.c_str(),
- artist.strDisbanded.c_str(),
- StringUtils::Join(artist.yearsActive, g_advancedSettings.m_musicItemSeparator).c_str(),
- artist.thumbURL.m_xml.c_str(),
- artist.fanart.m_xml.c_str());
- m_pDS->exec(strSQL.c_str());
- int idArtistInfo = (int)m_pDS->lastinsertid();
- for (unsigned int i=0;i<artist.discography.size();++i)
- {
- strSQL=PrepareSQL("insert into discography (idArtist,strAlbum,strYear) values (%i,'%s','%s')",idArtist,artist.discography[i].first.c_str(),artist.discography[i].second.c_str());
- m_pDS->exec(strSQL.c_str());
- }
-
- return idArtistInfo;
- }
- catch (...)
- {
- CLog::Log(LOGERROR, "%s - failed with query (%s)", __FUNCTION__, strSQL.c_str());
- }
-
-
- return -1;
-}
-
-bool CMusicDatabase::SetAlbumInfoSongs(int idAlbumInfo, const VECSONGS& songs)
-{
- CStdString strSQL;
- try
- {
- if (NULL == m_pDB.get()) return false;
- if (NULL == m_pDS.get()) return false;
-
- strSQL=PrepareSQL("delete from albuminfosong where idAlbumInfo=%i", idAlbumInfo);
- m_pDS->exec(strSQL.c_str());
-
- for (int i = 0; i < (int)songs.size(); i++)
- {
- CSong song = songs[i];
- strSQL=PrepareSQL("insert into albuminfosong (idAlbumInfoSong,idAlbumInfo,iTrack,strTitle,iDuration) values(NULL,%i,%i,'%s',%i)",
- idAlbumInfo,
- song.iTrack,
- song.strTitle.c_str(),
- song.iDuration);
- m_pDS->exec(strSQL.c_str());
- }
- return true;
- }
- catch (...)
- {
- CLog::Log(LOGERROR, "%s failed with query (%s)", __FUNCTION__, strSQL.c_str());
- }
-
- return false;
-}
-
bool CMusicDatabase::CleanupSongsByIds(const CStdString &strSongIds)
{
try
@@ -2097,12 +2348,6 @@ bool CMusicDatabase::CleanupSongsByIds(const CStdString &strSongIds)
// ok, now delete these songs + all references to them from the linked tables
strSQL = "delete from song where idSong in " + strSongsToDelete;
m_pDS->exec(strSQL.c_str());
- strSQL = "delete from song_artist where idSong in " + strSongsToDelete;
- m_pDS->exec(strSQL.c_str());
- strSQL = "delete from song_genre where idSong in " + strSongsToDelete;
- m_pDS->exec(strSQL.c_str());
- strSQL = "delete from karaokedata where idSong in " + strSongsToDelete;
- m_pDS->exec(strSQL.c_str());
m_pDS->close();
}
return true;
@@ -2179,12 +2424,6 @@ bool CMusicDatabase::CleanupAlbums()
// ok, now we can delete them and the references in the linked tables
strSQL = "delete from album where idAlbum in " + strAlbumIds;
m_pDS->exec(strSQL.c_str());
- strSQL = "delete from album_artist where idAlbum in " + strAlbumIds;
- m_pDS->exec(strSQL.c_str());
- strSQL = "delete from album_genre where idAlbum in " + strAlbumIds;
- m_pDS->exec(strSQL.c_str());
- strSQL = "delete from albuminfo where idAlbum in " + strAlbumIds;
- m_pDS->exec(strSQL.c_str());
return true;
}
catch (...)
@@ -2262,10 +2501,6 @@ bool CMusicDatabase::CleanupArtists()
strSQL += " and idArtist not in (select idArtist from album_artist)";
CStdString strSQL2;
m_pDS->exec(strSQL.c_str());
- m_pDS->exec("delete from artistinfo where idArtist not in (select idArtist from artist)");
- m_pDS->exec("delete from album_artist where idArtist not in (select idArtist from artist)");
- m_pDS->exec("delete from song_artist where idArtist not in (select idArtist from artist)");
- m_pDS->exec("delete from discography where idArtist not in (select idArtist from artist)");
return true;
}
catch (...)
@@ -2279,9 +2514,9 @@ bool CMusicDatabase::CleanupGenres()
{
try
{
- // Cleanup orphaned genres (ie those that don't belong to a song or an albuminfo entry)
+ // Cleanup orphaned genres (ie those that don't belong to a song or an album entry)
// (nested queries by Bobbin007)
- // Must be executed AFTER the song, song_genre, albuminfo and album_genre tables have been cleaned.
+ // Must be executed AFTER the song, song_genre, album and album_genre tables have been cleaned.
CStdString strSQL = "delete from genre where idGenre not in (select idGenre from song_genre) and";
strSQL += " idGenre not in (select idGenre from album_genre)";
m_pDS->exec(strSQL.c_str());
@@ -2331,7 +2566,7 @@ int CMusicDatabase::Cleanup(CGUIDialogProgress *pDlgProgress)
ret = ERROR_REORG_SONGS;
goto error;
}
- // then the albums that are not linked to a song or to albuminfo, or whose path is removed
+ // then the albums that are not linked to a song or to album, or whose path is removed
if (pDlgProgress)
{
pDlgProgress->SetLine(1, 326);
@@ -2413,70 +2648,6 @@ error:
return ret;
}
-void CMusicDatabase::DeleteAlbumInfo()
-{
- // open our database
- Open();
- if (NULL == m_pDB.get()) return ;
- if (NULL == m_pDS.get()) return ;
-
- // If we are scanning for music info in the background,
- // other writing access to the database is prohibited.
- if (g_application.IsMusicScanning())
- {
- CGUIDialogOK::ShowAndGetInput(189, 14057, 0, 0);
- return;
- }
-
- CStdString strSQL="select * from albuminfo,album,artist where and albuminfo.idAlbum=album.idAlbum and album.idArtist=artist.idArtist order by album.strAlbum";
- if (!m_pDS->query(strSQL.c_str())) return ;
- int iRowsFound = m_pDS->num_rows();
- if (iRowsFound == 0)
- {
- m_pDS->close();
- CGUIDialogOK::ShowAndGetInput(313, 425, 0, 0);
- }
- vector<CAlbum> vecAlbums;
- while (!m_pDS->eof())
- {
- CAlbum album;
- album.idAlbum = m_pDS->fv("album.idAlbum").get_asInt() ;
- album.strAlbum = m_pDS->fv("album.strAlbum").get_asString();
- album.artist = StringUtils::Split(m_pDS->fv("album.strArtists").get_asString(), g_advancedSettings.m_musicItemSeparator);
- vecAlbums.push_back(album);
- m_pDS->next();
- }
- m_pDS->close();
-
- // Show a selectdialog that the user can select the albuminfo to delete
- CGUIDialogSelect *pDlg = (CGUIDialogSelect*)g_windowManager.GetWindow(WINDOW_DIALOG_SELECT);
- if (pDlg)
- {
- pDlg->SetHeading(g_localizeStrings.Get(181).c_str());
- pDlg->Reset();
- for (int i = 0; i < (int)vecAlbums.size(); ++i)
- {
- CAlbum& album = vecAlbums[i];
- pDlg->Add(album.strAlbum + " - " + StringUtils::Join(album.artist, g_advancedSettings.m_musicItemSeparator));
- }
- pDlg->DoModal();
-
- // and wait till user selects one
- int iSelectedAlbum = pDlg->GetSelectedLabel();
- if (iSelectedAlbum < 0)
- {
- vecAlbums.erase(vecAlbums.begin(), vecAlbums.end());
- return ;
- }
-
- CAlbum& album = vecAlbums[iSelectedAlbum];
- strSQL=PrepareSQL("delete from albuminfo where albuminfo.idAlbum=%i", album.idAlbum);
- if (!m_pDS->exec(strSQL.c_str())) return ;
-
- vecAlbums.erase(vecAlbums.begin(), vecAlbums.end());
- }
-}
-
bool CMusicDatabase::LookupCDDBInfo(bool bRequery/*=false*/)
{
#ifdef HAS_DVD_DRIVE
@@ -2597,7 +2768,7 @@ void CMusicDatabase::DeleteCDDBInfo()
CGUIDialogOK::ShowAndGetInput(313, 426, 0, 0);
return ;
}
- // Show a selectdialog that the user can select the albuminfo to delete
+ // Show a selectdialog that the user can select the album to delete
CGUIDialogSelect *pDlg = (CGUIDialogSelect*)g_windowManager.GetWindow(WINDOW_DIALOG_SELECT);
if (pDlg)
{
@@ -3838,7 +4009,112 @@ bool CMusicDatabase::UpdateOldVersion(int version)
m_pDS->exec("DROP INDEX idxSong6 ON song");
m_pDS->exec("CREATE INDEX idxSong6 on song( idPath, strFileName(255) )");
}
-
+
+ if (version < 39)
+ {
+ m_pDS->exec("CREATE TABLE album_new "
+ "(idAlbum integer primary key, "
+ " strAlbum varchar(256), strMusicBrainzAlbumID text, "
+ " strArtists text, strGenres text, "
+ " iYear integer, idThumb integer, "
+ " bCompilation integer not null default '0', "
+ " strMoods text, strStyles text, strThemes text, "
+ " strReview text, strImage text, strLabel text, "
+ " strType text, "
+ " iRating integer, "
+ " lastScraped varchar(20) default NULL, "
+ " dateAdded varchar (20) default NULL)");
+ m_pDS->exec("INSERT INTO album_new "
+ "(idAlbum, "
+ " strAlbum, strMusicBrainzAlbumID, "
+ " strArtists, strGenres, "
+ " iYear, idThumb, "
+ " bCompilation, "
+ " strMoods, strStyles, strThemes, "
+ " strReview, strImage, strLabel, "
+ " strType, "
+ " iRating) "
+ " SELECT "
+ " album.idAlbum, "
+ " strAlbum, strMusicBrainzAlbumID, "
+ " strArtists, strGenres, "
+ " album.iYear, idThumb, "
+ " bCompilation, "
+ " strMoods, strStyles, strThemes, "
+ " strReview, strImage, strLabel, "
+ " strType, iRating "
+ " FROM album LEFT JOIN albuminfo ON album.idAlbum = albuminfo.idAlbum");
+ m_pDS->exec("UPDATE albuminfosong SET idAlbumInfo = (SELECT idAlbum FROM albuminfo WHERE albuminfo.idAlbumInfo = albuminfosong.idAlbumInfo)");
+ m_pDS->exec("CREATE INDEX idxAlbumInfoSong_1 ON albuminfosong ( idAlbumInfo )\n");
+ m_pDS->exec(PrepareSQL("UPDATE album_new SET lastScraped='%s' WHERE idAlbum IN (SELECT idAlbum FROM albuminfo)", CDateTime::GetCurrentDateTime().GetAsDBDateTime().c_str()));
+ m_pDS->exec("DROP TABLE album");
+ m_pDS->exec("DROP TABLE albuminfo");
+ m_pDS->exec("ALTER TABLE album_new RENAME TO album");
+ m_pDS->exec("CREATE TRIGGER tgrAlbumInfoSong AFTER delete ON album FOR EACH ROW BEGIN delete from albuminfosong where albuminfosong.idAlbumInfo=old.idAlbum; END");
+ }
+ if (version < 40)
+ {
+ m_pDS->exec("CREATE TABLE artist_new ( idArtist integer primary key, "
+ " strArtist varchar(256), strMusicBrainzArtistID text, "
+ " strBorn text, strFormed text, strGenres text, strMoods text, "
+ " strStyles text, strInstruments text, strBiography text, "
+ " strDied text, strDisbanded text, strYearsActive text, "
+ " strImage text, strFanart text, "
+ " lastScraped varchar(20) default NULL, "
+ " dateAdded varchar (20) default NULL)");
+ m_pDS->exec("INSERT INTO artist_new "
+ "(idArtist, strArtist, strMusicBrainzArtistID, "
+ " strBorn, strFormed, strGenres, strMoods, "
+ " strStyles , strInstruments , strBiography , "
+ " strDied, strDisbanded, strYearsActive, "
+ " strImage, strFanart) "
+ " SELECT "
+ " artist.idArtist, "
+ " strArtist, strMusicBrainzArtistID, "
+ " strBorn, strFormed, strGenres, strMoods, "
+ " strStyles, strInstruments, strBiography, "
+ " strDied, strDisbanded, strYearsActive, "
+ " strImage, strFanart "
+ " FROM artist "
+ " LEFT JOIN artistinfo ON artist.idArtist = artistInfo.idArtist");
+ m_pDS->exec(PrepareSQL("UPDATE artist_new SET lastScraped='%s' WHERE idArtist IN (SELECT idArtist FROM artistinfo)", CDateTime::GetCurrentDateTime().GetAsDBDateTime().c_str()));
+ m_pDS->exec("DROP TABLE artist");
+ m_pDS->exec("DROP TABLE artistinfo");
+ m_pDS->exec("ALTER TABLE artist_new RENAME TO artist");
+ m_pDS->exec("CREATE INDEX idxDiscography_1 ON discography ( idArtist )\n");
+ }
+ if (version < 41)
+ {
+ // add triggers
+ m_pDS->exec("CREATE TRIGGER tgrAlbumSong AFTER delete ON album FOR EACH ROW BEGIN delete from song where song.idAlbum = old.idAlbum; END");
+ m_pDS->exec("CREATE TRIGGER tgrAlbumArtist AFTER delete ON album FOR EACH ROW BEGIN delete from album_artist where album_artist.idAlbum = old.idAlbum; END");
+ m_pDS->exec("CREATE TRIGGER tgrAlbumGenre AFTER delete ON album FOR EACH ROW BEGIN delete from album_genre where album_genre.idAlbum = old.idAlbum; END");
+ m_pDS->exec("CREATE TRIGGER tgrAlbumAlbumInfo AFTER delete ON album FOR EACH ROW BEGIN delete from albuminfosong where albuminfosong.idAlbumInfo = old.idAlbum; END");
+ m_pDS->exec("CREATE TRIGGER tgrArtistAlbum AFTER delete ON artist FOR EACH ROW BEGIN delete from album_artist where album_artist.idArtist = old.idArtist; END");
+ m_pDS->exec("CREATE TRIGGER tgrArtistSong AFTER delete ON artist FOR EACH ROW BEGIN delete from song_artist where song_artist.idArtist = old.idArtist; END");
+ m_pDS->exec("CREATE TRIGGER tgrArtistDiscography AFTER delete ON artist FOR EACH ROW BEGIN delete from discography where discography.idArtist = old.idArtist; END");
+ m_pDS->exec("CREATE TRIGGER tgrSongArtist AFTER delete ON song FOR EACH ROW BEGIN delete from song_artist where song_artist.idSong = old.idSong; END");
+ m_pDS->exec("CREATE TRIGGER tgrSongGenre AFTER delete ON song FOR EACH ROW BEGIN delete from song_genre where song_genre.idSong = old.idSong; END");
+ m_pDS->exec("CREATE TRIGGER tgrSongKaraokedata AFTER delete ON song FOR EACH ROW BEGIN delete from karaokedata where karaokedata.idSong = old.idSong; END");
+ }
+ if (version < 42)
+ {
+ m_pDS->exec("ALTER TABLE album_artist ADD strArtist text\n");
+ m_pDS->exec("ALTER TABLE song_artist ADD strArtist text\n");
+ // populate these
+ map<int, string> artists;
+ CStdString sql = "select idArtist,strArtist from artist";
+ m_pDS->query(sql.c_str());
+ while (!m_pDS->eof())
+ {
+ m_pDS2->exec(PrepareSQL("UPDATE song_artist SET strArtist='%s' where idArtist=%i", m_pDS->fv(1).get_asString().c_str(), m_pDS->fv(0).get_asInt()));
+ m_pDS2->exec(PrepareSQL("UPDATE album_artist SET strArtist='%s' where idArtist=%i", m_pDS->fv(1).get_asString().c_str(), m_pDS->fv(0).get_asInt()));
+ m_pDS->next();
+ }
+ // drop the last separator if more than one
+ m_pDS->exec("UPDATE song_artist SET strJoinPhrase = '' WHERE 100*idSong+iOrder IN (select 100*idSong+max(iOrder) FROM song_artist GROUP BY idSong)");
+ m_pDS->exec("UPDATE album_artist SET strJoinPhrase = '' WHERE 100*idAlbum+iOrder IN (select 100*idAlbum+max(iOrder) FROM album_artist GROUP BY idAlbum)");
+ }
// always recreate the views after any table change
CreateViews();
@@ -3847,7 +4123,7 @@ bool CMusicDatabase::UpdateOldVersion(int version)
int CMusicDatabase::GetMinVersion() const
{
- return 37;
+ return 42;
}
unsigned int CMusicDatabase::GetSongIDs(const Filter &filter, vector<pair<int,int> > &songIDs)
@@ -4315,13 +4591,6 @@ bool CMusicDatabase::RemoveSongsFromPath(const CStdString &path1, MAPSONGS& song
// and delete all songs, and anything linked to them
sql = "delete from song where idSong in (" + StringUtils::Join(songIds, ",") + ")";
m_pDS->exec(sql.c_str());
- sql = "delete from song_artist where idSong in (" + StringUtils::Join(songIds, ",") + ")";
- m_pDS->exec(sql.c_str());
- sql = "delete from song_genre where idSong in (" + StringUtils::Join(songIds, ",") + ")";
- m_pDS->exec(sql.c_str());
- sql = "delete from karaokedata where idSong in (" + StringUtils::Join(songIds, ",") + ")";
- m_pDS->exec(sql.c_str());
-
}
// and remove the path as well (it'll be re-added later on with the new hash if it's non-empty)
sql = "delete from path" + where;
@@ -4623,11 +4892,21 @@ void CMusicDatabase::ExportToXML(const CStdString &xmlFile, bool singleFiles, bo
if (NULL == m_pDS2.get()) return;
// find all albums
- CStdString sql = "select albumview.*,albuminfo.strImage,albuminfo.idAlbumInfo from albuminfo "
- "join albumview on albuminfo.idAlbum=albumview.idAlbum ";
-
+ vector<int> albumIds;
+ CStdString sql = "select idAlbum FROM album WHERE lastScraped NOT NULL";
m_pDS->query(sql.c_str());
+ int total = m_pDS->num_rows();
+ int current = 0;
+
+ albumIds.reserve(total);
+ while (!m_pDS->eof())
+ {
+ albumIds.push_back(m_pDS->fv("idAlbum").get_asInt());
+ m_pDS->next();
+ }
+ m_pDS->close();
+
CGUIDialogProgress *progress = (CGUIDialogProgress *)g_windowManager.GetWindow(WINDOW_DIALOG_PROGRESS);
if (progress)
{
@@ -4640,9 +4919,6 @@ void CMusicDatabase::ExportToXML(const CStdString &xmlFile, bool singleFiles, bo
progress->ShowProgressBar(true);
}
- int total = m_pDS->num_rows();
- int current = 0;
-
// create our xml document
CXBMCTinyXML xmlDoc;
TiXmlDeclaration decl("1.0", "UTF-8", "yes");
@@ -4655,15 +4931,12 @@ void CMusicDatabase::ExportToXML(const CStdString &xmlFile, bool singleFiles, bo
TiXmlElement xmlMainElement("musicdb");
pMain = xmlDoc.InsertEndChild(xmlMainElement);
}
- while (!m_pDS->eof())
+ for (vector<int>::iterator albumId = albumIds.begin(); albumId != albumIds.end(); ++albumId)
{
- CAlbum album = GetAlbumFromDataset(m_pDS.get());
- album.thumbURL.Clear();
- album.thumbURL.ParseString(m_pDS->fv("albuminfo.strImage").get_asString());
- int idAlbumInfo = m_pDS->fv("albuminfo.idAlbumInfo").get_asInt();
- GetAlbumInfoSongs(idAlbumInfo,album.songs);
+ CAlbum album;
+ GetAlbum(*albumId, album);
CStdString strPath;
- GetAlbumPath(album.idAlbum,strPath);
+ GetAlbumPath(*albumId, strPath);
album.Save(pMain, "album", strPath);
if (singleFiles)
{
@@ -4702,41 +4975,27 @@ void CMusicDatabase::ExportToXML(const CStdString &xmlFile, bool singleFiles, bo
return;
}
}
- m_pDS->next();
current++;
}
- m_pDS->close();
// find all artists
- sql = "SELECT artist.idArtist AS idArtist, strArtist, "
- " strMusicBrainzArtistID, "
- " strBorn, strFormed, strGenres, "
- " strMoods, strStyles, strInstruments, "
- " strBiography, strDied, strDisbanded, "
- " strYearsActive, strImage, strFanart "
- " FROM artist "
- " JOIN artistinfo "
- " ON artist.idArtist=artistinfo.idArtist";
-
- // needed due to getartistpath
- auto_ptr<dbiplus::Dataset> pDS;
- pDS.reset(m_pDB->CreateDataset());
- pDS->query(sql.c_str());
-
- total = pDS->num_rows();
+ vector<int> artistIds;
+ CStdString artistSQL = "SELECT idArtist FROM artist where lastScraped NOT NULL";
+ m_pDS->query(artistSQL.c_str());
+ total = m_pDS->num_rows();
current = 0;
+ artistIds.reserve(total);
+ while (!m_pDS->eof())
+ {
+ artistIds.push_back(m_pDS->fv("idArtist").get_asInt());
+ m_pDS->next();
+ }
+ m_pDS->close();
- while (!pDS->eof())
+ for (vector<int>::iterator artistId = artistIds.begin(); artistId != artistIds.end(); ++artistId)
{
- CArtist artist = GetArtistFromDataset(pDS.get());
- CStdString strSQL=PrepareSQL("select * from discography where idArtist=%i",artist.idArtist);
- m_pDS->query(strSQL.c_str());
- while (!m_pDS->eof())
- {
- artist.discography.push_back(make_pair(m_pDS->fv("strAlbum").get_asString(),m_pDS->fv("strYear").get_asString()));
- m_pDS->next();
- }
- m_pDS->close();
+ CArtist artist;
+ GetArtist(*artistId, artist);
CStdString strPath;
GetArtistPath(artist.idArtist,strPath);
artist.Save(pMain, "artist", strPath);
@@ -4789,10 +5048,8 @@ void CMusicDatabase::ExportToXML(const CStdString &xmlFile, bool singleFiles, bo
return;
}
}
- pDS->next();
current++;
}
- pDS->close();
if (progress)
progress->Close();
@@ -4850,23 +5107,33 @@ void CMusicDatabase::ImportFromXML(const CStdString &xmlFile)
CStdString strTitle;
if (strnicmp(entry->Value(), "artist", 6) == 0)
{
- CArtist artist;
- artist.Load(entry);
- strTitle = artist.strArtist;
- int idArtist = GetArtistByName(artist.strArtist);
+ CArtist importedArtist;
+ importedArtist.Load(entry);
+ strTitle = importedArtist.strArtist;
+ int idArtist = GetArtistByName(importedArtist.strArtist);
if (idArtist > -1)
- SetArtistInfo(idArtist,artist);
+ {
+ CArtist artist;
+ GetArtist(idArtist, artist);
+ artist.MergeScrapedArtist(importedArtist, true);
+ UpdateArtist(artist);
+ }
current++;
}
else if (strnicmp(entry->Value(), "album", 5) == 0)
{
- CAlbum album;
- album.Load(entry);
- strTitle = album.strAlbum;
- int idAlbum = GetAlbumByName(album.strAlbum,album.artist);
+ CAlbum importedAlbum;
+ importedAlbum.Load(entry);
+ strTitle = importedAlbum.strAlbum;
+ int idAlbum = GetAlbumByName(importedAlbum.strAlbum, importedAlbum.artist);
if (idAlbum > -1)
- SetAlbumInfo(idAlbum,album,album.songs,false);
+ {
+ CAlbum album;
+ GetAlbum(idAlbum, album, true);
+ album.MergeScrapedAlbum(importedAlbum, true);
+ UpdateAlbum(album);
+ }
current++;
}
@@ -5012,7 +5279,7 @@ void CMusicDatabase::ExportKaraokeInfo(const CStdString & outFile, bool asHTML)
while (!m_pDS->eof())
{
- CSong song = GetSongFromDataset( false );
+ CSong song = GetSongFromDataset();
CStdString songnum = StringUtils::Format("%06d", song.iKaraokeNumber);
if ( asHTML )
@@ -5306,7 +5573,7 @@ void CMusicDatabase::SetPropertiesForFileItem(CFileItem& item)
if (idArtist > -1)
{
CArtist artist;
- if (GetArtistInfo(idArtist,artist))
+ if (GetArtist(idArtist, artist))
SetPropertiesFromArtist(item,artist);
}
int idAlbum = item.GetMusicInfoTag()->GetAlbumId();
@@ -5316,7 +5583,7 @@ void CMusicDatabase::SetPropertiesForFileItem(CFileItem& item)
if (idAlbum > -1)
{
CAlbum album;
- if (GetAlbumInfo(idAlbum,album,NULL,true)) // true to force additional information
+ if (GetAlbum(idAlbum, album, false))
SetPropertiesFromAlbum(item,album);
}
}
diff --git a/xbmc/music/MusicDatabase.h b/xbmc/music/MusicDatabase.h
index 6927a6df8e..86bd36668c 100644
--- a/xbmc/music/MusicDatabase.h
+++ b/xbmc/music/MusicDatabase.h
@@ -98,7 +98,6 @@ public:
void EmptyCache();
void Clean();
int Cleanup(CGUIDialogProgress *pDlgProgress=NULL);
- void DeleteAlbumInfo();
bool LookupCDDBInfo(bool bRequery=false);
void DeleteCDDBInfo();
@@ -112,7 +111,7 @@ public:
\param strPathAndFileName [in] the path and filename to the song
\param strComment [in] the ids of the added songs
\param strThumb [in] the ids of the added songs
- \param artists [in] a vector of artist names (will only be used for the cache names in the album views)
+ \param artistString [in] the assembled artist string, denormalized from CONCAT(strArtist||strJoinPhrase)
\param genres [in] a vector of genres to which this song belongs
\param iTrack [in] the track number and disc number of the song
\param iDuration [in] the duration of the song
@@ -125,9 +124,32 @@ public:
\param iKaraokeNumber [in] the karaoke id of the song
\return the id of the song
*/
- int AddSong(const int idAlbum, const CStdString& strTitle, const CStdString& strMusicBrainzTrackID, const CStdString& strPathAndFileName, const CStdString& strComment, const CStdString& strThumb, const std::vector<std::string>& artists, const std::vector<std::string>& genres, int iTrack, int iDuration, int iYear, const int iTimesPlayed, int iStartOffset, int iEndOffset, const CDateTime& dtLastPlayed, char rating, int iKaraokeNumber);
+ int AddSong(const int idAlbum,
+ const CStdString& strTitle,
+ const CStdString& strMusicBrainzTrackID,
+ const CStdString& strPathAndFileName,
+ const CStdString& strComment,
+ const CStdString& strThumb,
+ const std::string &artistString, const std::vector<std::string>& genres,
+ int iTrack, int iDuration, int iYear,
+ const int iTimesPlayed, int iStartOffset, int iEndOffset,
+ const CDateTime& dtLastPlayed,
+ char rating, int iKaraokeNumber);
bool GetSong(int idSong, CSong& song);
+ /*! \brief Update a song in the database.
+
+ NOTE: This function assumes that song.artist contains the artist string to be concatenated.
+ Most internal functions should instead use the long-form function as the artist string
+ should be constructed from the artist credits.
+ This function will eventually be demised.
+
+ \param idSong the database ID of the song to update
+ \param song the song
+ \return the id of the song.
+ */
+ int UpdateSong(int idSong, const CSong &song);
+
/*! \brief Update a song in the database
\param idSong [in] the database ID of the song to update
\param strTitle [in] the title of the song (required to be non-empty)
@@ -135,7 +157,7 @@ public:
\param strPathAndFileName [in] the path and filename to the song
\param strComment [in] the ids of the added songs
\param strThumb [in] the ids of the added songs
- \param artists [in] a vector of artist names (will only be used for the cache names in the album views)
+ \param artistString [in] the full artist string, denormalized from CONCAT(song_artist.strArtist || song_artist.strJoinPhrase)
\param genres [in] a vector of genres to which this song belongs
\param iTrack [in] the track number and disc number of the song
\param iDuration [in] the duration of the song
@@ -148,7 +170,15 @@ public:
\param iKaraokeNumber [in] the karaoke id of the song
\return the id of the song
*/
- int UpdateSong(int idSong, const CStdString& strTitle, const CStdString& strMusicBrainzTrackID, const CStdString& strPathAndFileName, const CStdString& strComment, const CStdString& strThumb, const std::vector<std::string>& artists, const std::vector<std::string>& genres, int iTrack, int iDuration, int iYear, int iTimesPlayed, int iStartOffset, int iEndOffset, const CDateTime& dtLastPlayed, char rating, int iKaraokeNumber);
+ int UpdateSong(int idSong,
+ const CStdString& strTitle, const CStdString& strMusicBrainzTrackID,
+ const CStdString& strPathAndFileName, const CStdString& strComment,
+ const CStdString& strThumb,
+ const std::string& artistString, const std::vector<std::string>& genres,
+ int iTrack, int iDuration, int iYear,
+ int iTimesPlayed, int iStartOffset, int iEndOffset,
+ const CDateTime& dtLastPlayed,
+ char rating, int iKaraokeNumber);
// bool DeleteSong(int idSong);
//// Misc Song
@@ -162,15 +192,42 @@ public:
/////////////////////////////////////////////////
// Album
/////////////////////////////////////////////////
+ bool AddAlbum(CAlbum& album);
+ /*! \brief Update an album and all its nested entities (artists, songs, infoSongs, etc)
+ \param album the album to update
+ \return true or false
+ */
+ bool UpdateAlbum(CAlbum& album);
+
/*! \brief Add an album and all its songs to the database
\param album the album to add
\param songIDs [out] the ids of the added songs
\return the id of the album
*/
- int AddAlbum(const CStdString& strAlbum, const CStdString& strMusicBrainzAlbumID, const CStdString& strArtist, const CStdString& strGenre, int year, bool bCompilation);
- bool GetAlbum(int idAlbum, CAlbum& album);
+ int AddAlbum(const CStdString& strAlbum, const CStdString& strMusicBrainzAlbumID,
+ const CStdString& strArtist, const CStdString& strGenre,
+ int year, bool bCompilation);
+ /*! \brief retrieve an album, optionally with all songs.
+ \param idAlbum the database id of the album.
+ \param album [out] the album to fill.
+ \param getSongs whether or not to retrieve songs, defaults to true.
+ \return true if the album is retrieved, false otherwise.
+ */
+ bool GetAlbum(int idAlbum, CAlbum& album, bool getSongs = true);
int UpdateAlbum(int idAlbum, const CAlbum &album);
+ int UpdateAlbum(int idAlbum,
+ const CStdString& strAlbum, const CStdString& strMusicBrainzAlbumID,
+ const CStdString& strArtist, const CStdString& strGenre,
+ const CStdString& strMoods, const CStdString& strStyles,
+ const CStdString& strThemes, const CStdString& strReview,
+ const CStdString& strImage, const CStdString& strLabel,
+ const CStdString& strType,
+ int iRating, int iYear, bool bCompilation);
bool DeleteAlbum(int idAlbum);
+ bool ClearAlbumLastScrapedTime(int idAlbum);
+ bool HasAlbumBeenScraped(int idAlbum);
+ int AddAlbumInfoSong(int idAlbum, const CSong& song);
+
/*! \brief Checks if the given path is inside a folder that has already been scanned into the library
\param path the path we want to check
*/
@@ -186,10 +243,23 @@ public:
/////////////////////////////////////////////////
// Artist CRUD
/////////////////////////////////////////////////
+ bool UpdateArtist(const CArtist& artist);
+
int AddArtist(const CStdString& strArtist, const CStdString& strMusicBrainzArtistID);
- bool GetArtist(int idArtist, CArtist& artist);
- int UpdateArtist(int idArtist, const CArtist& artist);
+ bool GetArtist(int idArtist, CArtist& artist, bool fetchAll = true);
+ int UpdateArtist(int idArtist,
+ const CStdString& strArtist, const CStdString& strMusicBrainzArtistID,
+ const CStdString& strBorn, const CStdString& strFormed,
+ const CStdString& strGenres, const CStdString& strMoods,
+ const CStdString& strStyles, const CStdString& strInstruments,
+ const CStdString& strBiography, const CStdString& strDied,
+ const CStdString& strDisbanded, const CStdString& strYearsActive,
+ const CStdString& strImage, const CStdString& strFanart);
bool DeleteArtist(int idArtist);
+ bool HasArtistBeenScraped(int idArtist);
+ bool ClearArtistLastScrapedTime(int idArtist);
+ int AddArtistDiscography(int idArtist, const CStdString& strAlbum, const CStdString& strYear);
+ bool DeleteArtistDiscography(int idArtist);
CStdString GetArtistById(int id);
int GetArtistByName(const CStdString& strArtist);
@@ -213,43 +283,25 @@ public:
int GetGenreByName(const CStdString& strGenre);
/////////////////////////////////////////////////
- // AlbumInfo
- /////////////////////////////////////////////////
- bool HasAlbumInfo(int idAlbum);
- int SetAlbumInfo(int idAlbum, const CAlbum& album, const VECSONGS& songs, bool bTransaction=true);
- bool GetAlbumInfo(int idAlbum, CAlbum &info, VECSONGS* songs, bool scrapedInfo = false);
- bool DeleteAlbumInfo(int idArtist);
- bool SetAlbumInfoSongs(int idAlbumInfo, const VECSONGS& songs);
- bool GetAlbumInfoSongs(int idAlbumInfo, VECSONGS& songs);
-
- /////////////////////////////////////////////////
- // ArtistInfo
- /////////////////////////////////////////////////
- /*! \brief Check if an artist entity has additional metadata (scraped)
- \param idArtist the id of the Artist to check
- \return true or false - whether the artist has metadata
- */
- bool HasArtistInfo(int idArtist);
- int SetArtistInfo(int idArtist, const CArtist& artist);
- bool GetArtistInfo(int idArtist, CArtist &info, bool needAll=true);
- bool DeleteArtistInfo(int idArtist);
-
- /////////////////////////////////////////////////
// Link tables
/////////////////////////////////////////////////
- bool AddAlbumArtist(int idArtist, int idAlbum, std::string joinPhrase, bool featured, int iOrder);
+ bool AddAlbumArtist(int idArtist, int idAlbum, std::string strArtist, std::string joinPhrase, bool featured, int iOrder);
bool GetAlbumsByArtist(int idArtist, bool includeFeatured, std::vector<int>& albums);
bool GetArtistsByAlbum(int idAlbum, bool includeFeatured, std::vector<int>& artists);
+ bool DeleteAlbumArtistsByAlbum(int idAlbum);
- bool AddSongArtist(int idArtist, int idSong, std::string joinPhrase, bool featured, int iOrder);
+ bool AddSongArtist(int idArtist, int idSong, std::string strArtist, std::string joinPhrase, bool featured, int iOrder);
bool GetSongsByArtist(int idArtist, bool includeFeatured, std::vector<int>& songs);
bool GetArtistsBySong(int idSong, bool includeFeatured, std::vector<int>& artists);
+ bool DeleteSongArtistsBySong(int idSong);
bool AddSongGenre(int idGenre, int idSong, int iOrder);
bool GetGenresBySong(int idSong, std::vector<int>& genres);
+ bool DeleteSongGenresBySong(int idSong);
bool AddAlbumGenre(int idGenre, int idAlbum, int iOrder);
bool GetGenresByAlbum(int idAlbum, std::vector<int>& genres);
+ bool DeleteAlbumGenresByAlbum(int idAlbum);
/////////////////////////////////////////////////
// Top 100
@@ -428,14 +480,16 @@ private:
virtual void CreateViews();
void SplitString(const CStdString &multiString, std::vector<std::string> &vecStrings, CStdString &extraStrings);
- CSong GetSongFromDataset(bool bWithMusicDbPath=false);
- CArtist GetArtistFromDataset(dbiplus::Dataset* pDS, bool needThumb = true);
- CArtist GetArtistFromDataset(const dbiplus::sql_record* const record, bool needThumb = true);
- CAlbum GetAlbumFromDataset(dbiplus::Dataset* pDS, bool imageURL=false);
- CAlbum GetAlbumFromDataset(const dbiplus::sql_record* const record, bool imageURL=false);
- CArtistCredit GetAlbumArtistCreditFromDataset(const dbiplus::sql_record* const record);
+ CSong GetSongFromDataset();
+ CSong GetSongFromDataset(const dbiplus::sql_record* const record, int offset = 0);
+ CArtist GetArtistFromDataset(dbiplus::Dataset* pDS, int offset = 0, bool needThumb = true);
+ CArtist GetArtistFromDataset(const dbiplus::sql_record* const record, int offset = 0, bool needThumb = true);
+ CAlbum GetAlbumFromDataset(dbiplus::Dataset* pDS, int offset = 0, bool imageURL = false);
+ CAlbum GetAlbumFromDataset(const dbiplus::sql_record* const record, int offset = 0, bool imageURL = false);
+ CArtistCredit GetArtistCreditFromDataset(const dbiplus::sql_record* const record, int offset = 0);
void GetFileItemFromDataset(CFileItem* item, const CMusicDbUrl &baseUrl);
void GetFileItemFromDataset(const dbiplus::sql_record* const record, CFileItem* item, const CMusicDbUrl &baseUrl);
+ CSong GetAlbumInfoSongFromDataset(const dbiplus::sql_record* const record, int offset = 0);
bool CleanupSongs();
bool CleanupSongsByIds(const CStdString &strSongIds);
bool CleanupPaths();
@@ -475,7 +529,8 @@ private:
song_iKarDelay,
song_strKarEncoding,
song_bCompilation,
- song_strAlbumArtists
+ song_strAlbumArtists,
+ song_enumCount // end of the enum, do not add past here
} SongFields;
// Fields should be ordered as they
@@ -488,7 +543,6 @@ private:
album_strArtists,
album_strGenres,
album_iYear,
- album_idAlbumInfo,
album_strMoods,
album_strStyles,
album_strThemes,
@@ -499,15 +553,22 @@ private:
album_iRating,
album_bCompilation,
album_iTimesPlayed,
-
- // used for GetAlbumInfo to get the cascaded artist credits
- album_idArtist,
- album_strArtist,
- album_strMusicBrainzArtistID,
- album_bFeatured,
- album_strJoinPhrase
+ album_enumCount // end of the enum, do not add past here
} AlbumFields;
+ enum _ArtistCreditFields
+ {
+ // used for GetAlbum to get the cascaded album/song artist credits
+ artistCredit_idEntity = 0, // can be idSong or idAlbum depending on context
+ artistCredit_idArtist,
+ artistCredit_strArtist,
+ artistCredit_strMusicBrainzArtistID,
+ artistCredit_bFeatured,
+ artistCredit_strJoinPhrase,
+ artistCredit_iOrder,
+ artistCredit_enumCount
+ } ArtistCreditFields;
+
enum _ArtistFields
{
artist_idArtist=0,
@@ -524,6 +585,17 @@ private:
artist_strDisbanded,
artist_strYearsActive,
artist_strImage,
- artist_strFanart
+ artist_strFanart,
+ artist_enumCount // end of the enum, do not add past here
} ArtistFields;
+
+ enum _AlbumInfoSongFields
+ {
+ albumInfoSong_idAlbumInfoSong=0,
+ albumInfoSong_idAlbumInfo,
+ albumInfoSong_iTrack,
+ albumInfoSong_strTitle,
+ albumInfoSong_iDuration,
+ albumInfoSong_enumCount // end of the enum, do not add past here
+ } AlbumInfoSongFields;
};
diff --git a/xbmc/music/MusicInfoLoader.cpp b/xbmc/music/MusicInfoLoader.cpp
index 85425f3f9d..48640076df 100644
--- a/xbmc/music/MusicInfoLoader.cpp
+++ b/xbmc/music/MusicInfoLoader.cpp
@@ -97,11 +97,11 @@ bool CMusicInfoLoader::LoadAdditionalTagInfo(CFileItem* pItem)
CArtist artist;
CMusicDatabase database;
database.Open();
- if (database.GetArtistInfo(param.GetArtistId(),artist,false))
+ if (database.GetArtist(param.GetArtistId(), artist, false))
CMusicDatabase::SetPropertiesFromArtist(*pItem,artist);
CAlbum album;
- if (database.GetAlbumInfo(param.GetAlbumId(),album,NULL))
+ if (database.GetAlbum(param.GetAlbumId(), album, false))
CMusicDatabase::SetPropertiesFromAlbum(*pItem,album);
path = pItem->GetMusicInfoTag()->GetURL();
diff --git a/xbmc/music/Song.cpp b/xbmc/music/Song.cpp
index 8698759968..44a2261f7f 100644
--- a/xbmc/music/Song.cpp
+++ b/xbmc/music/Song.cpp
@@ -72,6 +72,19 @@ CSong::CSong()
Clear();
}
+void CSong::MergeScrapedSong(const CSong& source, bool override)
+{
+ if ((override && !source.strTitle.empty()) || strTitle.empty())
+ strTitle = source.strTitle;
+ if ((override && source.iTrack != 0) || iTrack == 0)
+ iTrack = source.iTrack;
+ // artist = source.artist; // artist is read-only from the database
+ if (override)
+ artistCredits = source.artistCredits;
+ else if (source.artistCredits.size() > artistCredits.size())
+ artistCredits.insert(artistCredits.end(), source.artistCredits.begin()+artistCredits.size(), source.artistCredits.end());
+}
+
void CSong::Serialize(CVariant& value) const
{
value["filename"] = strFileName;
diff --git a/xbmc/music/Song.h b/xbmc/music/Song.h
index eac0e2ca03..4c7e6e2a1d 100644
--- a/xbmc/music/Song.h
+++ b/xbmc/music/Song.h
@@ -58,6 +58,7 @@ public:
CSong(CFileItem& item);
virtual ~CSong(){};
void Clear() ;
+ void MergeScrapedSong(const CSong& source, bool override);
virtual void Serialize(CVariant& value) const;
bool operator<(const CSong &song) const
diff --git a/xbmc/music/dialogs/GUIDialogMusicInfo.cpp b/xbmc/music/dialogs/GUIDialogMusicInfo.cpp
index 62abec3fee..dc2cc4ee06 100644
--- a/xbmc/music/dialogs/GUIDialogMusicInfo.cpp
+++ b/xbmc/music/dialogs/GUIDialogMusicInfo.cpp
@@ -150,7 +150,7 @@ bool CGUIDialogMusicInfo::OnAction(const CAction &action)
void CGUIDialogMusicInfo::SetAlbum(const CAlbum& album, const CStdString &path)
{
m_album = album;
- SetSongs(m_album.songs);
+ SetSongs(m_album.infoSongs);
*m_albumItem = CFileItem(path, true);
m_albumItem->GetMusicInfoTag()->SetAlbum(m_album.strAlbum);
m_albumItem->GetMusicInfoTag()->SetAlbumArtist(StringUtils::Join(m_album.artist, g_advancedSettings.m_musicItemSeparator));
@@ -222,11 +222,24 @@ void CGUIDialogMusicInfo::SetDiscography()
CMusicDatabase database;
database.Open();
+ vector<int> albumsByArtist;
+ database.GetAlbumsByArtist(m_artist.idArtist, true, albumsByArtist);
+
for (unsigned int i=0;i<m_artist.discography.size();++i)
{
CFileItemPtr item(new CFileItem(m_artist.discography[i].first));
item->SetLabel2(m_artist.discography[i].second);
- long idAlbum = database.GetAlbumByName(item->GetLabel(),m_artist.strArtist);
+
+ int idAlbum = -1;
+ for (vector<int>::const_iterator album = albumsByArtist.begin(); album != albumsByArtist.end(); ++album)
+ {
+ if (database.GetAlbumById(*album).Equals(item->GetLabel()))
+ {
+ idAlbum = *album;
+ item->GetMusicInfoTag()->SetDatabaseId(idAlbum, "album");
+ break;
+ }
+ }
if (idAlbum != -1) // we need this slight stupidity to get correct case for the album name
item->SetArt("thumb", database.GetArtForItem(idAlbum, "album", "thumb"));
@@ -541,14 +554,14 @@ void CGUIDialogMusicInfo::OnSearch(const CFileItem* pItem)
{
CMusicDatabase database;
database.Open();
- long idAlbum = database.GetAlbumByName(pItem->GetLabel(),m_artist.strArtist);
- if (idAlbum != -1)
+ if (pItem->HasMusicInfoTag() &&
+ pItem->GetMusicInfoTag()->GetDatabaseId() > 0)
{
CAlbum album;
- if (database.GetAlbumInfo(idAlbum,album,&album.songs))
+ if (database.GetAlbum(pItem->GetMusicInfoTag()->GetDatabaseId(), album))
{
CStdString strPath;
- database.GetAlbumPath(idAlbum,strPath);
+ database.GetAlbumPath(pItem->GetMusicInfoTag()->GetDatabaseId(), strPath);
SetAlbum(album,strPath);
Update();
}
diff --git a/xbmc/music/infoscanner/MusicAlbumInfo.h b/xbmc/music/infoscanner/MusicAlbumInfo.h
index 947927fd27..e764a233c2 100644
--- a/xbmc/music/infoscanner/MusicAlbumInfo.h
+++ b/xbmc/music/infoscanner/MusicAlbumInfo.h
@@ -44,7 +44,7 @@ public:
const CAlbum &GetAlbum() const { return m_album; }
CAlbum& GetAlbum() { return m_album; }
void SetAlbum(CAlbum& album);
- const VECSONGS &GetSongs() const { return m_album.songs; }
+ const VECSONGS &GetSongs() const { return m_album.infoSongs; }
const CStdString& GetTitle2() const { return m_strTitle2; }
void SetTitle(const CStdString& strTitle) { m_album.strAlbum = strTitle; }
const CScraperUrl& GetAlbumURL() const { return m_albumURL; }
diff --git a/xbmc/music/infoscanner/MusicInfoScanner.cpp b/xbmc/music/infoscanner/MusicInfoScanner.cpp
index a57a35d7ee..53f090e8c8 100644
--- a/xbmc/music/infoscanner/MusicInfoScanner.cpp
+++ b/xbmc/music/infoscanner/MusicInfoScanner.cpp
@@ -117,8 +117,7 @@ void CMusicInfoScanner::Process()
m_bCanInterrupt = false;
m_needsCleanup = false;
- bool commit = false;
- bool cancelled = false;
+ bool commit = true;
for (std::set<std::string>::const_iterator it = m_pathsToScan.begin(); it != m_pathsToScan.end(); it++)
{
if (!CDirectory::Exists(*it) && !m_bClean)
@@ -133,8 +132,10 @@ void CMusicInfoScanner::Process()
continue;
}
else if (!DoScan(*it))
- cancelled = true;
- commit = !cancelled;
+ {
+ commit = false;
+ break;
+ }
}
if (commit)
@@ -171,11 +172,11 @@ void CMusicInfoScanner::Process()
{
CQueryParams params;
CDirectoryNode::GetDatabaseInfo(*it, params);
- if (m_musicDatabase.HasAlbumInfo(params.GetArtistId())) // should this be here?
+ if (m_musicDatabase.HasAlbumBeenScraped(params.GetAlbumId())) // should this be here?
continue;
CAlbum album;
- m_musicDatabase.GetAlbumInfo(params.GetAlbumId(), album, &album.songs);
+ m_musicDatabase.GetAlbum(params.GetAlbumId(), album);
if (m_handle)
{
float percentage = (float) std::distance(it, m_pathsToScan.end()) / m_pathsToScan.size();
@@ -183,8 +184,12 @@ void CMusicInfoScanner::Process()
m_handle->SetPercentage(percentage);
}
- CMusicAlbumInfo albumInfo;
- UpdateDatabaseAlbumInfo(*it, albumInfo, false);
+ // find album info
+ ADDON::ScraperPtr scraper;
+ if (!m_musicDatabase.GetScraperForPath(*it, scraper, ADDON::ADDON_SCRAPER_ALBUMS))
+ continue;
+
+ UpdateDatabaseAlbumInfo(album, scraper, false);
if (m_bStop)
break;
@@ -196,11 +201,11 @@ void CMusicInfoScanner::Process()
{
CQueryParams params;
CDirectoryNode::GetDatabaseInfo(*it, params);
- if (m_musicDatabase.HasArtistInfo(params.GetArtistId())) // should this be here?
+ if (m_musicDatabase.HasArtistBeenScraped(params.GetArtistId())) // should this be here?
continue;
CArtist artist;
- m_musicDatabase.GetArtistInfo(params.GetArtistId(), artist);
+ m_musicDatabase.GetArtist(params.GetArtistId(), artist);
m_musicDatabase.GetArtistPath(params.GetArtistId(), artist.strPath);
if (m_handle)
@@ -209,9 +214,13 @@ void CMusicInfoScanner::Process()
m_handle->SetText(artist.strArtist);
m_handle->SetPercentage(percentage);
}
-
- CMusicArtistInfo artistInfo;
- UpdateDatabaseArtistInfo(*it, artistInfo, false);
+
+ // find album info
+ ADDON::ScraperPtr scraper;
+ if (!m_musicDatabase.GetScraperForPath(*it, scraper, ADDON::ADDON_SCRAPER_ARTISTS) || !scraper)
+ continue;
+
+ UpdateDatabaseArtistInfo(artist, scraper, false);
if (m_bStop)
break;
@@ -296,7 +305,7 @@ void CMusicInfoScanner::FetchAlbumInfo(const CStdString& strDirectory,
m_pathsToScan.insert(items[i]->GetPath());
if (refresh)
{
- m_musicDatabase.DeleteAlbumInfo(items[i]->GetMusicInfoTag()->GetDatabaseId());
+ m_musicDatabase.ClearAlbumLastScrapedTime(items[i]->GetMusicInfoTag()->GetDatabaseId());
}
}
m_musicDatabase.Close();
@@ -340,7 +349,7 @@ void CMusicInfoScanner::FetchArtistInfo(const CStdString& strDirectory,
m_pathsToScan.insert(items[i]->GetPath());
if (refresh)
{
- m_musicDatabase.DeleteArtistInfo(items[i]->GetMusicInfoTag()->GetDatabaseId());
+ m_musicDatabase.ClearArtistLastScrapedTime(items[i]->GetMusicInfoTag()->GetDatabaseId());
}
}
m_musicDatabase.Close();
@@ -681,7 +690,7 @@ int CMusicInfoScanner::RetrieveMusicInfo(const CStdString& strDirectory, CFileIt
m_needsCleanup = true;
CFileItemList scannedItems;
- if (ScanTags(items, scannedItems) == INFO_CANCELLED)
+ if (ScanTags(items, scannedItems) == INFO_CANCELLED || scannedItems.Size() == 0)
return 0;
VECALBUMS albums;
@@ -705,196 +714,79 @@ int CMusicInfoScanner::RetrieveMusicInfo(const CStdString& strDirectory, CFileIt
break;
album->strPath = strDirectory;
- m_musicDatabase.BeginTransaction();
-
- // Check if the album has already been downloaded or failed
- map<CAlbum, CAlbum>::iterator cachedAlbum = m_albumCache.find(*album);
- if (cachedAlbum == m_albumCache.end())
+ m_musicDatabase.AddAlbum(*album);
+
+ // Yuk - this is a kludgy way to do what we want to do, but it will work to sort
+ // out artist fanart until we can restructure the artist fanart to work more
+ // like the album fanart. This has to be done after we've added the album so
+ // we have the artist IDs to update, but before we call UpdateDatabaseArtistInfo.
+ if (albums.size() == 1 &&
+ album->artistCredits.size() > 0 &&
+ !StringUtils::EqualsNoCase(album->artistCredits[0].GetArtist(), "various artists") &&
+ !StringUtils::EqualsNoCase(album->artistCredits[0].GetArtist(), "various"))
{
- // No - download the information
- CMusicAlbumInfo albumInfo;
- INFO_RET albumDownloadStatus = INFO_NOT_FOUND;
- if ((m_flags & SCAN_ONLINE) && albumScraper)
- albumDownloadStatus = DownloadAlbumInfo(*album, albumScraper, albumInfo);
-
- if (albumDownloadStatus == INFO_ADDED || albumDownloadStatus == INFO_HAVE_ALREADY)
- {
- CAlbum &downloadedAlbum = albumInfo.GetAlbum();
- downloadedAlbum.idAlbum = m_musicDatabase.AddAlbum(downloadedAlbum.strAlbum,
- downloadedAlbum.strMusicBrainzAlbumID,
- downloadedAlbum.GetArtistString(),
- downloadedAlbum.GetGenreString(),
- downloadedAlbum.iYear,
- downloadedAlbum.bCompilation);
- m_musicDatabase.SetAlbumInfo(downloadedAlbum.idAlbum,
- downloadedAlbum,
- downloadedAlbum.songs);
- m_musicDatabase.SetArtForItem(downloadedAlbum.idAlbum,
- "album", album->art);
- GetAlbumArtwork(downloadedAlbum.idAlbum, downloadedAlbum);
- m_albumCache.insert(make_pair(*album, albumInfo.GetAlbum()));
- }
- else if (albumDownloadStatus == INFO_CANCELLED)
- break;
- else
+ CArtist artist;
+ if (m_musicDatabase.GetArtist(album->artistCredits[0].GetArtistId(), artist))
{
- // No download info, fallback to already gathered (eg. local) information/art (if any)
- album->idAlbum = m_musicDatabase.AddAlbum(album->strAlbum,
- album->strMusicBrainzAlbumID,
- album->GetArtistString(),
- album->GetGenreString(),
- album->iYear,
- album->bCompilation);
- if (!album->art.empty())
- m_musicDatabase.SetArtForItem(album->idAlbum,
- "album", album->art);
- m_albumCache.insert(make_pair(*album, *album));
+ artist.strPath = URIUtils::GetParentPath(strDirectory);
+ m_musicDatabase.SetArtForItem(artist.idArtist, "artist", GetArtistArtwork(artist));
}
-
- // Update the cache pointer with our newly created info
- cachedAlbum = m_albumCache.find(*album);
}
- if (m_bStop)
- break;
-
- // Add the album artists
- for (VECARTISTCREDITS::iterator artistCredit = cachedAlbum->second.artistCredits.begin(); artistCredit != cachedAlbum->second.artistCredits.end(); ++artistCredit)
+ if ((m_flags & SCAN_ONLINE))
{
- if (m_bStop)
- break;
+ if (!albumScraper || !artistScraper)
+ continue;
- // Check if the artist has already been downloaded or failed
- map<CArtistCredit, CArtist>::iterator cachedArtist = m_artistCache.find(*artistCredit);
- if (cachedArtist == m_artistCache.end())
- {
- CArtist artistTmp;
- artistTmp.strArtist = artistCredit->GetArtist();
- artistTmp.strMusicBrainzArtistID = artistCredit->GetMusicBrainzArtistID();
- URIUtils::GetParentPath(album->strPath, artistTmp.strPath);
-
- // No - download the information
- CMusicArtistInfo artistInfo;
- INFO_RET artistDownloadStatus = INFO_NOT_FOUND;
- if ((m_flags & SCAN_ONLINE) && artistScraper)
- artistDownloadStatus = DownloadArtistInfo(artistTmp, artistScraper, artistInfo);
-
- if (artistDownloadStatus == INFO_ADDED || artistDownloadStatus == INFO_HAVE_ALREADY)
- {
- CArtist &downloadedArtist = artistInfo.GetArtist();
- downloadedArtist.idArtist = m_musicDatabase.AddArtist(downloadedArtist.strArtist,
- downloadedArtist.strMusicBrainzArtistID);
- m_musicDatabase.SetArtistInfo(downloadedArtist.idArtist,
- downloadedArtist);
-
- URIUtils::GetParentPath(album->strPath, downloadedArtist.strPath);
- map<string, string> artwork = GetArtistArtwork(downloadedArtist);
- // check thumb stuff
- m_musicDatabase.SetArtForItem(downloadedArtist.idArtist, "artist", artwork);
- m_artistCache.insert(make_pair(*artistCredit, downloadedArtist));
- }
- else if (artistDownloadStatus == INFO_CANCELLED)
- break;
- else
- {
- // Cache the lookup failure so we don't retry
- artistTmp.idArtist = m_musicDatabase.AddArtist(artistCredit->GetArtist(), artistCredit->GetMusicBrainzArtistID());
- m_artistCache.insert(make_pair(*artistCredit, artistTmp));
- }
-
- // Update the cache pointer with our newly created info
- cachedArtist = m_artistCache.find(*artistCredit);
- }
+ INFO_RET albumScrapeStatus = INFO_NOT_FOUND;
+ if (!m_musicDatabase.HasAlbumBeenScraped(album->idAlbum))
+ albumScrapeStatus = UpdateDatabaseAlbumInfo(*album, albumScraper, false);
- m_musicDatabase.AddAlbumArtist(cachedArtist->second.idArtist,
- cachedAlbum->second.idAlbum,
- artistCredit->GetJoinPhrase(),
- artistCredit == cachedAlbum->second.artistCredits.begin() ? false : true,
- std::distance(cachedAlbum->second.artistCredits.begin(), artistCredit));
- }
-
- if (m_bStop)
- break;
-
- for (VECSONGS::iterator song = album->songs.begin(); song != album->songs.end(); ++song)
- {
- song->idAlbum = cachedAlbum->second.idAlbum;
- song->idSong = m_musicDatabase.AddSong(cachedAlbum->second.idAlbum,
- song->strTitle, song->strMusicBrainzTrackID,
- song->strFileName, song->strComment,
- song->strThumb,
- song->artist, song->genre,
- song->iTrack, song->iDuration, song->iYear,
- song->iTimesPlayed, song->iStartOffset,
- song->iEndOffset,
- song->lastPlayed,
- song->rating,
- song->iKaraokeNumber);
- for (VECARTISTCREDITS::iterator artistCredit = song->artistCredits.begin(); artistCredit != song->artistCredits.end(); ++artistCredit)
+ if (albumScrapeStatus == INFO_ADDED)
{
- if (m_bStop)
- break;
-
- // Check if the artist has already been downloaded or failed
- map<CArtistCredit, CArtist>::iterator cachedArtist = m_artistCache.find(*artistCredit);
- if (cachedArtist == m_artistCache.end())
+ for (VECARTISTCREDITS::const_iterator artistCredit = album->artistCredits.begin();
+ artistCredit != album->artistCredits.end();
+ ++artistCredit)
{
- CArtist artistTmp;
- artistTmp.strArtist = artistCredit->GetArtist();
- artistTmp.strMusicBrainzArtistID = artistCredit->GetMusicBrainzArtistID();
- URIUtils::GetParentPath(album->strPath, artistTmp.strPath); // FIXME
-
- // No - download the information
- CMusicArtistInfo artistInfo;
- INFO_RET artistDownloadStatus = INFO_NOT_FOUND;
- if ((m_flags & SCAN_ONLINE) && artistScraper)
- artistDownloadStatus = DownloadArtistInfo(artistTmp, artistScraper, artistInfo);
-
- if (artistDownloadStatus == INFO_ADDED || artistDownloadStatus == INFO_HAVE_ALREADY)
+ if (m_bStop)
+ break;
+
+ if (!m_musicDatabase.HasArtistBeenScraped(artistCredit->GetArtistId()))
{
- CArtist &downloadedArtist = artistInfo.GetArtist();
- downloadedArtist.idArtist = m_musicDatabase.AddArtist(downloadedArtist.strArtist,
- downloadedArtist.strMusicBrainzArtistID);
- m_musicDatabase.SetArtistInfo(downloadedArtist.idArtist,
- downloadedArtist);
- // check thumb stuff
- URIUtils::GetParentPath(album->strPath, downloadedArtist.strPath);
- map<string, string> artwork = GetArtistArtwork(downloadedArtist);
- m_musicDatabase.SetArtForItem(downloadedArtist.idArtist, "artist", artwork);
- m_artistCache.insert(make_pair(*artistCredit, downloadedArtist));
+ CArtist artist;
+ m_musicDatabase.GetArtist(artistCredit->GetArtistId(), artist);
+ UpdateDatabaseArtistInfo(artist, artistScraper, false);
}
- else if (artistDownloadStatus == INFO_CANCELLED)
+ }
+
+ for (VECSONGS::iterator song = album->songs.begin();
+ song != album->songs.end();
+ song++)
+ {
+ if (m_bStop)
break;
- else
+
+ for (VECARTISTCREDITS::const_iterator artistCredit = song->artistCredits.begin();
+ artistCredit != song->artistCredits.end();
+ ++artistCredit)
{
- // Cache the lookup failure so we don't retry
- artistTmp.idArtist = m_musicDatabase.AddArtist(artistCredit->GetArtist(), artistCredit->GetMusicBrainzArtistID());
- m_artistCache.insert(make_pair(*artistCredit, artistTmp));
- }
+ if (m_bStop)
+ break;
- // Update the cache pointer with our newly created info
- cachedArtist = m_artistCache.find(*artistCredit);
+ CMusicArtistInfo musicArtistInfo;
+ if (!m_musicDatabase.HasArtistBeenScraped(artistCredit->GetArtistId()))
+ {
+ CArtist artist;
+ m_musicDatabase.GetArtist(artistCredit->GetArtistId(), artist);
+ UpdateDatabaseArtistInfo(artist, artistScraper, false);
+ }
+ }
}
-
- m_musicDatabase.AddSongArtist(cachedArtist->second.idArtist,
- song->idSong,
- g_advancedSettings.m_musicItemSeparator, // we don't have song artist breakdowns from scrapers, yet
- artistCredit == song->artistCredits.begin() ? false : true,
- std::distance(song->artistCredits.begin(), artistCredit));
}
}
-
- if (m_bStop)
- break;
-
- // Commit the album to the DB
- m_musicDatabase.CommitTransaction();
numAdded += album->songs.size();
}
- if (m_bStop)
- m_musicDatabase.RollbackTransaction();
-
if (m_handle)
m_handle->SetTitle(g_localizeStrings.Get(505));
@@ -1003,26 +895,12 @@ int CMusicInfoScanner::GetPathHash(const CFileItemList &items, CStdString &hash)
return count;
}
-INFO_RET CMusicInfoScanner::UpdateDatabaseAlbumInfo(const CStdString& strPath, CMusicAlbumInfo& albumInfo, bool bAllowSelection, CGUIDialogProgress* pDialog /* = NULL */)
+INFO_RET CMusicInfoScanner::UpdateDatabaseAlbumInfo(CAlbum& album, const ADDON::ScraperPtr& scraper, bool bAllowSelection, CGUIDialogProgress* pDialog /* = NULL */)
{
- m_musicDatabase.Open();
- CQueryParams params;
- CDirectoryNode::GetDatabaseInfo(strPath, params);
-
- if (params.GetAlbumId() == -1)
+ if (!scraper)
return INFO_ERROR;
- CAlbum album;
- m_musicDatabase.GetAlbumInfo(params.GetAlbumId(), album, &album.songs);
-
- // find album info
- ADDON::ScraperPtr scraper;
- bool result = m_musicDatabase.GetScraperForPath(strPath, scraper, ADDON::ADDON_SCRAPER_ALBUMS);
-
- m_musicDatabase.Close();
-
- if (!result || !scraper)
- return INFO_ERROR;
+ CMusicAlbumInfo albumInfo;
loop:
CLog::Log(LOGDEBUG, "%s downloading info for: %s", __FUNCTION__, album.strAlbum.c_str());
@@ -1044,32 +922,22 @@ loop:
}
else if (albumDownloadStatus == INFO_ADDED)
{
+ album.MergeScrapedAlbum(albumInfo.GetAlbum(), CSettings::Get().GetBool("musiclibrary.overridetags"));
m_musicDatabase.Open();
- m_musicDatabase.SetAlbumInfo(params.GetAlbumId(), albumInfo.GetAlbum(), albumInfo.GetAlbum().songs);
- GetAlbumArtwork(params.GetAlbumId(), albumInfo.GetAlbum());
- albumInfo.SetLoaded(true);
+ m_musicDatabase.UpdateAlbum(album);
+ GetAlbumArtwork(album.idAlbum, album);
m_musicDatabase.Close();
+ albumInfo.SetLoaded(true);
}
return albumDownloadStatus;
}
-INFO_RET CMusicInfoScanner::UpdateDatabaseArtistInfo(const CStdString& strPath, CMusicArtistInfo& artistInfo, bool bAllowSelection, CGUIDialogProgress* pDialog /* = NULL */)
+INFO_RET CMusicInfoScanner::UpdateDatabaseArtistInfo(CArtist& artist, const ADDON::ScraperPtr& scraper, bool bAllowSelection, CGUIDialogProgress* pDialog /* = NULL */)
{
- m_musicDatabase.Open();
- CQueryParams params;
- CDirectoryNode::GetDatabaseInfo(strPath, params);
-
- if (params.GetArtistId() == -1)
+ if (!scraper)
return INFO_ERROR;
- CArtist artist;
- m_musicDatabase.GetArtistInfo(params.GetArtistId(), artist);
-
- // find album info
- ADDON::ScraperPtr scraper;
- if (!m_musicDatabase.GetScraperForPath(strPath, scraper, ADDON::ADDON_SCRAPER_ARTISTS) || !scraper)
- return INFO_ERROR;
- m_musicDatabase.Close();
+ CMusicArtistInfo artistInfo;
loop:
CLog::Log(LOGDEBUG, "%s downloading info for: %s", __FUNCTION__, artist.strArtist.c_str());
@@ -1085,20 +953,20 @@ loop:
}
else if (artistDownloadStatus == INFO_ADDED)
{
+ artist.MergeScrapedArtist(artistInfo.GetArtist(), CSettings::Get().GetBool("musiclibrary.overridetags"));
m_musicDatabase.Open();
- m_musicDatabase.SetArtistInfo(params.GetArtistId(), artistInfo.GetArtist());
- m_musicDatabase.GetArtistPath(params.GetArtistId(), artist.strPath);
- map<string, string> artwork = GetArtistArtwork(artist);
- m_musicDatabase.SetArtForItem(params.GetArtistId(), "artist", artwork);
- artistInfo.SetLoaded();
+ m_musicDatabase.UpdateArtist(artist);
+ m_musicDatabase.GetArtistPath(artist.idArtist, artist.strPath);
+ m_musicDatabase.SetArtForItem(artist.idArtist, "artist", GetArtistArtwork(artist));
m_musicDatabase.Close();
+ artistInfo.SetLoaded();
}
return artistDownloadStatus;
}
#define THRESHOLD .95f
-INFO_RET CMusicInfoScanner::DownloadAlbumInfo(const CAlbum& album, ADDON::ScraperPtr& info, CMusicAlbumInfo& albumInfo, CGUIDialogProgress* pDialog)
+INFO_RET CMusicInfoScanner::DownloadAlbumInfo(const CAlbum& album, const ADDON::ScraperPtr& info, CMusicAlbumInfo& albumInfo, CGUIDialogProgress* pDialog)
{
if (m_handle)
{
@@ -1141,10 +1009,10 @@ INFO_RET CMusicInfoScanner::DownloadAlbumInfo(const CAlbum& album, ADDON::Scrape
{
CScraperUrl scrUrl(nfoReader.ScraperUrl());
CMusicAlbumInfo albumNfo("nfo",scrUrl);
- info = nfoReader.GetScraperInfo();
- CLog::Log(LOGDEBUG,"-- nfo-scraper: %s",info->Name().c_str());
+ ADDON::ScraperPtr nfoReaderScraper = nfoReader.GetScraperInfo();
+ CLog::Log(LOGDEBUG,"-- nfo-scraper: %s", nfoReaderScraper->Name().c_str());
CLog::Log(LOGDEBUG,"-- nfo url: %s", scrUrl.m_url[0].m_url.c_str());
- scraper.SetScraperInfo(info);
+ scraper.SetScraperInfo(nfoReaderScraper);
scraper.GetAlbums().clear();
scraper.GetAlbums().push_back(albumNfo);
}
@@ -1310,7 +1178,7 @@ void CMusicInfoScanner::GetAlbumArtwork(long id, const CAlbum &album)
}
}
-INFO_RET CMusicInfoScanner::DownloadArtistInfo(const CArtist& artist, ADDON::ScraperPtr& info, MUSIC_GRABBER::CMusicArtistInfo& artistInfo, CGUIDialogProgress* pDialog)
+INFO_RET CMusicInfoScanner::DownloadArtistInfo(const CArtist& artist, const ADDON::ScraperPtr& info, MUSIC_GRABBER::CMusicArtistInfo& artistInfo, CGUIDialogProgress* pDialog)
{
if (m_handle)
{
@@ -1353,10 +1221,10 @@ INFO_RET CMusicInfoScanner::DownloadArtistInfo(const CArtist& artist, ADDON::Scr
{
CScraperUrl scrUrl(nfoReader.ScraperUrl());
CMusicArtistInfo artistNfo("nfo",scrUrl);
- info = nfoReader.GetScraperInfo();
- CLog::Log(LOGDEBUG,"-- nfo-scraper: %s",info->Name().c_str());
+ ADDON::ScraperPtr nfoReaderScraper = nfoReader.GetScraperInfo();
+ CLog::Log(LOGDEBUG,"-- nfo-scraper: %s",nfoReaderScraper->Name().c_str());
CLog::Log(LOGDEBUG,"-- nfo url: %s", scrUrl.m_url[0].m_url.c_str());
- scraper.SetScraperInfo(info);
+ scraper.SetScraperInfo(nfoReaderScraper);
scraper.GetArtists().push_back(artistNfo);
}
else
diff --git a/xbmc/music/infoscanner/MusicInfoScanner.h b/xbmc/music/infoscanner/MusicInfoScanner.h
index c43bd6d8a0..87dce55d4f 100644
--- a/xbmc/music/infoscanner/MusicInfoScanner.h
+++ b/xbmc/music/infoscanner/MusicInfoScanner.h
@@ -111,26 +111,26 @@ public:
static void FindArtForAlbums(VECALBUMS &albums, const CStdString &path);
/*! \brief Update the database information for a MusicDB album
- Given a musicdb:// style path pointing to an album, search and update its info
- with the scrapers. If info is found, update the database and artwork with the new
+ Given an album, search and update its info with the given scraper.
+ If info is found, update the database and artwork with the new
information.
- \param strPath [in] musicdb:// style path to the album in the database
- \param albumInfo [in/out] a CMusicAlbumInfo struct which will be populated with the output of the scraper
- \param pDialog [in] a progress dialog which this and downstream functions can update with status, if required
+ \param album [in/out] the album to update
+ \param scraper [in] the album scraper to use
\param bAllowSelection [in] should we allow the user to manually override the info with a GUI if the album is not found?
+ \param pDialog [in] a progress dialog which this and downstream functions can update with status, if required
*/
- INFO_RET UpdateDatabaseAlbumInfo(const CStdString& strPath, MUSIC_GRABBER::CMusicAlbumInfo& albumInfo, bool bAllowSelection, CGUIDialogProgress* pDialog = NULL);
+ INFO_RET UpdateDatabaseAlbumInfo(CAlbum& album, const ADDON::ScraperPtr& scraper, bool bAllowSelection, CGUIDialogProgress* pDialog = NULL);
/*! \brief Update the database information for a MusicDB artist
- Given a musicdb:// style path pointing to an artist, search and update its info
- with the scrapers. If info is found, update the database and artwork with the new
+ Given an artist, search and update its info with the given scraper.
+ If info is found, update the database and artwork with the new
information.
- \param strPath [in] musicdb:// style path to the artist in the database
- \param albumInfo [in/out] a CMusicArtistInfo struct which will be populated with the output of the scraper
- \param pDialog [in] a progress dialog which this and downstream functions can update with status, if required
+ \param artist [in/out] the artist to update
+ \param scraper [in] the artist scraper to use
\param bAllowSelection [in] should we allow the user to manually override the info with a GUI if the album is not found?
+ \param pDialog [in] a progress dialog which this and downstream functions can update with status, if required
*/
- INFO_RET UpdateDatabaseArtistInfo(const CStdString& strPath, MUSIC_GRABBER::CMusicArtistInfo& artistInfo, bool bAllowSelection, CGUIDialogProgress* pDialog = NULL);
+ INFO_RET UpdateDatabaseArtistInfo(CArtist& artist, const ADDON::ScraperPtr& scraper, bool bAllowSelection, CGUIDialogProgress* pDialog = NULL);
/*! \brief Using the scrapers download metadata for an album
Given a CAlbum style struct containing some data about an album, query
@@ -142,7 +142,7 @@ public:
\param albumInfo [in/out] a CMusicAlbumInfo struct which will be populated with the output of the scraper
\param pDialog [in] a progress dialog which this and downstream functions can update with status, if required
*/
- INFO_RET DownloadAlbumInfo(const CAlbum& album, ADDON::ScraperPtr& scraper, MUSIC_GRABBER::CMusicAlbumInfo& albumInfo, CGUIDialogProgress* pDialog = NULL);
+ INFO_RET DownloadAlbumInfo(const CAlbum& album, const ADDON::ScraperPtr& scraper, MUSIC_GRABBER::CMusicAlbumInfo& albumInfo, CGUIDialogProgress* pDialog = NULL);
/*! \brief Using the scrapers download metadata for an artist
Given a CAlbum style struct containing some data about an artist, query
@@ -154,7 +154,7 @@ public:
\param artistInfo [in/out] a CMusicAlbumInfo struct which will be populated with the output of the scraper
\param pDialog [in] a progress dialog which this and downstream functions can update with status, if required
*/
- INFO_RET DownloadArtistInfo(const CArtist& artist, ADDON::ScraperPtr& scraper, MUSIC_GRABBER::CMusicArtistInfo& artistInfo, CGUIDialogProgress* pDialog = NULL);
+ INFO_RET DownloadArtistInfo(const CArtist& artist, const ADDON::ScraperPtr& scraper, MUSIC_GRABBER::CMusicArtistInfo& artistInfo, CGUIDialogProgress* pDialog = NULL);
/*! \brief Search for art for an artist
Look for art for an artist. Checks the artist structure for thumbs, and checks
diff --git a/xbmc/music/windows/GUIWindowMusicBase.cpp b/xbmc/music/windows/GUIWindowMusicBase.cpp
index 8ca6877e60..f5261b70f4 100644
--- a/xbmc/music/windows/GUIWindowMusicBase.cpp
+++ b/xbmc/music/windows/GUIWindowMusicBase.cpp
@@ -252,7 +252,7 @@ bool CGUIWindowMusicBase::OnAction(const CAction &action)
return CGUIMediaWindow::OnAction(action);
}
-void CGUIWindowMusicBase::OnInfoAll(int iItem, bool bCurrent, bool refresh)
+void CGUIWindowMusicBase::OnInfoAll(int iItem, bool bCurrent /* = false */, bool refresh /* = false */)
{
CMusicDatabaseDirectory dir;
CStdString strPath = m_vecItems->GetPath();
@@ -364,12 +364,19 @@ void CGUIWindowMusicBase::ShowArtistInfo(const CFileItem *pItem, bool bShowInfo
{
CQueryParams params;
CDirectoryNode::GetDatabaseInfo(pItem->GetPath(), params);
- CMusicArtistInfo artistInfo;
+
+ ADDON::ScraperPtr scraper;
+ if (!m_musicdatabase.GetScraperForPath(pItem->GetPath(), scraper, ADDON::ADDON_SCRAPER_ARTISTS))
+ return;
+
+ CArtist artist;
+ if (!m_musicdatabase.GetArtist(params.GetArtistId(), artist))
+ return;
+
while (1)
{
// Check if we have the information in the database first
- if (!m_musicdatabase.HasArtistInfo(params.GetArtistId()) ||
- !m_musicdatabase.GetArtistInfo(params.GetArtistId(), artistInfo.GetArtist()))
+ if (!m_musicdatabase.HasArtistBeenScraped(params.GetArtistId()))
{
if (!CProfilesManager::Get().GetCurrentProfile().canWriteDatabases() && !g_passwordManager.bMasterUser)
break; // should display a dialog saying no permissions
@@ -391,7 +398,7 @@ void CGUIWindowMusicBase::ShowArtistInfo(const CFileItem *pItem, bool bShowInfo
}
CMusicInfoScanner scanner;
- if (scanner.UpdateDatabaseArtistInfo(pItem->GetPath(), artistInfo, bShowInfo) != INFO_ADDED || !artistInfo.Loaded())
+ if (scanner.UpdateDatabaseArtistInfo(artist, scraper, bShowInfo, m_dlgProgress) != INFO_ADDED)
{
CGUIDialogOK::ShowAndGetInput(21889, 0, 20199, 0);
break;
@@ -406,12 +413,12 @@ void CGUIWindowMusicBase::ShowArtistInfo(const CFileItem *pItem, bool bShowInfo
{
CStdString strPath;
m_musicdatabase.GetArtistPath(params.GetArtistId(), strPath);
- pDlgArtistInfo->SetArtist(artistInfo.GetArtist(), strPath);
+ pDlgArtistInfo->SetArtist(artist, strPath);
pDlgArtistInfo->DoModal();
if (pDlgArtistInfo->NeedRefresh())
{
- m_musicdatabase.DeleteArtistInfo(params.GetArtistId());
+ m_musicdatabase.ClearArtistLastScrapedTime(params.GetArtistId());
continue;
}
else if (pDlgArtistInfo->HasUpdatedThumb())
@@ -429,11 +436,18 @@ bool CGUIWindowMusicBase::ShowAlbumInfo(const CFileItem *pItem, bool bShowInfo /
{
CQueryParams params;
CDirectoryNode::GetDatabaseInfo(pItem->GetPath(), params);
- CMusicAlbumInfo albumInfo;
+
+ ADDON::ScraperPtr scraper;
+ if (!m_musicdatabase.GetScraperForPath(pItem->GetPath(), scraper, ADDON::ADDON_SCRAPER_ALBUMS))
+ return false;
+
+ CAlbum album;
+ if (!m_musicdatabase.GetAlbum(params.GetAlbumId(), album))
+ return false;
+
while (1)
{
- if (!m_musicdatabase.HasAlbumInfo(params.GetAlbumId()) ||
- !m_musicdatabase.GetAlbumInfo(params.GetAlbumId(), albumInfo.GetAlbum(), &albumInfo.GetAlbum().songs))
+ if (!m_musicdatabase.HasAlbumBeenScraped(params.GetAlbumId()))
{
if (!CProfilesManager::Get().GetCurrentProfile().canWriteDatabases() && !g_passwordManager.bMasterUser)
{
@@ -462,7 +476,7 @@ bool CGUIWindowMusicBase::ShowAlbumInfo(const CFileItem *pItem, bool bShowInfo /
}
CMusicInfoScanner scanner;
- if (scanner.UpdateDatabaseAlbumInfo(pItem->GetPath(), albumInfo, bShowInfo) != INFO_ADDED || !albumInfo.Loaded())
+ if (scanner.UpdateDatabaseAlbumInfo(album, scraper, bShowInfo, m_dlgProgress) != INFO_ADDED)
{
CGUIDialogOK::ShowAndGetInput(185, 0, 500, 0);
if (m_dlgProgress)
@@ -479,17 +493,17 @@ bool CGUIWindowMusicBase::ShowAlbumInfo(const CFileItem *pItem, bool bShowInfo /
{
CStdString strPath;
m_musicdatabase.GetAlbumPath(params.GetAlbumId(), strPath);
- pDlgAlbumInfo->SetAlbum(albumInfo.GetAlbum(), strPath);
+ pDlgAlbumInfo->SetAlbum(album, strPath);
pDlgAlbumInfo->DoModal();
if (pDlgAlbumInfo->NeedRefresh())
{
- m_musicdatabase.DeleteAlbumInfo(params.GetAlbumId());
+ m_musicdatabase.ClearAlbumLastScrapedTime(params.GetAlbumId());
continue;
}
else if (pDlgAlbumInfo->HasUpdatedThumb())
{
- UpdateThumb(albumInfo.GetAlbum(), strPath);
+ UpdateThumb(album, strPath);
}
}
break;
diff --git a/xbmc/music/windows/GUIWindowMusicNav.cpp b/xbmc/music/windows/GUIWindowMusicNav.cpp
index d3d2aacaca..09504c8cfc 100644
--- a/xbmc/music/windows/GUIWindowMusicNav.cpp
+++ b/xbmc/music/windows/GUIWindowMusicNav.cpp
@@ -571,7 +571,7 @@ bool CGUIWindowMusicNav::OnContextButton(int itemNumber, CONTEXT_BUTTON button)
return false;
CStdString path = StringUtils::Format("musicdb://artists/%ld/", idArtist);
CArtist artist;
- m_musicdatabase.GetArtistInfo(idArtist,artist,false);
+ m_musicdatabase.GetArtist(idArtist, artist, false);
*item = CFileItem(artist);
item->SetPath(path);
CGUIWindowMusicBase::OnContextButton(itemNumber,button);
@@ -588,7 +588,7 @@ bool CGUIWindowMusicNav::OnContextButton(int itemNumber, CONTEXT_BUTTON button)
return false;
CStdString path = StringUtils::Format("musicdb://albums/%ld/", idAlbum);
CAlbum album;
- m_musicdatabase.GetAlbumInfo(idAlbum,album,NULL);
+ m_musicdatabase.GetAlbum(idAlbum, album, false);
*item = CFileItem(path,album);
item->SetPath(path);
CGUIWindowMusicBase::OnContextButton(itemNumber,button);
diff --git a/xbmc/network/upnp/UPnPServer.cpp b/xbmc/network/upnp/UPnPServer.cpp
index 5c9e982f74..67f268df9a 100644
--- a/xbmc/network/upnp/UPnPServer.cpp
+++ b/xbmc/network/upnp/UPnPServer.cpp
@@ -297,12 +297,12 @@ CUPnPServer::Build(CFileItemPtr item,
}
else if (params.GetAlbumId() >= 0 ) {
CAlbum album;
- if (db.GetAlbumInfo(params.GetAlbumId(), album, NULL))
+ if (db.GetAlbum(params.GetAlbumId(), album, false))
item->GetMusicInfoTag()->SetAlbum(album);
}
else if (params.GetArtistId() >= 0 ) {
CArtist artist;
- if (db.GetArtistInfo(params.GetArtistId(), artist, false))
+ if (db.GetArtist(params.GetArtistId(), artist, false))
item->GetMusicInfoTag()->SetArtist(artist);
}
}