Commit 610b5a84cf367fc217c605fcd8bf9f304b7909fe

Revert "Add embedded cover art support"

As discussed on the mailing list, there are multiple problems with this patch. Besides the several technical issues, which Dan, Bart, and Jeff all bring up, there is the fact that we have been in feature freeze for 2 weeks, and this does not belong right now.

Andreas, we still want this feature, and we will be merging it back in as soon as 2.3 final is tagged. However, you can see the multiple comments that people have had, and things that we would like to be changed (e.g. no taglib code in sqlmeta).

Anyway, regardless of the technical quality, this still breaks our feature freeze for the 2.3.0 release, and given the ease with which we can develop in parallel in git, we have no reason to violate our freeze for this.

This reverts commit a0c4a6c706d6f4f6cf22740bfa4aec768a7c4b87.

Revert "One more for you, good friend ChangeLog."

This reverts commit 3be4fe9b8f4adca3d2f67db14b1f55240e679c80.

CCMAIL: amarok-devel@kde.org
CCMAIL: ecroy@gmx.net
ChangeLog
(0 / 2)
  
55
66VERSION 2.3
77 FEATURES:
8 * Support for embedded cover art. Patch by Andreas L. <ecroy@gmx.net>.
9 (BR 176402)
108 * Podcast channels and episodes can be dragged to add them to other
119 providers. (BR 195704)
1210 * Trackaction buttons are now available in the label for the current track
  
