summaryrefslogtreecommitdiffstats
path: root/src/metadata/tagengine.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/metadata/tagengine.cpp')
-rwxr-xr-xsrc/metadata/tagengine.cpp419
1 files changed, 419 insertions, 0 deletions
diff --git a/src/metadata/tagengine.cpp b/src/metadata/tagengine.cpp
new file mode 100755
index 0000000..34abd23
--- /dev/null
+++ b/src/metadata/tagengine.cpp
@@ -0,0 +1,419 @@
+
+#include "tagengine.h"
+
+#include <qfile.h>
+
+// #include <taglib/attachedpictureframe.h>
+#include <taglib/fileref.h>
+#include <taglib/id3v1genres.h> //used to load genre list
+#include <taglib/mpegfile.h>
+#include <taglib/tag.h>
+#include <taglib/tstring.h>
+#include <taglib/tlist.h>
+#include <taglib/apetag.h>
+#include <taglib/id3v2tag.h>
+#include <taglib/id3v1tag.h>
+#include <taglib/mpcfile.h>
+#include <taglib/mpegfile.h>
+#include <taglib/oggfile.h>
+#include <taglib/oggflacfile.h>
+#include <taglib/vorbisfile.h>
+#include <taglib/flacfile.h>
+#include <taglib/textidentificationframe.h>
+#include <taglib/uniquefileidentifierframe.h>
+#include <taglib/xiphcomment.h>
+#include "wavpack/wvfile.h"
+#include "trueaudio/ttafile.h"
+
+#include <config.h>
+#ifdef HAVE_MP4V2
+#include "mp4/mp4file.h"
+#include "mp4/mp4tag.h"
+#else
+#include "m4a/mp4file.h"
+#include "m4a/mp4itunestag.h"
+#endif
+
+
+// TODO COMPILATION tag
+// FIXME BPM tag
+
+TagData::TagData( const QString& _artist, const QString& _composer,
+ const QString& _album, const QString& _title,
+ const QString& _genre, const QString& _comment,
+ int _track, int _disc, int _year,
+ int _length, int _fileSize, int _bitrate, int _samplingRate )
+{
+ artist = _artist;
+ composer = _composer;
+ album = _album;
+ title = _title;
+ genre = _genre;
+ comment = _comment;
+ track = _track;
+ disc = _disc;
+ year = _year;
+ length = _length;
+ fileSize = _fileSize;
+ bitrate = _bitrate;
+ samplingRate = _samplingRate;
+}
+
+TagData::~TagData()
+{}
+
+
+TagEngine::TagEngine()
+{
+ TagLib::StringList genres = TagLib::ID3v1::genreList();
+ for( TagLib::StringList::ConstIterator it = genres.begin(), end = genres.end(); it != end; ++it )
+ genreList += TStringToQString( (*it) );
+
+ genreList.sort();
+}
+
+TagEngine::~TagEngine()
+{}
+
+TagData* TagEngine::readTags( const QString& file )
+{
+ TagLib::FileRef fileref( QFile::encodeName(file) );
+ TagData* tagData = new TagData();
+
+ if( !fileref.isNull() )
+ {
+ TagLib::Tag *tag = fileref.tag();
+
+ tagData->track = 0;
+ tagData->year = 0;
+ tagData->disc = 0;
+ tagData->track_gain = 210588; // 0 is a valid value
+ tagData->album_gain = 210588;
+
+ if( tag )
+ {
+ tagData->title = TStringToQString( tag->title() ).stripWhiteSpace();
+ tagData->artist = TStringToQString( tag->artist() ).stripWhiteSpace();
+ tagData->album = TStringToQString( tag->album() ).stripWhiteSpace();
+ tagData->genre = TStringToQString( tag->genre() ).stripWhiteSpace();
+ tagData->comment = TStringToQString( tag->comment() ).stripWhiteSpace();
+ tagData->track = tag->track();
+ tagData->year = tag->year();
+ }
+
+ TagLib::AudioProperties *audioProperties = fileref.audioProperties();
+
+ if( audioProperties )
+ {
+ tagData->length = audioProperties->length();
+ // TODO read all information
+ //tagData->fileSize = ;
+ // = audioProperties->channels();
+ //tagData->bitrate = audioProperties->bitrate();
+ tagData->samplingRate = audioProperties->sampleRate();
+ }
+
+ QString disc;
+ QString track_gain;
+ QString album_gain;
+ if ( TagLib::MPEG::File *file = dynamic_cast<TagLib::MPEG::File *>( fileref.file() ) )
+ {
+ if ( file->ID3v2Tag() )
+ {
+ if ( !file->ID3v2Tag()->frameListMap()[ "TPOS" ].isEmpty() )
+ disc = TStringToQString( file->ID3v2Tag()->frameListMap()["TPOS"].front()->toString() ).stripWhiteSpace();
+
+ if ( !file->ID3v2Tag()->frameListMap()[ "TCOM" ].isEmpty() )
+ tagData->composer = TStringToQString( file->ID3v2Tag()->frameListMap()["TCOM"].front()->toString() ).stripWhiteSpace();
+ }
+ if ( file->APETag() )
+ {
+ if ( !file->APETag()->itemListMap()[ "REPLAYGAIN_TRACK_GAIN" ].isEmpty() )
+ track_gain = TStringToQString( file->APETag()->itemListMap()["REPLAYGAIN_TRACK_GAIN"].toString() ).stripWhiteSpace();
+
+ if ( !file->APETag()->itemListMap()[ "REPLAYGAIN_ALBUM_GAIN" ].isEmpty() )
+ album_gain = TStringToQString( file->APETag()->itemListMap()["REPLAYGAIN_ALBUM_GAIN"].toString() ).stripWhiteSpace();
+ }
+ }
+ else if ( TagLib::Ogg::Vorbis::File *file = dynamic_cast<TagLib::Ogg::Vorbis::File *>( fileref.file() ) )
+ {
+ if ( file->tag() )
+ {
+ if ( !file->tag()->fieldListMap()[ "COMPOSER" ].isEmpty() )
+ tagData->composer = TStringToQString( file->tag()->fieldListMap()["COMPOSER"].front() ).stripWhiteSpace();
+
+ if ( !file->tag()->fieldListMap()[ "DISCNUMBER" ].isEmpty() )
+ disc = TStringToQString( file->tag()->fieldListMap()["DISCNUMBER"].front() ).stripWhiteSpace();
+
+ if ( !file->tag()->fieldListMap()[ "REPLAYGAIN_TRACK_GAIN" ].isEmpty() )
+ track_gain = TStringToQString( file->tag()->fieldListMap()["REPLAYGAIN_TRACK_GAIN"].front() ).stripWhiteSpace();
+
+ if ( !file->tag()->fieldListMap()[ "REPLAYGAIN_ALBUM_GAIN" ].isEmpty() )
+ album_gain = TStringToQString( file->tag()->fieldListMap()["REPLAYGAIN_ALBUM_GAIN"].front() ).stripWhiteSpace();
+ }
+ }
+ else if ( TagLib::FLAC::File *file = dynamic_cast<TagLib::FLAC::File *>( fileref.file() ) )
+ {
+ if ( file->xiphComment() )
+ {
+ if ( !file->xiphComment()->fieldListMap()[ "COMPOSER" ].isEmpty() )
+ tagData->composer = TStringToQString( file->xiphComment()->fieldListMap()["COMPOSER"].front() ).stripWhiteSpace();
+
+ if ( !file->xiphComment()->fieldListMap()[ "DISCNUMBER" ].isEmpty() )
+ disc = TStringToQString( file->xiphComment()->fieldListMap()["DISCNUMBER"].front() ).stripWhiteSpace();
+
+ if ( !file->xiphComment()->fieldListMap()[ "REPLAYGAIN_TRACK_GAIN" ].isEmpty() )
+ track_gain = TStringToQString( file->xiphComment()->fieldListMap()["REPLAYGAIN_TRACK_GAIN"].front() ).stripWhiteSpace();
+
+ if ( !file->xiphComment()->fieldListMap()[ "REPLAYGAIN_ALBUM_GAIN" ].isEmpty() )
+ album_gain = TStringToQString( file->xiphComment()->fieldListMap()["REPLAYGAIN_ALBUM_GAIN"].front() ).stripWhiteSpace();
+ }
+
+ /*if ( file->tag() )
+ {
+ if ( !file->tag()->fieldListMap()[ "REPLAYGAIN_TRACK_GAIN" ].isEmpty() )
+ track_gain = TStringToQString( file->tag()->fieldListMap()["REPLAYGAIN_TRACK_GAIN"].front() ).stripWhiteSpace();
+
+ if ( !file->tag()->fieldListMap()[ "REPLAYGAIN_ALBUM_GAIN" ].isEmpty() )
+ album_gain = TStringToQString( file->tag()->fieldListMap()["REPLAYGAIN_ALBUM_GAIN"].front() ).stripWhiteSpace();
+ }*/
+ }
+ else if ( TagLib::MP4::File *file = dynamic_cast<TagLib::MP4::File *>( fileref.file() ) )
+ {
+ TagLib::MP4::Tag *mp4tag = dynamic_cast<TagLib::MP4::Tag *>( file->tag() );
+ if( mp4tag )
+ {
+ tagData->composer = TStringToQString( mp4tag->composer() );
+
+ disc = QString::number( mp4tag->disk() );
+ }
+ }
+/* else if ( TagLib::MPC::File *file = dynamic_cast<TagLib::MPC::File *>( fileref.file() ) )
+ {
+ if ( file->APETag() )
+ {
+ if ( !file->APETag()->itemListMap()[ "REPLAYGAIN_TRACK_GAIN" ].isEmpty() )
+ track_gain = TStringToQString( file->APETag()->itemListMap()["REPLAYGAIN_TRACK_GAIN"].toString() ).stripWhiteSpace();
+
+ if ( !file->APETag()->itemListMap()[ "REPLAYGAIN_ALBUM_GAIN" ].isEmpty() )
+ album_gain = TStringToQString( file->APETag()->itemListMap()["REPLAYGAIN_ALBUM_GAIN"].toString() ).stripWhiteSpace();
+ }
+ }*/
+ else if ( TagLib::WavPack::File *file = dynamic_cast<TagLib::WavPack::File *>( fileref.file() ) )
+ {
+ if ( file->APETag() )
+ {
+ if ( !file->APETag()->itemListMap()[ "REPLAYGAIN_TRACK_GAIN" ].isEmpty() )
+ track_gain = TStringToQString( file->APETag()->itemListMap()["REPLAYGAIN_TRACK_GAIN"].toString() ).stripWhiteSpace();
+
+ if ( !file->APETag()->itemListMap()[ "REPLAYGAIN_ALBUM_GAIN" ].isEmpty() )
+ album_gain = TStringToQString( file->APETag()->itemListMap()["REPLAYGAIN_ALBUM_GAIN"].toString() ).stripWhiteSpace();
+ }
+ }
+ else if ( TagLib::TTA::File *file = dynamic_cast<TagLib::TTA::File *>( fileref.file() ) )
+ {
+ if ( file->ID3v2Tag() )
+ {
+ if ( !file->ID3v2Tag()->frameListMap()[ "TPOS" ].isEmpty() )
+ disc = TStringToQString( file->ID3v2Tag()->frameListMap()["TPOS"].front()->toString() ).stripWhiteSpace();
+
+ if ( !file->ID3v2Tag()->frameListMap()[ "TCOM" ].isEmpty() )
+ tagData->composer = TStringToQString( file->ID3v2Tag()->frameListMap()["TCOM"].front()->toString() ).stripWhiteSpace();
+ }
+ }
+
+ if( !disc.isEmpty() )
+ {
+ int i = disc.find('/');
+ if( i != -1 )
+ // disc.right( i ).toInt() is total number of discs, we don't use this at the moment
+ tagData->disc = disc.left( i ).toInt();
+ else
+ tagData->disc = disc.toInt();
+ }
+
+ if( !track_gain.isEmpty() )
+ {
+ int i = track_gain.find(' ');
+ if( i != -1 )
+ tagData->track_gain = track_gain.left( i ).toFloat();
+ else
+ tagData->track_gain = track_gain.toFloat();
+ }
+
+ if( !album_gain.isEmpty() )
+ {
+ int i = album_gain.find(' ');
+ if( i != -1 )
+ tagData->album_gain = album_gain.left( i ).toFloat();
+ else
+ tagData->album_gain = album_gain.toFloat();
+ }
+
+ return tagData;
+ }
+
+ return 0;
+}
+
+bool TagEngine::writeTags( const QString& file, TagData* tagData )
+{
+ if( !tagData ) tagData = new TagData();
+
+ //Set default codec to UTF-8 (see bugs 111246 and 111232)
+ TagLib::ID3v2::FrameFactory::instance()->setDefaultTextEncoding( TagLib::String::UTF8 );
+
+ TagLib::FileRef fileref( QFile::encodeName(file), false );
+
+ if ( !fileref.isNull() )
+ {
+ TagLib::Tag* tag = fileref.tag();
+ if ( tag )
+ {
+ tag->setTitle( QStringToTString(tagData->title) );
+ tag->setArtist( QStringToTString(tagData->artist) );
+ tag->setAlbum( QStringToTString(tagData->album) );
+ tag->setTrack( tagData->track );
+ tag->setYear( tagData->year );
+ tag->setComment( QStringToTString(tagData->comment) );
+ tag->setGenre( QStringToTString(tagData->genre) );
+ }
+ else
+ {
+ return false;
+ }
+
+ if ( TagLib::MPEG::File *file = dynamic_cast<TagLib::MPEG::File *>( fileref.file() ) )
+ {
+ if ( file->ID3v2Tag() )
+ {
+ if ( !file->ID3v2Tag()->frameListMap()[ "TPOS" ].isEmpty() )
+ {
+ file->ID3v2Tag()->frameListMap()[ "TPOS" ].front()->setText( QStringToTString( QString::number(tagData->disc) ) );
+ }
+ else
+ {
+ TagLib::ID3v2::TextIdentificationFrame *frame = new TagLib::ID3v2::TextIdentificationFrame( "TPOS", TagLib::ID3v2::FrameFactory::instance()->defaultTextEncoding() );
+ frame->setText( QStringToTString( QString::number(tagData->disc) ) );
+ file->ID3v2Tag()->addFrame( frame );
+ }
+
+ if ( !file->ID3v2Tag()->frameListMap()[ "TCOM" ].isEmpty() )
+ {
+ file->ID3v2Tag()->frameListMap()[ "TCOM" ].front()->setText( QStringToTString( tagData->composer ) );
+ }
+ else
+ {
+ TagLib::ID3v2::TextIdentificationFrame *frame = new TagLib::ID3v2::TextIdentificationFrame( "TCOM", TagLib::ID3v2::FrameFactory::instance()->defaultTextEncoding() );
+ frame->setText( QStringToTString( tagData->composer ) );
+ file->ID3v2Tag()->addFrame( frame );
+ }
+
+ // HACK sets the id3v2 genre tag as string
+ if ( !file->ID3v2Tag()->frameListMap()[ "TCON" ].isEmpty() )
+ {
+ file->ID3v2Tag()->frameListMap()[ "TCON" ].front()->setText( QStringToTString( tagData->genre ) );
+ }
+ else
+ {
+ TagLib::ID3v2::TextIdentificationFrame *frame = new TagLib::ID3v2::TextIdentificationFrame( "TCON", TagLib::ID3v2::FrameFactory::instance()->defaultTextEncoding() );
+ frame->setText( QStringToTString( tagData->genre ) );
+ file->ID3v2Tag()->addFrame( frame );
+ }
+
+ // HACK sets the id3v2 year tag
+ if ( !file->ID3v2Tag()->frameListMap()[ "TYER" ].isEmpty() )
+ {
+ file->ID3v2Tag()->frameListMap()[ "TYER" ].front()->setText( QStringToTString( QString::number(tagData->year) ) );
+ }
+ else
+ {
+ TagLib::ID3v2::TextIdentificationFrame *frame = new TagLib::ID3v2::TextIdentificationFrame( "TYER", TagLib::ID3v2::FrameFactory::instance()->defaultTextEncoding() );
+ frame->setText( QStringToTString( QString::number(tagData->year) ) );
+ file->ID3v2Tag()->addFrame( frame );
+ }
+ }
+ }
+ else if ( TagLib::Ogg::Vorbis::File *file = dynamic_cast<TagLib::Ogg::Vorbis::File *>( fileref.file() ) )
+ {
+ if ( file->tag() )
+ {
+ file->tag()->addField( "COMPOSER", QStringToTString( tagData->composer ), true );
+
+ file->tag()->addField( "DISCNUMBER", QStringToTString( QString::number(tagData->disc) ), true );
+ }
+ }
+ else if ( TagLib::FLAC::File *file = dynamic_cast<TagLib::FLAC::File *>( fileref.file() ) )
+ {
+ if ( file->xiphComment() )
+ {
+ file->xiphComment()->addField( "COMPOSER", QStringToTString( tagData->composer ), true );
+
+ file->xiphComment()->addField( "DISCNUMBER", QStringToTString( QString::number(tagData->disc) ), true );
+ }
+ }
+ else if ( TagLib::MP4::File *file = dynamic_cast<TagLib::MP4::File *>( fileref.file() ) )
+ {
+ TagLib::MP4::Tag *mp4tag = dynamic_cast<TagLib::MP4::Tag *>( file->tag() );
+ if( mp4tag )
+ {
+ mp4tag->setComposer( QStringToTString( tagData->composer ) );
+
+ mp4tag->setDisk( tagData->disc );
+ }
+ }
+ if ( TagLib::TTA::File *file = dynamic_cast<TagLib::TTA::File *>( fileref.file() ) )
+ {
+ if ( file->ID3v2Tag() )
+ {
+ if ( !file->ID3v2Tag()->frameListMap()[ "TPOS" ].isEmpty() )
+ {
+ file->ID3v2Tag()->frameListMap()[ "TPOS" ].front()->setText( QStringToTString( QString::number(tagData->disc) ) );
+ }
+ else
+ {
+ TagLib::ID3v2::TextIdentificationFrame *frame = new TagLib::ID3v2::TextIdentificationFrame( "TPOS", TagLib::ID3v2::FrameFactory::instance()->defaultTextEncoding() );
+ frame->setText( QStringToTString( QString::number(tagData->disc) ) );
+ file->ID3v2Tag()->addFrame( frame );
+ }
+
+ if ( !file->ID3v2Tag()->frameListMap()[ "TCOM" ].isEmpty() )
+ {
+ file->ID3v2Tag()->frameListMap()[ "TCOM" ].front()->setText( QStringToTString( tagData->composer ) );
+ }
+ else
+ {
+ TagLib::ID3v2::TextIdentificationFrame *frame = new TagLib::ID3v2::TextIdentificationFrame( "TCOM", TagLib::ID3v2::FrameFactory::instance()->defaultTextEncoding() );
+ frame->setText( QStringToTString( tagData->composer ) );
+ file->ID3v2Tag()->addFrame( frame );
+ }
+ }
+ }
+
+ return fileref.save();
+ }
+ return false;
+}
+
+// bool TagEngine::canWrite( QString format )
+// {
+// format = format.lower();
+//
+// if( format == "ogg" ||
+// format == "flac" || format == "fla" ||
+// format == "mp3" || // TODO mp2 ?
+// format == "mpc" ||
+// format == "aac" ||
+// format == "ape" || format == "mac" ||
+// format == "aa" ||
+// format == "m4a" || format == "m4b" || format == "m4p" || format == "mp4" || format == "m4v" || format == "mp4v" ||
+// format == "ra" || format == "rv" || format == "rm" || format == "rmj" || format == "rmvb" ||
+// format == "wma" || format == "asf" )
+// {
+// return true;
+// }
+// else {
+// return false;
+// }
+// }
+