File indexing completed on 2024-04-28 04:45:52
0001 /**************************************************************************************** 0002 * Copyright (c) 2010 Sergey Ivanov <123kash@gmail.com> * 0003 * * 0004 * This program is free software; you can redistribute it and/or modify it under * 0005 * the terms of the GNU General Public License as published by the Free Software * 0006 * Foundation; either version 2 of the License, or (at your option) any later * 0007 * version. * 0008 * * 0009 * This program is distributed in the hope that it will be useful, but WITHOUT ANY * 0010 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A * 0011 * PARTICULAR PURPOSE. See the GNU General Public License for more details. * 0012 * * 0013 * You should have received a copy of the GNU General Public License along with * 0014 * this program. If not, see <http://www.gnu.org/licenses/>. * 0015 ****************************************************************************************/ 0016 0017 #include "TagHelper.h" 0018 0019 #include <config.h> 0020 0021 #include <QImage> 0022 #include <QRegExp> 0023 #include <QStringList> 0024 0025 #pragma GCC diagnostic push 0026 #pragma GCC diagnostic ignored "-Wnon-virtual-dtor" 0027 #include <fileref.h> 0028 #include <aifffile.h> 0029 #include <asffile.h> 0030 #include <flacfile.h> 0031 #include <mp4file.h> 0032 #include <mpcfile.h> 0033 #include <mpegfile.h> 0034 #include <oggfile.h> 0035 #ifdef TAGLIB_OPUS_FOUND 0036 #include <opusfile.h> 0037 #endif 0038 #include <oggflacfile.h> 0039 #include <rifffile.h> 0040 #include <speexfile.h> 0041 #include <trueaudiofile.h> 0042 #include <vorbisfile.h> 0043 #include <wavfile.h> 0044 #include <wavpackfile.h> 0045 #ifdef TAGLIB_MOD_FOUND 0046 #include <modfile.h> 0047 #include <s3mfile.h> 0048 #include <itfile.h> 0049 #include <xmfile.h> 0050 #endif 0051 #pragma GCC diagnostic pop 0052 0053 #include "APETagHelper.h" 0054 #include "ASFTagHelper.h" 0055 #include "ID3v2TagHelper.h" 0056 #include "MP4TagHelper.h" 0057 #include "VorbisCommentTagHelper.h" 0058 0059 #include "StringHelper.h" 0060 0061 using namespace Meta::Tag; 0062 0063 TagHelper::TagHelper( TagLib::Tag *tag, Amarok::FileType fileType ) 0064 : m_tag( tag ) 0065 , m_fileType( fileType ) 0066 { 0067 } 0068 0069 TagHelper::TagHelper( TagLib::ID3v1::Tag *tag, Amarok::FileType fileType ) 0070 : m_tag( tag ) 0071 , m_fileType( fileType ) 0072 { 0073 } 0074 0075 TagHelper::~TagHelper() 0076 { 0077 } 0078 0079 Meta::FieldHash 0080 TagHelper::tags() const 0081 { 0082 Meta::FieldHash data; 0083 0084 data.insert( Meta::valTitle, TStringToQString( m_tag->title() ) ); 0085 data.insert( Meta::valArtist, TStringToQString( m_tag->artist() ) ); 0086 data.insert( Meta::valAlbum, TStringToQString( m_tag->album() ) ); 0087 data.insert( Meta::valTrackNr, m_tag->track() ); 0088 data.insert( Meta::valYear, m_tag->year() ); 0089 data.insert( Meta::valGenre, TStringToQString( m_tag->genre() ) ); 0090 data.insert( Meta::valComment, TStringToQString( m_tag->comment() ) ); 0091 0092 return data; 0093 } 0094 0095 bool 0096 TagHelper::setTags( const Meta::FieldHash &changes ) 0097 { 0098 bool modified = false; 0099 0100 if( changes.contains( Meta::valTitle ) ) 0101 { 0102 m_tag->setTitle( Qt4QStringToTString( changes.value( Meta::valTitle ).toString() ) ); 0103 modified = true; 0104 } 0105 if( changes.contains( Meta::valArtist ) ) 0106 { 0107 m_tag->setArtist( Qt4QStringToTString( changes.value( Meta::valArtist ).toString() ) ); 0108 modified = true; 0109 } 0110 if( changes.contains( Meta::valAlbum ) ) 0111 { 0112 m_tag->setAlbum( Qt4QStringToTString( changes.value( Meta::valAlbum ).toString() ) ); 0113 modified = true; 0114 } 0115 if( changes.contains( Meta::valTrackNr ) ) 0116 { 0117 m_tag->setTrack( changes.value( Meta::valTrackNr ).toUInt() ); 0118 modified = true; 0119 } 0120 if( changes.contains( Meta::valYear ) ) 0121 { 0122 m_tag->setYear( changes.value( Meta::valYear ).toUInt() ); 0123 modified = true; 0124 } 0125 if( changes.contains( Meta::valGenre ) ) 0126 { 0127 m_tag->setGenre( Qt4QStringToTString( changes.value( Meta::valGenre ).toString() ) ); 0128 modified = true; 0129 } 0130 if( changes.contains( Meta::valComment ) ) 0131 { 0132 m_tag->setComment( Qt4QStringToTString( changes.value( Meta::valComment ).toString() ) ); 0133 modified = true; 0134 } 0135 0136 return modified; 0137 } 0138 0139 TagLib::ByteVector 0140 TagHelper::render() const 0141 { 0142 QByteArray byteArray; 0143 QDataStream stream( &byteArray, QIODevice::WriteOnly ); 0144 stream << tags(); 0145 return TagLib::ByteVector( byteArray.constData(), byteArray.size() ); 0146 } 0147 0148 bool 0149 TagHelper::hasEmbeddedCover() const 0150 { 0151 return false; 0152 } 0153 0154 QImage 0155 TagHelper::embeddedCover() const 0156 { 0157 return QImage(); 0158 } 0159 0160 bool 0161 TagHelper::setEmbeddedCover( const QImage &cover ) 0162 { 0163 Q_UNUSED( cover ) 0164 return false; 0165 } 0166 0167 TagLib::String 0168 TagHelper::fieldName( const qint64 field ) const 0169 { 0170 return m_fieldMap.value( field ); 0171 } 0172 0173 qint64 0174 TagHelper::fieldName( const TagLib::String &field ) const 0175 { 0176 return m_fieldMap.key( field ); 0177 } 0178 0179 QPair< TagHelper::UIDType, QString > 0180 TagHelper::splitUID( const QString &uidUrl ) const 0181 { 0182 TagHelper::UIDType type = UIDInvalid; 0183 QString uid = uidUrl; 0184 0185 if( uid.startsWith( QLatin1String("amarok-") ) ) 0186 uid = uid.remove( QRegExp( QStringLiteral("^(amarok-\\w+://).+$") ) ); 0187 0188 if( isValidUID( uid, UIDAFT ) ) 0189 type = UIDAFT; 0190 0191 return qMakePair( type, uid ); 0192 } 0193 0194 QPair< int, int > 0195 TagHelper::splitDiscNr( const QString &value ) const 0196 { 0197 int disc; 0198 int count = 0; 0199 if( value.indexOf( QLatin1Char('/') ) != -1 ) 0200 { 0201 QStringList list = value.split( QLatin1Char('/'), Qt::SkipEmptyParts ); 0202 disc = list.value( 0 ).toInt(); 0203 count = list.value( 1 ).toInt(); 0204 } 0205 else if( value.indexOf( QLatin1Char(':') ) != -1 ) 0206 { 0207 QStringList list = value.split( QLatin1Char(':'), Qt::SkipEmptyParts ); 0208 disc = list.value( 0 ).toInt(); 0209 count = list.value( 1 ).toInt(); 0210 } 0211 else 0212 disc = value.toInt(); 0213 0214 return qMakePair( disc, count ); 0215 } 0216 0217 bool 0218 TagHelper::isValidUID( const QString &uid, const TagHelper::UIDType type ) const 0219 { 0220 if( uid.length() >= 127 ) // the database can't handle longer uids 0221 return false; 0222 0223 QRegExp regexp( QStringLiteral("^$") ); 0224 0225 if( type == UIDAFT ) 0226 regexp.setPattern( QStringLiteral("^[0-9a-fA-F]{32}$") ); 0227 0228 return regexp.exactMatch( uid ); 0229 } 0230 0231 TagLib::String 0232 TagHelper::uidFieldName( const TagHelper::UIDType type ) const 0233 { 0234 return m_uidFieldMap.value( type ); 0235 } 0236 0237 TagLib::String 0238 TagHelper::fmpsFieldName( const TagHelper::FMPS field ) const 0239 { 0240 return m_fmpsFieldMap.value( field ); 0241 } 0242 0243 Amarok::FileType 0244 TagHelper::fileType() const 0245 { 0246 return m_fileType; 0247 } 0248 0249 QByteArray 0250 TagHelper::testString() const 0251 { 0252 TagLib::String string = m_tag->album() + m_tag->artist() + m_tag->comment() + 0253 m_tag->genre() + m_tag->title(); 0254 0255 return QByteArray( string.toCString( true ) ); 0256 } 0257 0258 0259 Meta::Tag::TagHelper * 0260 Meta::Tag::selectHelper( const TagLib::FileRef &fileref, bool forceCreation ) 0261 { 0262 TagHelper *tagHelper = nullptr; 0263 0264 if( TagLib::MPEG::File *file = dynamic_cast< TagLib::MPEG::File * >( fileref.file() ) ) 0265 { 0266 if( file->ID3v2Tag( forceCreation ) ) 0267 tagHelper = new ID3v2TagHelper( fileref.tag(), file->ID3v2Tag(), Amarok::Mp3 ); 0268 else if( file->APETag() ) 0269 tagHelper = new APETagHelper( fileref.tag(), file->APETag(), Amarok::Mp3 ); 0270 else if( file->ID3v1Tag() ) 0271 tagHelper = new TagHelper( fileref.tag(), Amarok::Mp3 ); 0272 } 0273 else if( TagLib::Ogg::Vorbis::File *file = dynamic_cast< TagLib::Ogg::Vorbis::File * >( fileref.file() ) ) 0274 { 0275 if( file->tag() ) 0276 tagHelper = new VorbisCommentTagHelper( fileref.tag(), file->tag(), Amarok::Ogg ); 0277 } 0278 else if( TagLib::Ogg::FLAC::File *file = dynamic_cast< TagLib::Ogg::FLAC::File * >( fileref.file() ) ) 0279 { 0280 if( file->tag() ) 0281 tagHelper = new VorbisCommentTagHelper( fileref.tag(), file->tag(), Amarok::Flac ); 0282 } 0283 else if( TagLib::Ogg::Speex::File *file = dynamic_cast< TagLib::Ogg::Speex::File * >( fileref.file() ) ) 0284 { 0285 if( file->tag() ) 0286 tagHelper = new VorbisCommentTagHelper( fileref.tag(), file->tag(), Amarok::Speex ); 0287 } 0288 #ifdef TAGLIB_OPUS_FOUND 0289 else if( TagLib::Ogg::Opus::File *file = dynamic_cast< TagLib::Ogg::Opus::File * >( fileref.file() ) ) 0290 { 0291 if( file->tag() ) 0292 tagHelper = new VorbisCommentTagHelper( fileref.tag(), file->tag(), Amarok::Opus ); 0293 } 0294 #endif 0295 else if( TagLib::FLAC::File *file = dynamic_cast< TagLib::FLAC::File * >( fileref.file() ) ) 0296 { 0297 if( file->xiphComment() ) 0298 tagHelper = new VorbisCommentTagHelper( fileref.tag(), file->xiphComment(), Amarok::Flac, file ); 0299 else if( file->ID3v2Tag() ) 0300 tagHelper = new ID3v2TagHelper( fileref.tag(), file->ID3v2Tag(), Amarok::Flac ); 0301 else if( file->ID3v1Tag() ) 0302 tagHelper = new TagHelper( fileref.tag(), Amarok::Flac ); 0303 } 0304 else if( TagLib::MP4::File *file = dynamic_cast< TagLib::MP4::File * >( fileref.file() ) ) 0305 { 0306 TagLib::MP4::Tag *tag = dynamic_cast< TagLib::MP4::Tag * >( file->tag() ); 0307 if( tag ) 0308 { 0309 Amarok::FileType specificType = Amarok::Mp4; 0310 QString filename = QString::fromLatin1( fileref.file()->name() ); 0311 foreach( Amarok::FileType type, QList<Amarok::FileType>() << Amarok::M4a << Amarok::M4v ) 0312 { 0313 if( filename.endsWith( Amarok::FileTypeSupport::toString( type ), Qt::CaseInsensitive ) ) 0314 specificType = type; 0315 } 0316 tagHelper = new MP4TagHelper( fileref.tag(), tag, specificType ); 0317 } 0318 } 0319 else if( TagLib::MPC::File *file = dynamic_cast< TagLib::MPC::File * >( fileref.file() ) ) 0320 { 0321 if( file->APETag( forceCreation ) ) 0322 tagHelper = new APETagHelper( fileref.tag(), file->APETag(), Amarok::Mpc ); 0323 else if( file->ID3v1Tag() ) 0324 tagHelper = new TagHelper( fileref.tag(), Amarok::Mpc ); 0325 } 0326 else if( TagLib::RIFF::AIFF::File *file = dynamic_cast< TagLib::RIFF::AIFF::File * >( fileref.file() ) ) 0327 { 0328 if( file->tag() ) 0329 tagHelper = new ID3v2TagHelper( fileref.tag(), file->tag(), Amarok::Aiff ); 0330 } 0331 else if( TagLib::RIFF::WAV::File *file = dynamic_cast< TagLib::RIFF::WAV::File * >( fileref.file() ) ) 0332 { 0333 if( file->tag() ) 0334 tagHelper = new ID3v2TagHelper( fileref.tag(), file->tag(), Amarok::Wav ); 0335 } 0336 else if( TagLib::ASF::File *file = dynamic_cast< TagLib::ASF::File * >( fileref.file() ) ) 0337 { 0338 TagLib::ASF::Tag *tag = dynamic_cast< TagLib::ASF::Tag * >( file->tag() ); 0339 if( tag ) 0340 tagHelper = new ASFTagHelper( fileref.tag(), tag, Amarok::Wma ); 0341 } 0342 else if( TagLib::TrueAudio::File *file = dynamic_cast< TagLib::TrueAudio::File * >( fileref.file() ) ) 0343 { 0344 if( file->ID3v2Tag( forceCreation ) ) 0345 tagHelper = new ID3v2TagHelper( fileref.tag(), file->ID3v2Tag(), Amarok::TrueAudio ); 0346 else if( file->ID3v1Tag() ) 0347 tagHelper = new TagHelper( fileref.tag(), Amarok::TrueAudio ); 0348 } 0349 else if( TagLib::WavPack::File *file = dynamic_cast< TagLib::WavPack::File * >( fileref.file() ) ) 0350 { 0351 if( file->APETag( forceCreation ) ) 0352 tagHelper = new APETagHelper( fileref.tag(), file->APETag(), Amarok::WavPack ); 0353 else if( file->ID3v1Tag() ) 0354 tagHelper = new TagHelper( fileref.tag(), Amarok::WavPack ); 0355 } 0356 #ifdef TAGLIB_MOD_FOUND 0357 else if( TagLib::Mod::File *file = dynamic_cast< TagLib::Mod::File * >( fileref.file() ) ) 0358 { 0359 if( file->tag() ) 0360 tagHelper = new TagHelper( fileref.tag(), Amarok::Mod ); 0361 } 0362 else if( TagLib::S3M::File *file = dynamic_cast< TagLib::S3M::File * >( fileref.file() ) ) 0363 { 0364 if( file->tag() ) 0365 tagHelper = new TagHelper( fileref.tag(), Amarok::S3M ); 0366 } 0367 else if( TagLib::IT::File *file = dynamic_cast< TagLib::IT::File * >( fileref.file() ) ) 0368 { 0369 if( file->tag() ) 0370 tagHelper = new TagHelper( fileref.tag(), Amarok::IT ); 0371 } 0372 else if( TagLib::XM::File *file = dynamic_cast< TagLib::XM::File * >( fileref.file() ) ) 0373 { 0374 if( file->tag() ) 0375 tagHelper = new TagHelper( fileref.tag(), Amarok::XM ); 0376 } 0377 #endif 0378 0379 return tagHelper; 0380 } 0381