Added multi artists support

This commit is contained in:
emeric
2019-03-18 13:54:13 +01:00
parent 9538aa9de9
commit 202d447422
35 changed files with 593 additions and 555 deletions
+72 -150
View File
@@ -84,62 +84,69 @@ isPathInParentPath(const boost::filesystem::path& path, const boost::filesystem:
return false;
}
Artist::pointer
getArtist(Wt::Dbo::Session& session, const std::string& name, const std::string& mbid)
std::vector<Artist::pointer>
getArtists(Wt::Dbo::Session& session, const std::vector<MetaData::Artist>& artistsInfo)
{
Artist::pointer artist;
std::vector<Artist::pointer> artists;
// First try to get by MBID
if (!mbid.empty())
for (const MetaData::Artist& artistInfo : artistsInfo)
{
artist = Artist::getByMBID(session, mbid);
if (!artist)
artist = Artist::create(session, name, mbid);
Artist::pointer artist;
return artist;
}
// Fall back on artist name (collisions may occur)
if (!name.empty())
{
for (Artist::pointer sameNamedArtist : Artist::getByName(session, name))
// First try to get by MBID
if (!artistInfo.musicBrainzArtistID.empty())
{
if (sameNamedArtist->getMBID().empty())
{
artist = sameNamedArtist;
break;
}
artist = Artist::getByMBID(session, artistInfo.musicBrainzArtistID);
if (!artist)
artist = Artist::create(session, artistInfo.name, artistInfo.musicBrainzArtistID);
artists.emplace_back(std::move(artist));
continue;
}
// No Artist found with the same name and without MBID -> creating
if (!artist)
artist = Artist::create(session, name);
// Fall back on artist name (collisions may occur)
if (!artistInfo.name.empty())
{
for (const Artist::pointer& sameNamedArtist : Artist::getByName(session, artistInfo.name))
{
if (sameNamedArtist->getMBID().empty())
{
artist = sameNamedArtist;
break;
}
}
return artist;
// No Artist found with the same name and without MBID -> creating
if (!artist)
artist = Artist::create(session, artistInfo.name);
artists.emplace_back(std::move(artist));
continue;
}
}
return Artist::pointer();
return artists;
}
Release::pointer
getRelease(Wt::Dbo::Session& session, const std::string& name, const std::string& mbid)
getRelease(Wt::Dbo::Session& session, const MetaData::Album& album)
{
Release::pointer release;
// First try to get by MBID
if (!mbid.empty())
if (!album.musicBrainzAlbumID.empty())
{
release = Release::getByMBID(session, mbid );
release = Release::getByMBID(session, album.musicBrainzAlbumID);
if (!release)
release = Release::create(session, name, mbid);
release = Release::create(session, album.name, album.musicBrainzAlbumID);
return release;
}
// Fall back on release name (collisions may occur)
if (!name.empty())
if (!album.name.empty())
{
for (Release::pointer sameNamedRelease : Release::getByName(session, name))
for (const Release::pointer& sameNamedRelease : Release::getByName(session, album.name))
{
if (sameNamedRelease->getMBID().empty())
{
@@ -150,12 +157,12 @@ getRelease(Wt::Dbo::Session& session, const std::string& name, const std::string
// No release found with the same name and without MBID -> creating
if (!release)
release = Release::create(session, name);
release = Release::create(session, album.name);
return release;
}
return Release::pointer();
return Release::pointer{};
}
std::vector<Cluster::pointer>
@@ -400,8 +407,8 @@ MediaScanner::scanAudioFile(const boost::filesystem::path& file, bool forceScan,
}
}
boost::optional<MetaData::Items> items = _metadataParser.parse(file);
if (!items)
boost::optional<MetaData::Track> trackInfo {_metadataParser.parse(file)};
if (!trackInfo)
{
stats.scanErrors++;
return;
@@ -412,15 +419,14 @@ MediaScanner::scanAudioFile(const boost::filesystem::path& file, bool forceScan,
std::vector<unsigned char> checksum ;
computeCrc(file, checksum);
Wt::Dbo::Transaction transaction(_db.getSession());
Wt::Dbo::Transaction transaction {_db.getSession()};
Wt::Dbo::ptr<Track> track = Track::getByPath(_db.getSession(), file);
Wt::Dbo::ptr<Track> track {Track::getByPath(_db.getSession(), file) };
// We estimate this is a audio file if:
// - we found a least one audio stream
// - the duration is not null
if ((*items).find(MetaData::Type::AudioStreams) == (*items).end()
|| boost::any_cast<std::vector<MetaData::AudioStream>> ((*items)[MetaData::Type::AudioStreams]).empty())
if (trackInfo->audioStreams.empty())
{
LMS_LOG(DBUPDATER, INFO) << "Skipped '" << file.string() << "' (no audio stream found)";
@@ -433,10 +439,9 @@ MediaScanner::scanAudioFile(const boost::filesystem::path& file, bool forceScan,
stats.incompleteScans++;
return;
}
if ((*items).find(MetaData::Type::Duration) == (*items).end()
|| boost::any_cast<std::chrono::milliseconds>((*items)[MetaData::Type::Duration]).count() <= 0)
if (trackInfo->duration == std::chrono::milliseconds::zero())
{
LMS_LOG(DBUPDATER, INFO) << "Skipped '" << file.string() << "' (no duration or duration <= 0)";
LMS_LOG(DBUPDATER, INFO) << "Skipped '" << file.string() << "' (duration is 0)";
// If Track exists here, delete it!
if (track)
@@ -450,10 +455,8 @@ MediaScanner::scanAudioFile(const boost::filesystem::path& file, bool forceScan,
// ***** Title
std::string title;
if ((*items).find(MetaData::Type::Title) != (*items).end())
{
title = boost::any_cast<std::string>((*items)[MetaData::Type::Title]);
}
if (!trackInfo->title.empty())
title = trackInfo->title;
else
{
// TODO parse file name guess track etc.
@@ -462,51 +465,19 @@ MediaScanner::scanAudioFile(const boost::filesystem::path& file, bool forceScan,
}
// ***** Clusters
std::vector< Cluster::pointer > genres;
{
MetaData::Clusters clusterNames;
std::vector<Cluster::pointer> clusters {getClusters(_db.getSession(), trackInfo->clusters)};
if ((*items).find(MetaData::Type::Clusters) != (*items).end())
{
clusterNames = boost::any_cast<MetaData::Clusters> ((*items)[MetaData::Type::Clusters]);
}
genres = getClusters(_db.getSession(), clusterNames);
}
// ***** Artist
std::set<Artist::pointer> artists;
{
std::string artistName;
std::string artistMusicBrainzID;
if ((*items).find(MetaData::Type::MusicBrainzArtistID) != (*items).end())
artistMusicBrainzID = boost::any_cast<std::string>((*items)[MetaData::Type::MusicBrainzArtistID] );
if ((*items).find(MetaData::Type::Artist) != (*items).end())
artistName = boost::any_cast<std::string>((*items)[MetaData::Type::Artist]);
artist = getArtist(_db.getSession(), artistName, artistMusicBrainzID);
}
// ***** Artists
std::vector<Artist::pointer> artists {getArtists(_db.getSession(), trackInfo->artists)};
// ***** Release
Release::pointer release;
{
std::string releaseName;
std::string releaseMusicBrainzID;
if ((*items).find(MetaData::Type::MusicBrainzAlbumID) != (*items).end())
releaseMusicBrainzID = boost::any_cast<std::string>((*items)[MetaData::Type::MusicBrainzAlbumID] );
if ((*items).find(MetaData::Type::Album) != (*items).end())
releaseName = boost::any_cast<std::string>((*items)[MetaData::Type::Album]);
release = getRelease(_db.getSession(), releaseName, releaseMusicBrainzID);
}
if (trackInfo->album)
release = getRelease(_db.getSession(), *trackInfo->album);
// If file already exist, update data
// Otherwise, create it
bool trackAdded = false;
bool trackAdded {false};
if (!track)
{
// Create a new song
@@ -519,9 +490,6 @@ MediaScanner::scanAudioFile(const boost::filesystem::path& file, bool forceScan,
{
LMS_LOG(DBUPDATER, INFO) << "Updating '" << file.string() << "'";
// Remove the songs from its clusters
track.modify()->eraseClusters();
stats.updates++;
}
@@ -529,74 +497,28 @@ MediaScanner::scanAudioFile(const boost::filesystem::path& file, bool forceScan,
track.modify()->setScanVersion(_scanVersion);
track.modify()->setChecksum(checksum);
track.modify()->setArtist(artist);
track.modify()->setArtists(artists);
track.modify()->setRelease(release);
track.modify()->setClusters(clusters);
track.modify()->setLastWriteTime(lastWriteTime);
track.modify()->setName(title);
track.modify()->setDuration( boost::any_cast<std::chrono::milliseconds>((*items)[MetaData::Type::Duration]) );
track.modify()->setAddedTime( Wt::WLocalDateTime::currentServerDateTime().toUTC() );
track.modify()->setDuration(trackInfo->duration);
track.modify()->setAddedTime(Wt::WLocalDateTime::currentServerDateTime().toUTC());
track.modify()->setTrackNumber(trackInfo->trackNumber ? *trackInfo->trackNumber : 0);
track.modify()->setTotalTrackNumber(trackInfo->totalTrack ? *trackInfo->totalTrack : 0);
track.modify()->setDiscNumber(trackInfo->discNumber ? *trackInfo->discNumber : 0);
track.modify()->setTotalDiscNumber(trackInfo->totalDisc ? *trackInfo->totalDisc : 0);
track.modify()->setYear(trackInfo->year ? *trackInfo->year : 0);
track.modify()->setOriginalYear(trackInfo->originalYear ? *trackInfo->originalYear : 0);
{
std::string trackClusterList;
// Product genre list
for (Cluster::pointer genre : genres)
{
if (!trackClusterList.empty())
trackClusterList += ", ";
trackClusterList += genre->getName();
// If a file has an OriginalYear but no Year, set it to ease filtering
if (!trackInfo->year && trackInfo->originalYear)
track.modify()->setYear(*trackInfo->originalYear);
genre.modify()->addTrack(track);
}
track.modify()->setGenres( trackClusterList );
}
if ((*items).find(MetaData::Type::TrackNumber) != (*items).end())
track.modify()->setTrackNumber( boost::any_cast<std::size_t>((*items)[MetaData::Type::TrackNumber]) );
if ((*items).find(MetaData::Type::TotalTrack) != (*items).end())
track.modify()->setTotalTrackNumber( boost::any_cast<std::size_t>((*items)[MetaData::Type::TotalTrack]) );
if ((*items).find(MetaData::Type::DiscNumber) != (*items).end())
track.modify()->setDiscNumber( boost::any_cast<std::size_t>((*items)[MetaData::Type::DiscNumber]) );
if ((*items).find(MetaData::Type::TotalDisc) != (*items).end())
track.modify()->setTotalDiscNumber( boost::any_cast<std::size_t>((*items)[MetaData::Type::TotalDisc]) );
if ((*items).find(MetaData::Type::Year) != (*items).end())
track.modify()->setYear( boost::any_cast<int>((*items)[MetaData::Type::Year]) );
if ((*items).find(MetaData::Type::OriginalYear) != (*items).end())
{
track.modify()->setOriginalYear( boost::any_cast<int>((*items)[MetaData::Type::OriginalYear]) );
// If a file has an OriginalYear but no Year, set it o ease filtering
if ((*items).find(MetaData::Type::Year) == (*items).end())
track.modify()->setYear( boost::any_cast<int>((*items)[MetaData::Type::OriginalYear]) );
}
if ((*items).find(MetaData::Type::MusicBrainzRecordingID) != (*items).end())
{
track.modify()->setMBID( boost::any_cast<std::string>((*items)[MetaData::Type::MusicBrainzRecordingID]) );
}
if ((*items).find(MetaData::Type::HasCover) != (*items).end())
{
bool hasCover = boost::any_cast<bool>((*items)[MetaData::Type::HasCover]);
track.modify()->setHasCover(hasCover);
}
if ((*items).find(MetaData::Type::Copyright) != (*items).end())
{
track.modify()->setCopyright( boost::any_cast<std::string>((*items)[MetaData::Type::Copyright]) );
}
if ((*items).find(MetaData::Type::CopyrightURL) != (*items).end())
{
track.modify()->setCopyrightURL( boost::any_cast<std::string>((*items)[MetaData::Type::CopyrightURL]) );
}
track.modify()->setMBID(trackInfo->musicBrainzRecordID);
track.modify()->setHasCover(trackInfo->hasCover);
track.modify()->setCopyright(trackInfo->copyright);
track.modify()->setCopyrightURL(trackInfo->copyrightURL);
transaction.commit();