File indexing completed on 2024-05-12 08:47:34
0001 /**************************************************************************************** 0002 * Copyright (C) 2003-2005 Max Howell <max.howell@methylblue.com> * 0003 * (C) 2003-2010 Mark Kretschmann <kretschmann@kde.org> * 0004 * (C) 2005-2007 Alexandre Oliveira <aleprj@gmail.com> * 0005 * (C) 2008 Dan Meltzer <parallelgrapefruit@gmail.com> * 0006 * (C) 2008-2009 Jeff Mitchell <mitchell@kde.org> * 0007 * (C) 2010 Ralf Engels <ralf-engels@gmx.de> * 0008 * (c) 2010 Sergey Ivanov <123kash@gmail.com> * 0009 * * 0010 * This program is free software; you can redistribute it and/or modify it under * 0011 * the terms of the GNU General Public License as published by the Free Software * 0012 * Foundation; either version 2 of the License, or (at your option) any later * 0013 * version. * 0014 * * 0015 * This program is distributed in the hope that it will be useful, but WITHOUT ANY * 0016 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A * 0017 * PARTICULAR PURPOSE. See the GNU General Public License for more details. * 0018 * * 0019 * You should have received a copy of the GNU General Public License along with * 0020 * this program. If not, see <http://www.gnu.org/licenses/>. * 0021 ****************************************************************************************/ 0022 0023 0024 #include "MP4TagHelper.h" 0025 0026 #include "StringHelper.h" 0027 0028 #include <QBuffer> 0029 #include <QImage> 0030 0031 using namespace Meta::Tag; 0032 0033 MP4TagHelper::MP4TagHelper( TagLib::Tag *tag, TagLib::MP4::Tag *mp4Tag, Amarok::FileType fileType ) 0034 : TagHelper( tag, fileType ) 0035 , m_tag( mp4Tag ) 0036 { 0037 m_fieldMap.insert( Meta::valAlbumArtist, TagLib::String( "aART" ) ); 0038 m_fieldMap.insert( Meta::valBpm, TagLib::String( "tmpo" ) ); 0039 m_fieldMap.insert( Meta::valCompilation, TagLib::String( "cpil" ) ); 0040 m_fieldMap.insert( Meta::valComposer, TagLib::String( "\xA9wrt" ) ); 0041 m_fieldMap.insert( Meta::valDiscNr, TagLib::String( "disk" ) ); 0042 m_fieldMap.insert( Meta::valHasCover, TagLib::String( "covr" ) ); 0043 m_fieldMap.insert( Meta::valPlaycount, TagLib::String( "----:com.apple.iTunes:FMPS_Playcount" ) ); 0044 m_fieldMap.insert( Meta::valRating, TagLib::String( "----:com.apple.iTunes:FMPS_Rating" ) ); 0045 m_fieldMap.insert( Meta::valScore, TagLib::String( "----:com.apple.iTunes:FMPS_Rating_Amarok_Score" ) ); 0046 m_fieldMap.insert( Meta::valLyrics, TagLib::String( "\xa9lyr" ) ); 0047 0048 m_uidFieldMap.insert( UIDAFT, TagLib::String( "----:com.apple.iTunes:Amarok 2 AFTv1 - amarok.kde.org" ) ); 0049 } 0050 0051 Meta::FieldHash 0052 MP4TagHelper::tags() const 0053 { 0054 Meta::FieldHash data = TagHelper::tags(); 0055 0056 TagLib::MP4::ItemListMap map = m_tag->itemListMap(); 0057 for( TagLib::MP4::ItemListMap::ConstIterator it = map.begin(); it != map.end(); ++it ) 0058 { 0059 qint64 field; 0060 QString value = TStringToQString( it->second.toStringList().toString( '\n' ) ); 0061 if( ( field = fieldName( it->first ) ) ) 0062 { 0063 if( field == Meta::valHasCover ) 0064 { 0065 TagLib::MP4::CoverArtList coverList = it->second.toCoverArtList(); 0066 for( TagLib::MP4::CoverArtList::ConstIterator it = coverList.begin(); it != coverList.end(); ++it ) 0067 if( it->data().size() > MIN_COVER_SIZE ) 0068 { 0069 data.insert( field, true ); 0070 break; 0071 } 0072 } 0073 0074 // http://gitorious.org/~jefferai/xdg-specs/jefferais-xdg-specs/blobs/mediaspecs/specifications/FMPSpecs/specification.txt sais that mp4 tags should be saved as strings 0075 else if( field == Meta::valPlaycount ) 0076 data.insert( field, value.toInt() ); 0077 else if( field == Meta::valRating ) 0078 data.insert( field, qRound( value.toFloat() * 10.0 ) ); 0079 else if( field == Meta::valScore ) 0080 data.insert( field, value.toFloat() * 100.0 ); 0081 0082 else if( field == Meta::valBpm ) 0083 data.insert( field, it->second.toInt() ); 0084 else if( field == Meta::valDiscNr ) 0085 data.insert( field, it->second.toIntPair().first ); 0086 0087 else if( field == Meta::valCompilation ) 0088 data.insert( field, it->second.toBool() ); 0089 else 0090 data.insert( field, value ); 0091 } 0092 else if( it->first == uidFieldName( UIDAFT ) && isValidUID( value, UIDAFT ) ) 0093 data.insert( Meta::valUniqueId, value ); 0094 } 0095 0096 return data; 0097 } 0098 0099 bool 0100 MP4TagHelper::setTags( const Meta::FieldHash &changes ) 0101 { 0102 bool modified = TagHelper::setTags( changes ); 0103 0104 foreach( const qint64 key, changes.keys() ) 0105 { 0106 QVariant value = changes.value( key ); 0107 TagLib::String field = fieldName( key ); 0108 0109 if( !field.isNull() && !field.isEmpty() ) 0110 { 0111 // http://gitorious.org/~jefferai/xdg-specs/jefferais-xdg-specs/blobs/mediaspecs/specifications/FMPSpecs/specification.txt sais that mp4 tags should be saved as strings 0112 if( key == Meta::valHasCover ) 0113 continue; 0114 else if( key == Meta::valRating ) 0115 m_tag->itemListMap()[field] = TagLib::StringList( Qt4QStringToTString( QString::number( value.toFloat() / 10.0 ) ) ); 0116 else if( key == Meta::valScore ) 0117 m_tag->itemListMap()[field] = TagLib::StringList( Qt4QStringToTString( QString::number( value.toFloat() / 100.0 ) ) ); 0118 else if( key == Meta::valBpm || key == Meta::valDiscNr ) 0119 m_tag->itemListMap()[field] = TagLib::MP4::Item( value.toInt(), 0 ); 0120 else if( key == Meta::valCompilation ) 0121 m_tag->itemListMap()[field] = TagLib::MP4::Item( value.toBool() ); 0122 else 0123 m_tag->itemListMap()[field] = TagLib::StringList( Qt4QStringToTString( value.toString() ) ); 0124 0125 modified = true; 0126 } 0127 else if( key == Meta::valUniqueId ) 0128 { 0129 QPair < UIDType, QString > uidPair = splitUID( value.toString() ); 0130 if( uidPair.first == UIDInvalid ) 0131 continue; 0132 0133 m_tag->itemListMap()[uidFieldName( uidPair.first )] = TagLib::StringList( Qt4QStringToTString( uidPair.second ) ); 0134 modified = true; 0135 } 0136 } 0137 0138 return modified; 0139 } 0140 0141 bool 0142 MP4TagHelper::hasEmbeddedCover() const 0143 { 0144 TagLib::MP4::ItemListMap map = m_tag->itemListMap(); 0145 TagLib::String name = fieldName( Meta::valHasCover ); 0146 for( TagLib::MP4::ItemListMap::ConstIterator it = map.begin(); it != map.end(); ++it ) 0147 { 0148 if( it->first == name ) 0149 { 0150 TagLib::MP4::CoverArtList coverList = it->second.toCoverArtList(); 0151 for( TagLib::MP4::CoverArtList::ConstIterator cover = coverList.begin(); cover != coverList.end(); ++cover ) 0152 { 0153 if( cover->data().size() > MIN_COVER_SIZE ) 0154 return true; 0155 } 0156 } 0157 } 0158 0159 return false; 0160 } 0161 0162 QImage 0163 MP4TagHelper::embeddedCover() const 0164 { 0165 TagLib::MP4::ItemListMap map = m_tag->itemListMap(); 0166 TagLib::String name = fieldName( Meta::valHasCover ); 0167 for( TagLib::MP4::ItemListMap::ConstIterator it = map.begin(); it != map.end(); ++it ) 0168 { 0169 if( it->first == name ) 0170 { 0171 TagLib::MP4::CoverArtList coverList = it->second.toCoverArtList(); 0172 for( TagLib::MP4::CoverArtList::Iterator cover = coverList.begin(); cover != coverList.end(); ++cover ) 0173 { 0174 if( cover->data().size() > MIN_COVER_SIZE ) 0175 return QImage::fromData( ( uchar * ) cover->data().data(), cover->data().size() ); 0176 } 0177 } 0178 } 0179 0180 return QImage(); 0181 } 0182 0183 bool 0184 MP4TagHelper::setEmbeddedCover( const QImage &cover ) 0185 { 0186 QByteArray bytes; 0187 QBuffer buffer( &bytes ); 0188 0189 buffer.open( QIODevice::WriteOnly ); 0190 0191 if( !cover.save( &buffer, "JPEG" ) ) 0192 { 0193 buffer.close(); 0194 return false; 0195 } 0196 0197 buffer.close(); 0198 0199 TagLib::MP4::CoverArtList covers; 0200 0201 covers.append( TagLib::MP4::CoverArt( TagLib::MP4::CoverArt::JPEG, TagLib::ByteVector( bytes.data(), bytes.count() ) ) ); 0202 0203 m_tag->itemListMap()[fieldName( Meta::valHasCover )] = TagLib::MP4::Item( covers ); 0204 0205 return true; 0206 }