799799 directoryData.append( data );
800800 currentDir = url.directory();
801801 }
802
803 //the boolean attribute 'apic' indicates that the file contains an embedded cover-art image
804 //we therefore add the path of the audio file to the list of images for this album
805 if( !attrs.value( "apic" ).isEmpty() )
806 {
807 QList<QPair<QString, QString> > covers;
808 covers += qMakePair( attrs.value( "artist" ).toString(), attrs.value( "album" ).toString() );
809 processor.addImage( attrs.value( "path" ).toString(), covers );
810 }
811802 }
812803 else if( localname == "folder" )
813804 {
  
188188 QString goodPath;
189189 foreach( const QString &path, paths )
190190 {
191 // skip embedded images
192 if( SqlAlbum::isEmbeddedImage( path ) )
193 continue;
194
195191 QString file = QFileInfo( path ).fileName();
196192
197193 //prioritize "front"
234234 if( !goodPath.isEmpty() )
235235 return goodPath;
236236
237 //next: pick largest non-embedded image -- often a high-quality blowup of the front
237 //finally: pick largest image -- often a high-quality blowup of the front
238238 //so that people can print it out
239 qint64 size = -1;
239 qint64 size = 0;
240240 QString current;
241241 foreach( const QString &path, paths )
242242 {
243243 QFileInfo info( path );
244 if( info.size() > size &&
245 ! SqlAlbum::isEmbeddedImage( path ) )
244 if( info.size() > size )
246245 {
247246 size = info.size();
248247 current = path;
249248 }
250249 }
251
252 //finally: if all available images are embedded, simply pick the first one
253 if( size == -1 )
254 return paths.first();
255
256250 return current;
251
257252}
258253
259254void
  
4646#include <KLocale>
4747#include <KSharedPtr>
4848
49//Taglib:
50#include <mpegfile.h>
51#include <id3v2tag.h>
52#include <attachedpictureframe.h>
53
5449using namespace Meta;
5550
5651QString
11131113
11141114 //FIXME this cache doesn't differentiate between shadowed/unshadowed
11151115 if( m_images.contains( size ) )
1116 {
1117 if (isEmbeddedImage( m_images.value( size ) ) )
1118 return QPixmap::fromImage( loadImageFromTag( m_images.value( size ) ) );
1119 else
1120 return QPixmap( m_images.value( size ) );
1121 }
1116 return QPixmap( m_images.value( size ) );
11221117
11231118 QString result;
11241119
11521152 {
11531153 m_hasImage = true;
11541154 m_images.insert( size, result );
1155 if (isEmbeddedImage( m_images.value( size ) ) )
1156 return QPixmap::fromImage( loadImageFromTag( result ) );
1157 else
1158 return QPixmap( result );
1155 return QPixmap( result );
11591156 }
11601157
11611158 // Cover fetching runs in another thread. If there is a retrieved cover
14111411 // Don't overwrite if it already exists
14121412 if( !QFile::exists( cachedImagePath ) )
14131413 {
1414 QImage img;
1415 if ( isEmbeddedImage( path ) )
1416 img = loadImageFromTag( path );
1417 else
1418 img.load( path );
1419
1420 if( img.isNull() )
1414 QImage img( path );
1415 if( img.isNull() )
14211416 return QString();
14221417
14231418 // resize and save the image
14241424 return QString();
14251425}
14261426
1427QImage
1428SqlAlbum::loadImageFromTag( const QString path ) const
1429{
1430#ifdef COMPLEX_TAGLIB_FILENAME
1431 const wchar_t * encodedName = reinterpret_cast<const wchar_t *>(path.utf16());
1432#else
1433 QByteArray fileName = QFile::encodeName( path );
1434 const char * encodedName = fileName.constData(); // valid as long as fileName exists
1435#endif
1436
1437 TagLib::FileRef fileref;
1438 TagLib::Tag *tag = 0;
1439 fileref = TagLib::FileRef( encodedName, true );
1440
1441 if( !fileref.isNull() )
1442 {
1443 tag = fileref.tag();
1444 if ( tag )
1445 {
1446 if ( TagLib::MPEG::File *file = dynamic_cast<TagLib::MPEG::File *>( fileref.file() ) )
1447 {
1448 if ( !file->ID3v2Tag()->frameListMap()["APIC"].isEmpty() )
1449 {
1450 TagLib::ID3v2::FrameList apicList = file->ID3v2Tag()->frameListMap()["APIC"];
1451 for ( TagLib::ID3v2::FrameList::ConstIterator it = apicList.begin(), end = apicList.end(); it != end; ++it )
1452 {
1453 TagLib::ID3v2::AttachedPictureFrame *apicFrame = (TagLib::ID3v2::AttachedPictureFrame *)(*it);
1454 // take first APIC frame which is a FrontCover
1455 if ( apicFrame->type() == TagLib::ID3v2::AttachedPictureFrame::FrontCover)
1456 {
1457 return QImage::fromData((uchar*)(apicFrame->picture().data()), apicFrame->picture().size());
1458 }
1459 }
1460 // if there was no FrontCover, just take the first picture available
1461 TagLib::ID3v2::AttachedPictureFrame *apicFrame = (TagLib::ID3v2::AttachedPictureFrame *)(apicList[0]);
1462 return QImage::fromData((uchar*)(apicFrame->picture().data()), apicFrame->picture().size());
1463 }
1464 }
1465 }
1466 }
1467 return QImage::QImage();
1468}
1469
14701427QString
14711428SqlAlbum::findImage( int size )
14721429{
16711671SqlAlbum::createCapabilityInterface( Meta::Capability::Type type )
16721672{
16731673 return ( m_delegate ? m_delegate->createCapabilityInterface( type, this ) : 0 );
1674}
1675
1676bool
1677SqlAlbum::isEmbeddedImage( const QString& path )
1678{
1679 //Entries in the images table are currently either image files or audio files with embedded cover-art images.
1680 //This function simply checks the file extension and determines whether it is an audio file or not, using the
1681 //same suffix criteria as in ScanResultProcessor::addTrack for now.
1682 //Future versions could extend the database scheme to include image type information.
1683 //No additional checks are made - we trust that the entry was put into the images table for a reason.
1684
1685 QStringList audioFiletypes;
1686 audioFiletypes << "mp3" << "ogg" << "oga" << "flac" << "wma" << "m4a" << "m4b";
1687 return audioFiletypes.contains( QFileInfo( path ).suffix().toLower() );
16881674}
16891675
16901676//---------------SqlComposer---------------------------------
  
292292
293293 virtual Meta::Capability* createCapabilityInterface( Meta::Capability::Type type );
294294
295 static bool isEmbeddedImage( const QString& path );
296
297295 //SQL specific methods
298296 int id() const { return m_id; }
299297
309309 void updateImage( const QString path ) const; // Updates the database to ensure the album has the correct path
310310 // Finds or creates a magic value in the database which tells Amarok not to auto fetch an image since it has been explicitly unset.
311311 int unsetImageId() const;
312 QImage loadImageFromTag( const QString path ) const;
313312
314313 private:
315314 SqlCollection* m_collection;
  
4343#include <QTextStream>
4444#include <QTime>
4545#include <QTimer>
46#include <qpixmap.h>
4746
4847//Taglib:
4948#include <apetag.h>
6161#include <tlist.h>
6262#include <tstring.h>
6363#include <vorbisfile.h>
64#include <attachedpictureframe.h>
65#include <tbytevector.h>
6664
6765#include <audiblefiletyperesolver.h>
6866#include <realmediafiletyperesolver.h>
455455
456456 else
457457 {
458 //FIXME: PORT 2.0
459// QList<EmbeddedImage> images;
458460 const AttributeHash attributes = readTags( path );
459461
460462 if( !attributes.empty() )
467467
468468 if( !covers.contains( cover ) )
469469 covers += cover;
470
471 //FIXME: PORT 2.0
472// foreach( EmbeddedImage image, images )
473// {
474// AttributeHash attributes;
475// if( m_batch && !m_rpath.isEmpty() )
476// {
477// QString rpath = path;
478// rpath.remove( QDir::cleanPath( QDir::currentPath() ) );
479// rpath.prepend( QDir::cleanPath( m_rpath + '/' ) );
480// attributes["path"] = rpath;
481// }
482// else
483// attributes["path"] = path;
484// attributes["hash"] = image.hash();
485// attributes["description"] = image.description();
486// writeElement( "embed", attributes );
487// }
470488 }
471489 }
472490
621621 if ( !file->ID3v2Tag()->frameListMap()["TCMP"].isEmpty() )
622622 compilation = TStringToQString( file->ID3v2Tag()->frameListMap()["TCMP"].front()->toString() ).trimmed();
623623
624 if ( !file->ID3v2Tag()->frameListMap()["APIC"].isEmpty() )
625 attributes["apic"] = QString("true");
624 //FIXME: Port 2.0
625// if( images )
626// loadImagesFromTag( *file->ID3v2Tag(), *images );
626627 }
627628// HACK: charset-detector disabled, so all tags assumed utf-8
628629// TODO: fix charset-detector to detect encoding with higher accuracy