Ticket #2942: mythmusic_apic.diff

File mythmusic_apic.diff, 20.8 KB (added by stuartm, 5 years ago)

Added image size sanity check

  • mythmusic/mythmusic/visualize.cpp

     
    389389    return false; 
    390390} 
    391391 
    392 QString AlbumArt::getImageFilename()  
    393 { 
    394     return m_pParent->metadata()->getAlbumArt(m_currImageType); 
    395 } 
    396  
    397392bool AlbumArt::draw(QPainter *p, const QColor &back) 
    398393{ 
    399394    if (!m_pParent->decoder()) 
     
    402397    // If the directory has changed (new album) or the size, reload 
    403398    if (needsUpdate()) 
    404399    { 
    405         QImage art(getImageFilename()); 
     400        QImage art(m_pParent->metadata()->getAlbumArt(m_currImageType)); 
    406401        if (art.isNull()) 
    407402        { 
    408403            m_cursize = m_size; 
  • mythmusic/mythmusic/metadata.cpp

     
    381381 
    382382    if (m_id < 1 && query.isActive() && 1 == query.numRowsAffected()) 
    383383        m_id = query.lastInsertId().toInt(); 
     384 
     385    if (! m_albumart.empty()) 
     386    { 
     387        QValueList<struct AlbumArtImage>::iterator it; 
     388        for ( it = m_albumart.begin(); it != m_albumart.end(); ++it ) 
     389        { 
     390            query.prepare("SELECT albumart_id FROM music_albumart WHERE " 
     391                          "song_id=:SONGID AND imagetype=:TYPE;"); 
     392            query.bindValue(":TYPE", (*it).imageType); 
     393            query.bindValue(":SONGID", m_id); 
     394            query.exec(); 
     395 
     396            if (query.next()) 
     397            { 
     398                int artid = query.value(0).toInt(); 
     399 
     400                query.prepare("UPDATE music_albumart SET " 
     401                            "filename=:FILENAME, imagetype=:TYPE, " 
     402                            "song_id=:SONGID, embedded=:EMBED " 
     403                            "WHERE albumart_id=:ARTID"); 
     404 
     405                query.bindValue(":ARTID", artid); 
     406            } 
     407            else 
     408            { 
     409                query.prepare("INSERT INTO music_albumart ( filename, " 
     410                            "imagetype, song_id, embedded ) VALUES ( " 
     411                            ":FILENAME, :TYPE, :SONGID, :EMBED );"); 
     412            } 
     413 
     414            query.bindValue(":FILENAME", (*it).description); 
     415            query.bindValue(":TYPE", (*it).imageType); 
     416            query.bindValue(":SONGID", m_id); 
     417            query.bindValue(":EMBED", 1); 
     418 
     419            query.exec(); 
     420        } 
     421    } 
    384422} 
    385423 
    386424// Default values for formats 
     
    616654    m_changed = true; 
    617655} 
    618656 
     657void Metadata::setEmbeddedAlbumArt(QValueList<struct AlbumArtImage> albumart) 
     658{ 
     659    m_albumart = albumart; 
     660} 
     661 
    619662QStringList Metadata::fillFieldList(QString field) 
    620663{ 
    621664    QStringList searchList; 
     
    658701    return searchList; 
    659702} 
    660703 
    661 QStringList Metadata::AlbumArtInDir(QString directory) 
     704QImage Metadata::getAlbumArt(ImageType type) 
    662705{ 
    663     QStringList paths; 
     706    AlbumArtImages albumArt(this); 
    664707 
    665     directory.remove(0, m_startdir.length()); 
     708    QImage image; 
    666709 
    667     MSqlQuery query(MSqlQuery::InitCon()); 
    668     query.prepare("SELECT CONCAT_WS('/', music_directories.path, " 
    669                   "music_albumart.filename) FROM music_albumart " 
    670                   "LEFT JOIN music_directories ON " 
    671                   "music_directories.directory_id=music_albumart.directory_id " 
    672                   "WHERE music_directories.path = :DIR;"); 
    673     query.bindValue(":DIR", directory.utf8()); 
    674     if (query.exec()) 
     710    if (albumArt.isImageAvailable(type)) 
    675711    { 
    676         while (query.next()) 
    677         { 
    678             paths += m_startdir + "/" + 
    679                 QString::fromUtf8(query.value(0).toString()); 
    680         } 
     712        AlbumArtImage albumart_image = albumArt.getImage(type); 
     713 
     714        if (albumart_image.embedded) 
     715            image = QImage(MetaIOTagLib::getAlbumArt(m_filename, type)); 
     716        else 
     717            image = QImage(albumart_image.filename); 
    681718    } 
    682     return paths; 
    683 } 
    684719 
    685 QString Metadata::getAlbumArt(ImageType type) 
    686 { 
    687     QString res = ""; 
    688     AlbumArtImages albumArt(this); 
    689  
    690     res = albumArt.getImageFilename(type); 
    691  
    692     return res; 
     720    return image; 
    693721} 
    694722 
    695723MetadataLoadingThread::MetadataLoadingThread(AllMusic *parent_ptr) 
     
    13891417    if (m_parent == NULL) 
    13901418        return; 
    13911419 
     1420    int trackid = m_parent->ID(); 
     1421 
    13921422    QFileInfo fi(m_parent->Filename()); 
    13931423    QString dir = fi.dirPath(true); 
    13941424    dir.remove(0, Metadata::GetStartdir().length()); 
    13951425 
    13961426    MSqlQuery query(MSqlQuery::InitCon()); 
    13971427    query.prepare("SELECT albumart_id, CONCAT_WS('/', music_directories.path, " 
    1398             "music_albumart.filename), music_albumart.imagetype " 
     1428            "music_albumart.filename), music_albumart.imagetype, " 
     1429            "music_albumart.embedded " 
    13991430            "FROM music_albumart " 
    14001431            "LEFT JOIN music_directories ON " 
    14011432            "music_directories.directory_id=music_albumart.directory_id " 
    14021433            "WHERE music_directories.path = :DIR " 
     1434            "OR song_id = :SONGID " 
    14031435            "ORDER BY music_albumart.imagetype;"); 
    14041436    query.bindValue(":DIR", dir.utf8()); 
     1437    query.bindValue(":SONGID", trackid); 
    14051438    if (query.exec()) 
    14061439    { 
    14071440        while (query.next()) 
     
    14121445                    QString::fromUtf8(query.value(1).toString()); 
    14131446            image->imageType = (ImageType) query.value(2).toInt(); 
    14141447            image->typeName = getTypeName(image->imageType); 
     1448            if (query.value(3).toInt() == 1) 
     1449            { 
     1450                image->description = query.value(1).toString(); 
     1451                image->embedded = true; 
     1452            } 
     1453            else { 
     1454                image->embedded = false; 
     1455            } 
    14151456            m_imageList.append(image); 
    14161457        } 
    14171458    } 
    14181459} 
    14191460 
    1420 QString AlbumArtImages::getImageFilename(ImageType type) 
     1461AlbumArtImage AlbumArtImages::getImage(ImageType type) 
    14211462{ 
    14221463    // try to find a matching image 
    14231464    AlbumArtImage *image; 
     
    14251466    for (image = m_imageList.first(); image; image = m_imageList.next()) 
    14261467    { 
    14271468        if (image->imageType == type) 
    1428             return image->filename; 
     1469            return *image; 
    14291470    } 
    14301471 
    1431     return ""; 
     1472    return *image; 
    14321473} 
    14331474 
    14341475QStringList AlbumArtImages::getImageFilenames() 
     
    14451486    return paths; 
    14461487} 
    14471488 
     1489AlbumArtImage AlbumArtImages::getImageAt(uint index) 
     1490{ 
     1491    return *(m_imageList.at(index)); 
     1492} 
     1493 
    14481494bool AlbumArtImages::isImageAvailable(ImageType type) 
    14491495{ 
    14501496    // try to find a matching image 
     
    14591505    return false; 
    14601506} 
    14611507 
    1462 bool AlbumArtImages::saveImageType(const QString &filename, ImageType type) 
     1508bool AlbumArtImages::saveImageType(const int id, ImageType type) 
    14631509{ 
    1464     // try to find a matching filename 
    1465     AlbumArtImage *image; 
    1466  
    1467     for (image = m_imageList.first(); image; image = m_imageList.next()) 
    1468     { 
    1469         if (image->filename == filename) 
    1470         { 
    1471             image->imageType = type; 
    1472  
    1473             MSqlQuery query(MSqlQuery::InitCon()); 
    1474             query.prepare("UPDATE music_albumart SET imagetype = :TYPE " 
    1475                           "WHERE albumart_id = :ID"); 
    1476             query.bindValue(":TYPE", type); 
    1477             query.bindValue(":ID", image->id); 
    1478             return (query.exec()); 
    1479         } 
    1480     } 
    1481  
    1482     return false; 
     1510    MSqlQuery query(MSqlQuery::InitCon()); 
     1511    query.prepare("UPDATE music_albumart SET imagetype = :TYPE " 
     1512                    "WHERE albumart_id = :ID"); 
     1513    query.bindValue(":TYPE", type); 
     1514    query.bindValue(":ID", id); 
     1515    return (query.exec()); 
    14831516} 
    14841517 
    14851518QString AlbumArtImages::getTypeName(ImageType type) 
  • mythmusic/mythmusic/dbcheck.cpp

     
    99#include "mythtv/mythcontext.h" 
    1010#include "mythtv/mythdbcon.h" 
    1111 
    12 const QString currentDatabaseVersion = "1011"; 
     12const QString currentDatabaseVersion = "1012"; 
    1313 
    1414static bool UpdateDBVersionNumber(const QString &newnumber) 
    1515{    
     
    587587            return false; 
    588588 
    589589    } 
     590 
     591    if (dbver == "1011") 
     592    { 
     593        const QString updates[] = { 
     594"ALTER TABLE music_albumart ADD COLUMN song_id int(11) NOT NULL DEFAULT '0', ADD COLUMN embedded TINYINT(1) NOT NULL DEFAULT '0';", 
     595        "" 
     596}; 
     597 
     598        if (!performActualUpdate(updates, "1012", dbver)) 
     599            return false; 
     600 
     601    } 
    590602/* in 0.21 */ 
    591603//"DROP TABLE musicmetadata;", 
    592604//"DROP TABLE musicplaylist;", 
  • mythmusic/mythmusic/metadata.h

     
    44#include <qstring.h> 
    55#include <qstringlist.h> 
    66#include <qptrlist.h> 
     7#include <qvaluelist.h> 
    78#include <qmap.h> 
    89#include <qthread.h> 
    910 
    1011#include "treecheckitem.h" 
    1112#include <mythtv/uitypes.h> 
    1213 
     14 
    1315class AllMusic; 
    1416class CoverArt; 
    1517 
     
    2325    IT_LAST 
    2426}; 
    2527 
     28#include "metaiotaglib.h" 
     29 
    2630typedef struct AlbumArtImage 
    2731{ 
    2832    int       id; 
    2933    QString   filename; 
    3034    ImageType imageType; 
    3135    QString   typeName; 
     36    QString   description; 
     37    bool      embedded; 
    3238} AlbumArtImage; 
    3339 
     40//typedef QValueList<struct AlbumArtImage> AlbumArtList; 
     41 
    3442class Metadata 
    3543{ 
    3644  public: 
     
    5967                   m_lastplay(llastplay), 
    6068                   m_playcount(lplaycount), 
    6169                   m_compilation(lcompilation), 
     70                   m_albumart(), 
    6271                   m_id(lid), 
    6372                   m_filename(lfilename), 
    6473                   m_changed(false), 
     
    159168    } 
    160169    bool determineIfCompilation(bool cd = false); 
    161170 
     171    void setEmbeddedAlbumArt(QValueList<struct AlbumArtImage> art); 
     172 
    162173    bool isInDatabase(void); 
    163174    void dumpToDatabase(void); 
    164175    void setField(const QString &field, const QString &data); 
     
    173184 
    174185    static QStringList fillFieldList(QString field); 
    175186 
    176     QStringList AlbumArtInDir(QString directory); 
    177     QString getAlbumArt(ImageType type); 
     187    QImage getAlbumArt(ImageType type); 
    178188 
    179189  private: 
    180190    void setCompilationFormatting(bool cd = false); 
     
    201211    QString m_lastplay; 
    202212    int m_playcount; 
    203213    bool m_compilation; 
     214    QValueList<struct AlbumArtImage> m_albumart; 
    204215 
    205216    unsigned int m_id; 
    206217    QString m_filename; 
     
    389400    AlbumArtImages(Metadata *metadata); 
    390401 
    391402    uint                     getImageCount() { return m_imageList.count(); } 
    392     QString                  getImageFilename(ImageType type); 
     403    AlbumArtImage            getImage(ImageType type); 
    393404    QString                  getTypeName(ImageType type); 
    394405    QStringList              getImageFilenames(); 
    395406    QPtrList<AlbumArtImage> *getImageList() { return &m_imageList; } 
     
    397408 
    398409    bool isImageAvailable(ImageType type); 
    399410 
    400     bool saveImageType(const QString &filename, ImageType type); 
     411    bool saveImageType(const int id, ImageType type); 
    401412 
    402413    static ImageType guessImageType(const QString &filename); 
    403414 
  • mythmusic/mythmusic/editmetadata.cpp

     
    148148 
    149149    for (uint x = 0; x < albumArtList->count(); x++) 
    150150    { 
     151        if (albumArtList->at(x)->embedded) 
     152            continue; 
     153 
    151154        QPixmap *pixmap = createScaledPixmap(albumArtList->at(x)->filename, 
    152155                                             size.width(), size.height(), 
    153156                                             QImage::ScaleMin); 
     
    738741                image->typeName = item->text; 
    739742 
    740743                // save the image type to the DB 
    741                 albumArt->saveImageType(image->filename, image->imageType); 
     744                albumArt->saveImageType(image->id, image->imageType); 
    742745 
    743746                gridItemChanged(item); 
    744747            } 
  • mythmusic/mythmusic/metaiotaglib.h

     
    22#define METAIOTAGLIB_H_ 
    33 
    44#include "metaio.h" 
     5#include "metadata.h" 
    56#include <id3v2tag.h> 
    67#include <textidentificationframe.h> 
     8#include <attachedpictureframe.h> 
    79#include <mpegfile.h> 
     10#include <mpegproperties.h> 
    811 
    912using TagLib::MPEG::File; 
    1013using TagLib::Tag; 
    1114using TagLib::ID3v2::UserTextIdentificationFrame; 
     15using TagLib::ID3v2::AttachedPictureFrame; 
    1216using TagLib::String; 
     17using TagLib::MPEG::Properties; 
    1318 
    1419class MetaIOTagLib : public MetaIO 
    1520{ 
     
    2025    bool write(Metadata* mdata, bool exclusive = false); 
    2126    Metadata* read(QString filename); 
    2227 
     28    static QImage getAlbumArt(QString filename, ImageType type); 
     29 
    2330private: 
    2431 
    25      int getTrackLength(QString filename); 
     32    int getTrackLength(QString filename); 
    2633 
    27      UserTextIdentificationFrame* find(TagLib::ID3v2::Tag *tag, const String &description); 
     34    QValueList<struct AlbumArtImage> readAlbumArt(TagLib::ID3v2::Tag *tag); 
     35    UserTextIdentificationFrame* find(TagLib::ID3v2::Tag *tag, const String &description); 
    2836}; 
    2937 
    3038#endif 
  • mythmusic/mythmusic/metaiotaglib.cpp

     
    102102            genre = ""; 
    103103    int year = 0, tracknum = 0, length = 0, playcount = 0, rating = 0, id = 0; 
    104104    bool compilation = false; 
     105    QValueList<struct AlbumArtImage> albumart; 
    105106 
    106107    QString extension = filename.section( '.', -1 ) ; 
    107108 
     
    151152        // Length 
    152153        if(!taglib->ID3v2Tag()->frameListMap()["TLEN"].isEmpty()) 
    153154            length = taglib->ID3v2Tag()->frameListMap()["TLEN"].front()->toString().toInt(); 
     155 
     156        // Album Art 
     157        if(!taglib->ID3v2Tag()->frameListMap()["APIC"].isEmpty()) 
     158        { 
     159            albumart = readAlbumArt(taglib->ID3v2Tag()); 
     160        } 
    154161    } 
    155162 
    156163    // Fallback to filename reading 
     
    183190                                     id, rating, playcount); 
    184191 
    185192    retdata->setCompilation(compilation); 
     193    retdata->setEmbeddedAlbumArt(albumart); 
    186194 
    187195    return retdata; 
    188196} 
     
    203211} 
    204212 
    205213/*! 
     214 * \brief Read the albumart image from the file 
     215 * 
     216 * \param filename The filename for which we want to find the length. 
     217 * \param type The type of image we want - front/back etc 
     218 * \returns A QByteArray that can contains the image data. 
     219 */ 
     220QImage MetaIOTagLib::getAlbumArt(QString filename, ImageType type) 
     221{ 
     222    QImage picture; 
     223 
     224    AttachedPictureFrame::Type apicType  
     225        = AttachedPictureFrame::FrontCover; 
     226 
     227    switch (type) 
     228    { 
     229        case IT_UNKNOWN : 
     230            apicType = AttachedPictureFrame::Other; 
     231            break; 
     232        case IT_FRONTCOVER : 
     233            apicType = AttachedPictureFrame::FrontCover; 
     234            break; 
     235        case IT_BACKCOVER : 
     236            apicType = AttachedPictureFrame::BackCover; 
     237            break; 
     238        case IT_CD : 
     239            apicType = AttachedPictureFrame::Media; 
     240            break; 
     241        case IT_INLAY : 
     242            apicType = AttachedPictureFrame::LeafletPage; 
     243            break; 
     244        default: 
     245            return picture; 
     246    } 
     247 
     248    File *taglib = new TagLib::MPEG::File(filename.local8Bit()); 
     249 
     250    if (taglib->isOpen() && !taglib->ID3v2Tag()->frameListMap()["APIC"].isEmpty()) 
     251    { 
     252        TagLib::ID3v2::FrameList apicframes = taglib->ID3v2Tag()->frameListMap()["APIC"]; 
     253 
     254        for(TagLib::ID3v2::FrameList::Iterator it = apicframes.begin(); it != apicframes.end(); ++it) { 
     255            AttachedPictureFrame *frame = static_cast<AttachedPictureFrame *>(*it); 
     256            if(frame && frame->type() == apicType) 
     257            { 
     258                QImage picture; 
     259                picture.loadFromData((const uchar *)frame->picture().data(), frame->picture().size()); 
     260                return picture; 
     261            } 
     262        } 
     263    } 
     264 
     265    return picture; 
     266} 
     267 
     268/*! 
     269 * \brief Read the albumart image from the file 
     270 * 
     271 * \param tag The ID3v2 tag object in which to look for Album Art 
     272 * \returns A QValueList containing a list of AlbumArtImage structs 
     273 *          with the type and description of the APIC tag. 
     274 */ 
     275QValueList<struct AlbumArtImage> MetaIOTagLib::readAlbumArt(TagLib::ID3v2::Tag *tag) 
     276{ 
     277 
     278    QValueList<struct AlbumArtImage> artlist; 
     279 
     280    if (!tag->frameListMap()["APIC"].isEmpty()) 
     281    { 
     282        TagLib::ID3v2::FrameList apicframes = tag->frameListMap()["APIC"]; 
     283 
     284        for(TagLib::ID3v2::FrameList::Iterator it = apicframes.begin(); 
     285            it != apicframes.end(); ++it) 
     286        { 
     287 
     288            AttachedPictureFrame *frame = 
     289                static_cast<AttachedPictureFrame *>(*it); 
     290 
     291            // Assume a valid image would have at least 
     292            // 100 bytes of data (1x1 indexed gif is 35 bytes) 
     293            if (frame->picture().size() < 100) 
     294            { 
     295                VERBOSE(VB_GENERAL, "Music Scanner - Discarding APIC frame " 
     296                                    "with size less than 100 bytes"); 
     297                continue; 
     298            } 
     299 
     300            AlbumArtImage art; 
     301 
     302            if (frame->description().isEmpty()) 
     303            { 
     304                art.description = ""; 
     305            } 
     306            else { 
     307                art.description = TStringToQString(frame->description()); 
     308            } 
     309 
     310            art.embedded = true; 
     311 
     312            switch (frame->type()) 
     313            { 
     314                case AttachedPictureFrame::FrontCover : 
     315                    art.imageType = IT_FRONTCOVER; 
     316                    break; 
     317                case AttachedPictureFrame::BackCover : 
     318                    art.imageType = IT_BACKCOVER; 
     319                    break; 
     320                case AttachedPictureFrame::Media : 
     321                    art.imageType = IT_CD; 
     322                    break; 
     323                case AttachedPictureFrame::LeafletPage : 
     324                    art.imageType = IT_INLAY; 
     325                    break; 
     326                case AttachedPictureFrame::Other : 
     327                    art.imageType = IT_UNKNOWN; 
     328                    break; 
     329                default: 
     330                    VERBOSE(VB_GENERAL, "Music Scanner - APIC tag found " 
     331                                        "with unsupported type"); 
     332                    continue; 
     333            } 
     334 
     335            artlist.append(art); 
     336        } 
     337    } 
     338 
     339    return artlist; 
     340} 
     341 
     342/*! 
    206343 * \brief Find the a custom comment tag by description. 
    207344 *        This is a copy of the same function in the 
    208345 *        TagLib::ID3v2::UserTextIdentificationFrame Class with a static 
  • mythmusic/mythmusic/mainvisual.cpp

     
    353353        return; 
    354354 
    355355    QString  text = "\"" + mdata->Title() + "\"\n" +  mdata->Artist() + "\n" + mdata->Album(); 
    356     QString albumArt = mdata->getAlbumArt(IT_FRONTCOVER); 
     356    QImage albumArt = mdata->getAlbumArt(IT_FRONTCOVER); 
    357357 
    358358    if (text == info) 
    359359        return; 
     
    373373    } 
    374374 
    375375    // ...and only then when we have an album art image to show 
    376     if (visMode != 2 && fullScreen && albumArt == "") 
     376    if (visMode != 2 && fullScreen && albumArt.isNull()) 
    377377    { 
    378378        hide(); 
    379379        return; 
    380380    } 
    381381 
    382     if (fullScreen && albumArt != "") 
     382    if (fullScreen && ! albumArt.isNull()) 
    383383    { 
    384384        resize(parentWidget()->width(), parentWidget()->height()); 
    385385        move(0, 0); 
     
    403403    int x = indent; 
    404404    int y = indent; 
    405405 
    406     if (fullScreen && albumArt != "") 
     406    if (fullScreen && ! albumArt.isNull()) 
    407407    { 
    408408        p.fillRect(0, 0, info_pixmap.width(), info_pixmap.height(), QColor ("black")); 
    409409 
     
    422422    { 
    423423        p.fillRect(0, 0, info_pixmap.width(), info_pixmap.height(), QColor ("darkblue")); 
    424424 
    425         if (albumArt != "") 
     425        if (! albumArt.isNull()) 
    426426        { 
    427427            // draw the albumArt image 
    428428 
  • mythmusic/mythmusic/visualize.h

     
    9191 
    9292  private: 
    9393    bool needsUpdate(void); 
    94     QString getImageFilename(void); 
    9594    void findFrontCover(void); 
    9695 
    9796    QSize m_size, m_cursize; 
  • mythmusic/mythmusic/filescanner.cpp

     
    469469    MSqlQuery query(MSqlQuery::InitCon()); 
    470470    query.exec("SELECT CONCAT_WS('/', path, filename) " 
    471471               "FROM music_albumart LEFT JOIN music_directories " 
    472                "ON music_albumart.directory_id=music_directories.directory_id "); 
     472               "ON music_albumart.directory_id=music_directories.directory_id " 
     473               "WHERE music_albumart.embedded=0"); 
    473474 
    474475    int counter = 0; 
    475476