Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
branch: master
Fetching contributors…

Cannot retrieve contributors at this time

executable file 380 lines (288 sloc) 9.322 kb
/* --------------------------------------------------------------------------
flactag -- A tagger for single album FLAC files with embedded CUE sheets
using data retrieved from the MusicBrainz service
Copyright (C) 2006-2012 Andrew Hawkins
Copyright (C) 2011-2012 Daniel Pocock
This file is part of flactag.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Flactag is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
$Id$
----------------------------------------------------------------------------*/
#include "MusicBrainzInfo.h"
#include "config.h"
#include <sstream>
#include "base64.h"
#include "DiscIDWrapper.h"
#include "ErrorLog.h"
#include "musicbrainz5/HTTPFetch.h"
#include "musicbrainz5/Query.h"
#include "musicbrainz5/Track.h"
#include "musicbrainz5/Release.h"
#include "musicbrainz5/Medium.h"
#include "musicbrainz5/ReleaseGroup.h"
#include "musicbrainz5/ArtistCredit.h"
#include "musicbrainz5/Artist.h"
#include "musicbrainz5/Recording.h"
#include "musicbrainz5/NameCredit.h"
CMusicBrainzInfo::CMusicBrainzInfo(const std::string& Server, int Port, const CCuesheet& Cuesheet)
: m_Server(Server),
m_Port(Port),
m_Cuesheet(Cuesheet),
m_DiscIDWrapper(),
m_DiskID(""),
m_OverrideDiskID(false)
{
if (m_Server.empty())
m_Server="musicbrainz.org";
if (0==m_Port)
m_Port=80;
m_DiscIDWrapper.FromCuesheet(m_Cuesheet);
m_DiskID.assign(m_DiscIDWrapper.ID());
}
CMusicBrainzInfo::CMusicBrainzInfo(const std::string& Server, int Port, const CCuesheet& Cuesheet, std::string DiskID)
: m_Server(Server),
m_Port(Port),
m_Cuesheet(Cuesheet),
m_DiscIDWrapper(),
m_DiskID(DiskID),
m_OverrideDiskID(true)
{
if (m_Server.empty())
m_Server="musicbrainz.org";
if (0==m_Port)
m_Port=80;
m_DiscIDWrapper.FromCuesheet(m_Cuesheet);
}
bool CMusicBrainzInfo::LoadInfo(const std::string& FlacFile)
{
//http://www.musicbrainz.org/ws/2/discid/arIS30RPWowvwNEqsqdDnZzDGhk-?inc=recordings+artists+artist-credits+url-rels+aliases
bool RetVal=false;
//std::string DiskID=DiscIDWrapper.ID();
//Test Disk ID for album title containing extended characters
//DiskID="5EgKduVn7sQH9JGg8JQyrPOjSqc-";
//CErrorLog::Log("DiskID: " + DiskID);
//CErrorLog::Log("Submit: " + DiscIDWrapper.SubmitURL());
MusicBrainz5::CQuery MusicBrainz("flactag-" VERSION,m_Server,m_Port);
try
{
MusicBrainz5::CReleaseList ReleaseList=MusicBrainz.LookupDiscID(m_DiskID);
if (ReleaseList.NumItems())
{
RetVal=true;
for (int ReleaseNum=0;ReleaseNum<ReleaseList.NumItems();ReleaseNum++)
{
MusicBrainz5::CRelease *Release=ReleaseList.Item(ReleaseNum);
MusicBrainz5::CRelease FullRelease=MusicBrainz.LookupRelease(Release->ID());
MusicBrainz5::CMediumList MediaList=FullRelease.MediaMatchingDiscID(m_DiskID);
for (int MediumNumber=0;MediumNumber<MediaList.NumItems();MediumNumber++)
{
MusicBrainz5::CMedium *Medium=MediaList.Item(MediumNumber);
CAlbum Album=ParseAlbum(FullRelease,Medium);
MusicBrainz5::CTrackList *TrackList=Medium->TrackList();
if (TrackList)
{
for (int TrackNumber=0;TrackNumber<TrackList->NumItems();TrackNumber++)
{
MusicBrainz5::CTrack *MBTrack=TrackList->Item(TrackNumber);
CTrack Track=ParseTrack(MBTrack);
Album.AddTrack(Track);
}
}
m_Albums.push_back(Album);
}
}
}
else
{
std::stringstream os;
os << "No albums found for file '" << FlacFile << "'";
CErrorLog::Log(os.str());
if(!m_OverrideDiskID)
{
CErrorLog::Log("Please submit the DiskID using the following URL:");
CErrorLog::Log(m_DiscIDWrapper.SubmitURL());
}
}
}
catch (MusicBrainz5::CResourceNotFoundError Exception)
{
std::stringstream os;
os << "No albums found for file '" << FlacFile << "'";
CErrorLog::Log(os.str());
CErrorLog::Log("Please submit the DiskID using the following URL:");
CErrorLog::Log(m_DiscIDWrapper.SubmitURL());
}
catch (MusicBrainz5::CExceptionBase Exception)
{
std::cerr << FlacFile << ": Exception: " << Exception.what() << std::endl;
}
return RetVal;
}
std::vector<unsigned char> CMusicBrainzInfo::GetCoverArt(const CUTF8Tag& ASIN)
{
std::vector<unsigned char> Data;
std::string URL="/images/P/" + ASIN.DisplayValue() + ".02.LZZZZZZZ.jpg";
MusicBrainz5::CHTTPFetch Fetch("flactag/v" VERSION, "images.amazon.com");
int Bytes=Fetch.Fetch(URL);
if (Bytes<1000)
{
URL="/images/P/" + ASIN.DisplayValue() + ".02.MZZZZZZZ.jpg";
Bytes=Fetch.Fetch(URL);
}
if (Bytes>0)
{
if (Bytes<1000)
CErrorLog::Log("Album art downloaded was less than 1000 bytes, ignoring");
else
{
Data=Fetch.Data();
}
}
else
CErrorLog::Log(std::string("Error downloading art: ") + Fetch.ErrorMessage());
return Data;
}
CAlbum CMusicBrainzInfo::ParseAlbum(const MusicBrainz5::CRelease& Release, const MusicBrainz5::CMedium* Medium)
{
CAlbum Album;
if (!Release.Title().empty())
Album.SetName(Release.Title());
else if (Release.ReleaseGroup() && !Release.ReleaseGroup()->Title().empty())
Album.SetName(Release.ReleaseGroup()->Title());
if (Release.MediumList() && Release.MediumList()->NumItems()>1)
Album.SetDiskNumber(Medium->Position());
Album.SetAlbumID(Release.ID());
MusicBrainz5::CArtistCredit *ArtistCredit=Release.ArtistCredit();
if (ArtistCredit)
{
std::string ArtistID;
std::string ArtistName;
std::string ArtistSort;
ParseArtist(ArtistCredit,ArtistID,ArtistName,ArtistSort);
Album.SetArtistID(ArtistID);
Album.SetArtist(ArtistName);
Album.SetArtistSort(ArtistSort);
}
Album.SetASIN(Release.ASIN());
if (!Album.ASIN().empty())
{
std::vector<unsigned char> Data=GetCoverArt(Album.ASIN());
if (Data.size()>1000)
Album.SetCoverArt(CCoverArt(&Data[0],Data.size()));
}
if (Release.ReleaseGroup())
Album.SetType(AlbumType(Release.ReleaseGroup()->PrimaryType()));
Album.SetStatus(AlbumStatus(Release.Status()));
std::string AlbumDate=Release.Date();
std::string::size_type MinusPos=AlbumDate.find("-");
if (std::string::npos!=MinusPos)
AlbumDate=AlbumDate.substr(0,MinusPos);
Album.SetDate(AlbumDate);
return Album;
}
void CMusicBrainzInfo::ParseArtist(const MusicBrainz5::CArtistCredit* ArtistCredit, std::string& ArtistID, std::string& ArtistName, std::string& ArtistSort)
{
bool FirstArtist=true;
MusicBrainz5::CNameCreditList *NameCreditsList=ArtistCredit->NameCreditList();
if (NameCreditsList)
{
for (int NameCreditNumber=0;NameCreditNumber<NameCreditsList->NumItems();NameCreditNumber++)
{
MusicBrainz5::CNameCredit *NameCredit=NameCreditsList->Item(NameCreditNumber);
MusicBrainz5::CArtist *Artist=NameCredit->Artist();
if (!NameCredit->Name().empty())
ArtistName+=NameCredit->Name();
else if (Artist)
ArtistName+=Artist->Name();
ArtistName+=NameCredit->JoinPhrase();
if (Artist)
{
ArtistSort+=Artist->SortName();
ArtistSort+=NameCredit->JoinPhrase();
}
if (FirstArtist)
{
FirstArtist=false;
if (Artist)
ArtistID=Artist->ID();
}
}
}
}
CTrack CMusicBrainzInfo::ParseTrack(const MusicBrainz5::CTrack* MBTrack)
{
CTrack Track;
Track.SetNumber(MBTrack->Position());
if (!MBTrack->Title().empty())
Track.SetName(MBTrack->Title());
else if (MBTrack->Recording())
Track.SetName(MBTrack->Recording()->Title());
if (MBTrack->Recording())
{
MusicBrainz5::CArtistCredit *ArtistCredit=MBTrack->Recording()->ArtistCredit();
if (ArtistCredit)
{
std::string ArtistID;
std::string ArtistName;
std::string ArtistSort;
ParseArtist(ArtistCredit,ArtistID,ArtistName,ArtistSort);
Track.SetArtistID(ArtistID);
Track.SetArtist(ArtistName);
Track.SetArtistSort(ArtistSort);
}
Track.SetTrackID(MBTrack->Recording()->ID());
}
return Track;
}
std::vector<CAlbum> CMusicBrainzInfo::Albums() const
{
return m_Albums;
}
std::string CMusicBrainzInfo::AlbumType(const std::string Type) const
{
const char *AlbumTypeStrings[] =
{
"album", "single", "EP", "compilation", "soundtrack",
"spokenword", "interview", "audiobook", "live", "remix", "other", "\0"
};
std::string Ret;
int i=0;
while (AlbumTypeStrings[i][0]!='\0')
{
if (strcasecmp(Type.c_str(),AlbumTypeStrings[i])==0)
{
Ret=AlbumTypeStrings[i];
break;
}
++i;
}
return Ret;
}
std::string CMusicBrainzInfo::AlbumStatus(const std::string Status) const
{
const char *AlbumStatusStrings[] =
{
"official", "promotion", "bootleg", "\0"
};
std::string Ret;
int i=0;
while (AlbumStatusStrings[i][0]!='\0')
{
if (strcasecmp(Status.c_str(),AlbumStatusStrings[i])==0)
{
Ret=AlbumStatusStrings[i];
break;
}
++i;
}
return Ret;
}
Jump to Line
Something went wrong with that request. Please try again.