diff options
Diffstat (limited to 'src/metadata/tagengine.cpp')
-rwxr-xr-x | src/metadata/tagengine.cpp | 419 |
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; +// } +// } + |