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 
0018 #include "ASFTagHelper.h"
0019 
0020 #include "StringHelper.h"
0021 
0022 #include <QBuffer>
0023 #include <QImage>
0024 
0025 #include <asfattribute.h>
0026 
0027 using namespace Meta::Tag;
0028 
0029 ASFTagHelper::ASFTagHelper( TagLib::Tag *tag, TagLib::ASF::Tag *asfTag, Amarok::FileType fileType )
0030             : TagHelper( tag, fileType )
0031             , m_tag( asfTag )
0032 {
0033     m_fieldMap.insert( Meta::valAlbumArtist, TagLib::String( "WM/AlbumArtist" ) );
0034     m_fieldMap.insert( Meta::valBpm,         TagLib::String( "WM/BeatsPerMinute" ) );
0035     m_fieldMap.insert( Meta::valCompilation, TagLib::String( "Amarok/Compilation" ) );  //Not standard tag
0036     m_fieldMap.insert( Meta::valComposer,    TagLib::String( "WM/Composer" ) );
0037     m_fieldMap.insert( Meta::valDiscNr,      TagLib::String( "WM/PartOfSet" ) );
0038     m_fieldMap.insert( Meta::valHasCover,    TagLib::String( "WM/Picture" ) );
0039     m_fieldMap.insert( Meta::valPlaycount,   TagLib::String( "FMPS/Playcount" ) );
0040     m_fieldMap.insert( Meta::valRating,      TagLib::String( "FMPS/Rating" ) );
0041     m_fieldMap.insert( Meta::valScore,       TagLib::String( "FMPS/Rating_Amarok_Score" ) );
0042     m_fieldMap.insert( Meta::valLyrics,      TagLib::String( "WM/Lyrics" ) );
0043 
0044     m_uidFieldMap.insert( UIDAFT,            TagLib::String( "Amarok/AFTv1" ) );
0045 }
0046 
0047 Meta::FieldHash
0048 ASFTagHelper::tags() const
0049 {
0050     Meta::FieldHash data = TagHelper::tags();
0051 
0052     TagLib::ASF::AttributeListMap map = m_tag->attributeListMap();
0053     for( TagLib::ASF::AttributeListMap::ConstIterator it = map.begin(); it != map.end(); ++it )
0054     {
0055         if( !it->second.size() )
0056             continue;
0057 
0058         qint64 field;
0059         TagLib::ASF::Attribute value = it->second[0];
0060         QString strValue = TStringToQString( value.toString() );
0061         if( ( field = fieldName( it->first ) ) )
0062         {
0063             if( field == Meta::valBpm || field == Meta::valPlaycount )
0064                 data.insert( field, value.toUInt() );
0065             else if( field == Meta::valRating )
0066                 data.insert( field, qRound( strValue.toFloat() * 10.0 ) );
0067             else if( field == Meta::valScore )
0068                 data.insert( field, strValue.toFloat() * 100.0 );
0069             else if( field == Meta::valDiscNr )
0070                 data.insert( field, value.toUInt() );
0071             else if( field == Meta::valCompilation )
0072                 data.insert( field, value.toBool() );
0073             else if( field == Meta::valHasCover )
0074             {
0075                 for( TagLib::ASF::AttributeList::ConstIterator cover = it->second.begin(); cover != it->second.end(); ++cover )
0076                 {
0077                     if( cover->type() != TagLib::ASF::Attribute::BytesType )
0078                         continue;
0079 
0080                     TagLib::ASF::Picture pict = cover->toPicture();
0081                     if( ( pict.type() == TagLib::ASF::Picture::FrontCover ||
0082                         pict.type() == TagLib::ASF::Picture::Other ) &&
0083                         pict.dataSize() > MIN_COVER_SIZE )
0084                     {
0085                         data.insert( field, true );
0086                         break;
0087                     }
0088                 }
0089             }
0090             else
0091                 data.insert( field, strValue );
0092         }
0093         else if( it->first == uidFieldName( UIDAFT ) && isValidUID( strValue, UIDAFT ) )
0094             data.insert( Meta::valUniqueId, strValue );
0095     }
0096 
0097     return data;
0098 }
0099 
0100 bool
0101 ASFTagHelper::setTags( const Meta::FieldHash &changes )
0102 {
0103     bool modified = TagHelper::setTags( changes );
0104 
0105     foreach( const qint64 key, changes.keys() )
0106     {
0107         QVariant value = changes.value( key );
0108         TagLib::String field = fieldName( key );
0109 
0110         if( !field.isNull() && !field.isEmpty() )
0111         {
0112             if( key == Meta::valHasCover )
0113                 continue;
0114             // http://gitorious.org/~jefferai/xdg-specs/jefferais-xdg-specs/blobs/mediaspecs/specifications/FMPSpecs/specification.txt sais that mp4 tags should be saved as strings
0115             if( key == Meta::valHasCover )
0116                 continue;
0117             else if( key == Meta::valRating )
0118                 m_tag->setAttribute( field, TagLib::ASF::Attribute( Qt4QStringToTString( QString::number( value.toFloat() / 10.0 ) ) ) );
0119             else if( key == Meta::valScore )
0120                 m_tag->setAttribute( field, TagLib::ASF::Attribute( Qt4QStringToTString( QString::number( value.toFloat() / 100.0 ) ) ) );
0121             else if( key == Meta::valBpm || key == Meta::valDiscNr )
0122                 m_tag->setAttribute( field, TagLib::ASF::Attribute( value.toUInt() ) );
0123             else if( key == Meta::valCompilation )
0124                 m_tag->setAttribute( field, TagLib::ASF::Attribute( value.toBool() ) );
0125             else
0126                 m_tag->setAttribute( field, TagLib::ASF::Attribute( Qt4QStringToTString( value.toString() ) ) );
0127 
0128             modified = true;
0129         }
0130         else if( key == Meta::valUniqueId )
0131         {
0132             QPair < UIDType, QString > uidPair = splitUID( value.toString() );
0133             if( uidPair.first == UIDInvalid )
0134                 continue;
0135 
0136             m_tag->setAttribute( uidFieldName( uidPair.first ),
0137                                  TagLib::ASF::Attribute( Qt4QStringToTString( uidPair.second ) ) );
0138             modified = true;
0139         }
0140     }
0141 
0142     return modified;
0143 }
0144 
0145 bool
0146 ASFTagHelper::hasEmbeddedCover() const
0147 {
0148     TagLib::ASF::AttributeListMap map = m_tag->attributeListMap();
0149     TagLib::String name = fieldName( Meta::valHasCover );
0150     for( TagLib::ASF::AttributeListMap::ConstIterator it = map.begin(); it != map.end(); ++it )
0151     {
0152         if( it->first == name )
0153         {
0154             TagLib::ASF::AttributeList coverList = it->second;
0155             for( TagLib::ASF::AttributeList::ConstIterator cover = coverList.begin(); cover != coverList.end(); ++cover )
0156             {
0157                 if( cover->type() != TagLib::ASF::Attribute::BytesType )
0158                     continue;
0159 
0160                 TagLib::ASF::Picture pict = cover->toPicture();
0161                 if( ( pict.type() == TagLib::ASF::Picture::FrontCover ||
0162                       pict.type() == TagLib::ASF::Picture::Other ) &&
0163                     pict.dataSize() > MIN_COVER_SIZE )
0164                 {
0165                     return true;
0166                 }
0167             }
0168         }
0169     }
0170 
0171     return false;
0172 }
0173 
0174 QImage
0175 ASFTagHelper::embeddedCover() const
0176 {
0177     TagLib::ASF::AttributeListMap map = m_tag->attributeListMap();
0178     TagLib::String name = fieldName( Meta::valHasCover );
0179 
0180     TagLib::ASF::Picture cover, otherCover;
0181     bool hasCover = false, hasOtherCover = false;
0182 
0183     for( TagLib::ASF::AttributeListMap::ConstIterator it = map.begin(); it != map.end(); ++it )
0184     {
0185         if( it->first == name )
0186         {
0187             TagLib::ASF::AttributeList coverList = it->second;
0188             for( TagLib::ASF::AttributeList::ConstIterator it = coverList.begin(); it != coverList.end(); ++it )
0189             {
0190                 if( it->type() != TagLib::ASF::Attribute::BytesType )
0191                     continue;
0192 
0193                 TagLib::ASF::Picture pict = it->toPicture();
0194 
0195                 if( pict.dataSize() < MIN_COVER_SIZE )
0196                     continue;
0197 
0198                 if( pict.type() == TagLib::ASF::Picture::FrontCover )
0199                 {
0200                     cover = pict;
0201                     hasCover = true;
0202                 }
0203                 else if( pict.type() == TagLib::ASF::Picture::Other )
0204                 {
0205                     otherCover = pict;
0206                     hasOtherCover = true;
0207                 }
0208             }
0209         }
0210     }
0211 
0212     if( !hasCover && hasOtherCover )
0213     {
0214         cover = otherCover;
0215         hasCover = true;
0216     }
0217 
0218     if( !hasCover )
0219         return QImage();
0220 
0221     return QImage::fromData( ( uchar * ) cover.picture().data(), cover.picture().size() );
0222 }
0223 
0224 bool
0225 ASFTagHelper::setEmbeddedCover( const QImage &cover )
0226 {
0227     QByteArray bytes;
0228     QBuffer buffer( &bytes );
0229 
0230     buffer.open( QIODevice::WriteOnly );
0231 
0232     if( !cover.save( &buffer, "JPEG" ) )
0233     {
0234         buffer.close();
0235         return false;
0236     }
0237 
0238     buffer.close();
0239 
0240     TagLib::String name = fieldName( Meta::valHasCover );
0241 
0242     // remove all covers
0243     m_tag->removeItem( name );
0244 
0245     // add new cover
0246     TagLib::ASF::Picture picture;
0247     picture.setPicture( TagLib::ByteVector( bytes.data(), bytes.count() ) );
0248     picture.setType( TagLib::ASF::Picture::FrontCover );
0249     picture.setMimeType( "image/jpeg" );
0250     m_tag->addAttribute( name, TagLib::ASF::Attribute( picture.render() ) );
0251 
0252     return true;
0253 }