Ticket #8595: mythmusic_popm.diff

File mythmusic_popm.diff, 17.9 KB (added by stuartm, 11 years ago)
  • mythplugins/mythmusic/mythmusic/decoder.h

     
    9393    virtual Metadata *getMetadata(void);
    9494    virtual MetaIO *doCreateTagger (void);
    9595    virtual void commitMetadata(Metadata *mdata);
     96    virtual void commitPlayCount(const Metadata *mdata);
     97    virtual void commitRating(const Metadata *mdata);
    9698
    9799    // static methods
    98100    static QStringList all();
  • mythplugins/mythmusic/mythmusic/metaio.h

     
    1616    virtual ~MetaIO(void);
    1717
    1818    /*!
    19     * \brief Writes metadata back to a file
     19    * \brief Writes all metadata back to a file
    2020    *
    2121    * \param mdata A pointer to a Metadata object
    2222    * \returns Boolean to indicate success/failure.
     
    2424    virtual bool write(Metadata* mdata) = 0;
    2525
    2626    /*!
     27    * \brief Writes playcount (only) back to a file
     28    *
     29    * \param playcount Integer representing the number of times this file has
     30    *                  been played
     31    * \returns Boolean to indicate success/failure.
     32    */
     33    virtual bool writePlayCount(const Metadata* mdata)
     34    {
     35        (void)mdata;
     36        return false;
     37    }
     38
     39    /*!
     40    * \brief Writes rating (only) back to a file
     41    *
     42    * \param rating Integer between 0 and 10 representing the rating given to
     43    *               this file by the user
     44    * \returns Boolean to indicate success/failure.
     45    */
     46    virtual bool writeRating(const Metadata* mdata)
     47    {
     48        (void)mdata;
     49        return false;
     50    }
     51
     52    /*!
    2753    * \brief Reads Metadata from a file.
    2854    *
    2955    * \param filename The filename to read metadata from.
     
    3157    */
    3258    virtual Metadata* read(QString filename) = 0;
    3359
    34     void readFromFilename(QString filename, QString &artist, QString &album, 
     60    void readFromFilename(QString filename, QString &artist, QString &album,
    3561                          QString &title, QString &genre, int &tracknum);
    3662
    3763    Metadata* readFromFilename(QString filename, bool blnLength = false);
    3864
    3965    void readFromFilename(Metadata *metadata);
    40    
     66
    4167  protected:
    4268
    4369  private:
  • mythplugins/mythmusic/mythmusic/decoder.cpp

     
    156156    }
    157157}
    158158
     159/**
     160 *  \brief Write the playcount to the \p filename if the tag format supports it.
     161 *
     162 *  Creates a \p MetaIO object using \p Decoder::doCreateTagger and
     163 *  asks the MetaIO object to write the playcount to \p
     164 *  filename.
     165 *
     166 *  \params mdata the metadata to write to the disk
     167 */
     168void Decoder::commitPlayCount(const Metadata *mdata)
     169{
     170    MetaIO* p_tagger = doCreateTagger();
     171    if (p_tagger)
     172    {
     173        p_tagger->writePlayCount(mdata);
     174        delete p_tagger;
     175    }
     176}
     177
     178/**
     179 *  \brief Write the rating to the \p filename if the tag format supports it.
     180 *
     181 *  Creates a \p MetaIO object using \p Decoder::doCreateTagger and
     182 *  asks the MetaIO object to write the rating to \p
     183 *  filename.
     184 *
     185 *  \params mdata the metadata to write to the disk
     186 */
     187void Decoder::commitRating(const Metadata *mdata)
     188{
     189    MetaIO* p_tagger = doCreateTagger();
     190    if (p_tagger)
     191    {
     192        p_tagger->writeRating(mdata);
     193        delete p_tagger;
     194    }
     195}
     196
    159197// static methods
    160198
    161199int Decoder::ignore_id3 = 0;
  • mythplugins/mythmusic/mythmusic/editmetadata.cpp

     
    660660
    661661    m_metadata->dumpToDatabase();
    662662    *m_sourceMetadata = m_metadata;
     663
     664    if (m_metadata->hasChanged())
     665    {
     666        // Only save rating, this is safe for ID3 since mythtv uses it's own
     667        // labelled field and won't overwrite existing ratings
     668        Decoder *decoder = Decoder::create(m_metadata->Filename(), NULL, NULL, true);
     669        if (decoder)
     670        {
     671            decoder->commitRating(m_metadata);
     672            delete decoder;
     673        }
     674    }
     675
    663676    accept();
    664677}
    665678
  • mythplugins/mythmusic/mythmusic/metaiotaglib.h

     
    2626
    2727    virtual bool write(Metadata* mdata) = 0;
    2828    virtual Metadata* read(QString filename) = 0;
    29    
     29
    3030  protected:
    3131    int getTrackLength(TagLib::FileRef *file);
    3232    int getTrackLength(QString filename);
  • mythplugins/mythmusic/mythmusic/metaioid3.cpp

     
    44
    55// Libmyth
    66#include <mythverbose.h>
     7#include <set>
    78
     9const String email = "music@mythtv.org";  // TODO username/ip/hostname?
     10
    811MetaIOID3::MetaIOID3(void)
    912    : MetaIOTagLib()
    1013{
     
    2427{
    2528    QByteArray fname = filename.toLocal8Bit();
    2629    TagLib::MPEG::File *mpegfile = new TagLib::MPEG::File(fname.constData());
    27    
     30
    2831    if (!mpegfile->isOpen())
    2932    {
    3033        delete mpegfile;
     
    4346
    4447    if (!mpegfile)
    4548        return false;
    46    
     49
    4750    TagLib::ID3v2::Tag *tag = mpegfile->ID3v2Tag();
    4851
    4952    if (!tag)
     
    5154        delete mpegfile;
    5255        return false;
    5356    }
    54    
     57
    5558    WriteGenericMetadata(tag, mdata);
    56    
    57     if (mdata->Rating() > 0 || mdata->PlayCount() > 0)
    58     {
    59         // Needs to be implemented for taglib by subclassing ID3v2::Frames
    60         // with one to handle POPM frames
    61     }
    62    
     59
     60    // MythTV rating and playcount, stored in POPM frame
     61    writeRating(tag, mdata->Rating());
     62    writePlayCount(tag, mdata->PlayCount());
     63
    6364    // MusicBrainz ID
    6465    UserTextIdentificationFrame *musicbrainz = NULL;
    6566    musicbrainz = find(tag, "MusicBrainz Album Artist Id");
    6667
    6768    if (mdata->Compilation())
    6869    {
    69        
     70
    7071        if (!musicbrainz)
    7172        {
    7273            musicbrainz = new UserTextIdentificationFrame(TagLib::String::UTF8);
    7374            tag->addFrame(musicbrainz);
    7475            musicbrainz->setDescription("MusicBrainz Album Artist Id");
    7576        }
    76        
     77
    7778        musicbrainz->setText(MYTH_MUSICBRAINZ_ALBUMARTIST_UUID);
    7879    }
    7980    else if (musicbrainz)
     
    8687        TagLib::ID3v2::FrameList tpelist = tag->frameListMap()["TPE4"];
    8788        if (!tpelist.isEmpty())
    8889            tpe4frame = (TextIdentificationFrame *)tpelist.front();
    89        
     90
    9091        if (!tpe4frame)
    9192        {
    9293            tpe4frame = new TextIdentificationFrame(TagLib::ByteVector("TPE4"),
     
    9596        }
    9697        tpe4frame->setText(QStringToTString(mdata->CompilationArtist()));
    9798
    98        
     99
    99100        TextIdentificationFrame *tpe2frame = NULL;
    100101        tpelist = tag->frameListMap()["TPE2"];
    101102        if (!tpelist.isEmpty())
     
    109110        }
    110111        tpe2frame->setText(QStringToTString(mdata->CompilationArtist()));
    111112    }
    112    
     113
    113114    bool result = mpegfile->save();
    114115
    115116    delete mpegfile;
    116    
     117
    117118    return result;
    118119}
    119120
     
    123124Metadata *MetaIOID3::read(QString filename)
    124125{
    125126    TagLib::MPEG::File *mpegfile = OpenFile(filename);
    126    
     127
    127128    if (!mpegfile)
    128129        return NULL;
    129130
     
    134135        delete mpegfile;
    135136        return NULL;
    136137    }
    137    
     138
    138139    Metadata *metadata = new Metadata(filename);
    139    
     140
    140141    ReadGenericMetadata(tag, metadata);
    141142
    142143    bool compilation = false;
     
    151152        tpelist = tag->frameListMap()["TPE2"];
    152153    if (!tpelist.isEmpty())
    153154        tpeframe = (TextIdentificationFrame *)tpelist.front();
    154    
     155
    155156    if (tpeframe && !tpeframe->toString().isEmpty())
    156157    {
    157158        QString compilation_artist = TStringToQString(tpeframe->toString())
     
    159160        metadata->setCompilationArtist(compilation_artist);
    160161    }
    161162
     163    // MythTV rating and playcount, stored in POPM frame
     164    PopularimeterFrame *popm = findPOPM(tag, email);
     165
     166    if (!popm)
     167    {
     168        if (!tag->frameListMap()["POPM"].isEmpty())
     169            popm = dynamic_cast<PopularimeterFrame *>
     170                                        (tag->frameListMap()["POPM"].front());
     171    }
     172
     173    if (popm)
     174    {
     175        int rating = popm->rating();
     176        rating = static_cast<int>(((static_cast<float>(rating)/255.0)
     177                                                                * 10.0) + 0.5);
     178        metadata->setRating(rating);
     179        metadata->setPlaycount(popm->counter());
     180    }
     181
    162182    // Look for MusicBrainz Album+Artist ID in TXXX Frame
    163183    UserTextIdentificationFrame *musicbrainz = find(tag,
    164184                                            "MusicBrainz Album Artist Id");
     
    173193    }
    174194
    175195    // Length
    176     if (!mpegfile->ID3v2Tag()->frameListMap()["TLEN"].isEmpty())
     196    if (!tag->frameListMap()["TLEN"].isEmpty())
    177197    {
    178198        int length = tag->frameListMap()["TLEN"].front()->toString().toInt();
    179199        metadata->setLength(length);
     
    199219    }
    200220    else
    201221        delete mpegfile;
    202    
     222
    203223    return metadata;
    204224}
    205225
     
    237257        default:
    238258            return picture;
    239259    }
    240    
     260
    241261    QByteArray fname = filename.toLocal8Bit();
    242262    TagLib::MPEG::File *mpegfile = new TagLib::MPEG::File(fname.constData());
    243263
     
    364384    if (f && f->description() == description)
    365385      return f;
    366386  }
    367   return 0;
     387  return NULL;
    368388}
     389
     390/*!
     391 * \brief Find the POPM tag associated with MythTV
     392 *        This is a copy of the same function in the
     393 *        TagLib::ID3v2::UserTextIdentificationFrame Class with a static
     394 *        instead of dynamic cast.
     395 *
     396 * \param tag Pointer to TagLib::ID3v2::Tag object
     397 * \param email Email address associated with this POPM frame
     398 * \returns Pointer to frame
     399 */
     400PopularimeterFrame* MetaIOID3::findPOPM(TagLib::ID3v2::Tag *tag,
     401                                        const String &email)
     402{
     403  TagLib::ID3v2::FrameList l = tag->frameList("POPM");
     404  for(TagLib::ID3v2::FrameList::Iterator it = l.begin(); it != l.end(); ++it)
     405  {
     406    PopularimeterFrame *f = static_cast<PopularimeterFrame *>(*it);
     407    if (f && f->email() == email)
     408      return f;
     409  }
     410  return NULL;
     411}
     412
     413bool MetaIOID3::writePlayCount(const Metadata* mdata)
     414{
     415    QString filename = mdata->Filename();
     416    int playcount = mdata->PlayCount();
     417    TagLib::MPEG::File *mpegfile = OpenFile(filename);
     418
     419    if (!mpegfile)
     420        return false;
     421
     422    TagLib::ID3v2::Tag *tag = mpegfile->ID3v2Tag();
     423
     424    if (!tag)
     425    {
     426        delete mpegfile;
     427        return false;
     428    }
     429
     430    bool result = writePlayCount(tag, playcount);
     431
     432    mpegfile->save();
     433    delete mpegfile;
     434
     435    return result;
     436}
     437
     438bool MetaIOID3::writePlayCount(TagLib::ID3v2::Tag *tag, int playcount)
     439{
     440    if (!tag)
     441        return false;
     442
     443    PopularimeterFrame *popm = findPOPM(tag, email);
     444
     445    if (!popm)
     446    {
     447        popm = new PopularimeterFrame();
     448        tag->addFrame(popm);
     449        popm->setEmail(email);
     450    }
     451
     452    popm->setCounter(playcount);
     453
     454    return true;
     455}
     456
     457bool MetaIOID3::writeRating(const Metadata* mdata)
     458{
     459    QString filename = mdata->Filename();
     460    int rating = mdata->Rating();
     461    TagLib::MPEG::File *mpegfile = OpenFile(filename);
     462
     463    if (!mpegfile)
     464        return false;
     465
     466    TagLib::ID3v2::Tag *tag = mpegfile->ID3v2Tag();
     467
     468    if (!tag)
     469    {
     470        delete mpegfile;
     471        return false;
     472    }
     473
     474    bool result = writeRating(tag, rating);
     475
     476    mpegfile->save();
     477    delete mpegfile;
     478
     479    return result;
     480}
     481
     482bool MetaIOID3::writeRating(TagLib::ID3v2::Tag *tag, int rating)
     483{
     484    if (!tag)
     485        return false;
     486
     487    PopularimeterFrame *popm = findPOPM(tag, email);
     488
     489    if (!popm)
     490    {
     491        popm = new PopularimeterFrame();
     492        tag->addFrame(popm);
     493        popm->setEmail(email);
     494    }
     495    int popmrating = static_cast<int>(((static_cast<float>(rating) / 10.0)
     496                                                               * 255.0) + 0.5);
     497    popm->setRating(popmrating);
     498
     499    return true;
     500}
  • mythplugins/mythmusic/mythmusic/musicplayer.cpp

     
    166166            m_output->addListener(visual);
    167167            m_output->addVisual(visual);
    168168        }
    169  
     169
    170170        m_visualisers.insert(visual);
    171171    }
    172172}
     
    355355    if (m_currentMetadata)
    356356    {
    357357        if (m_currentMetadata->hasChanged())
     358        {
    358359            m_currentMetadata->persist();
     360            m_decoder->commitPlayCount(m_currentMetadata);
     361        }
    359362        delete m_currentMetadata;
    360363    }
    361364    m_currentMetadata = NULL;
     
    768771    {
    769772        m_currentTrack = position;
    770773    }
    771    
     774
    772775    m_currentFile.clear();
    773776    Track *track = m_currentPlaylist->getSongAt(m_currentTrack);
    774777    if (track)
    775778        m_currentFile = getFilenameFromID(track->getValue());
    776    
     779
    777780    if (!m_currentFile.isEmpty())
    778781        play();
    779782}
     
    989992
    990993void MusicPlayer::toMap(QHash<QString, QString> &map)
    991994{
    992     map["volumemute"] = QString("%1%").arg(getVolume()) + 
     995    map["volumemute"] = QString("%1%").arg(getVolume()) +
    993996                        (isMuted() ? " (" + tr("Muted") + ")" : "");
    994997    map["volume"] = QString("%1").arg(getVolume());
    995998    map["volumepercent"] = QString("%1%").arg(getVolume());
  • mythplugins/mythmusic/mythmusic/metaioavfcomment.h

     
    2121public:
    2222    MetaIOAVFComment(void);
    2323    virtual ~MetaIOAVFComment(void);
    24    
     24
    2525    bool write(Metadata* mdata);
    2626    Metadata* read(QString filename);
    27    
     27
    2828private:
    2929    int getTrackLength(QString filename);
    3030    int getTrackLength(AVFormatContext* p_context);
  • mythplugins/mythmusic/mythmusic/metaioid3.h

     
    99#include <id3v2tag.h>
    1010#include <textidentificationframe.h>
    1111#include <attachedpictureframe.h>
     12#include <popularimeterframe.h>
    1213#include <mpegproperties.h>
    1314#include <mpegfile.h>
    1415#include <tfile.h>
     
    1819
    1920using TagLib::ID3v2::UserTextIdentificationFrame;
    2021using TagLib::ID3v2::TextIdentificationFrame;
     22using TagLib::ID3v2::PopularimeterFrame;
    2123using TagLib::ID3v2::AttachedPictureFrame;
    2224using TagLib::MPEG::Properties;
    2325
     
    3739  public:
    3840    MetaIOID3(void);
    3941    virtual ~MetaIOID3(void);
    40    
     42
    4143    bool write(Metadata* mdata);
     44
     45    bool writePlayCount(const Metadata* mdata);
     46    bool writePlayCount(TagLib::ID3v2::Tag *tag, int playcount);
     47    bool writeRating(const Metadata* mdata);
     48    bool writeRating(TagLib::ID3v2::Tag *tag, int rating);
     49
    4250    Metadata* read(QString filename);
    4351    static QImage getAlbumArt(QString filename, ImageType type);
    4452
     
    4755
    4856    AlbumArtList readAlbumArt(TagLib::ID3v2::Tag *tag);
    4957    UserTextIdentificationFrame* find(TagLib::ID3v2::Tag *tag, const String &description);
     58    PopularimeterFrame* findPOPM(TagLib::ID3v2::Tag *tag, const String &email);
    5059};
    5160
    5261#endif
  • mythplugins/mythmusic/mythmusic/musiccommon.cpp

     
    191191
    192192    if (m_currentPlaylist)
    193193    {
    194         connect(m_currentPlaylist, SIGNAL(itemClicked(MythUIButtonListItem*)), 
     194        connect(m_currentPlaylist, SIGNAL(itemClicked(MythUIButtonListItem*)),
    195195                this, SLOT(playlistItemClicked(MythUIButtonListItem*)));
    196         connect(m_currentPlaylist, SIGNAL(itemSelected(MythUIButtonListItem*)), 
     196        connect(m_currentPlaylist, SIGNAL(itemSelected(MythUIButtonListItem*)),
    197197                this, SLOT(playlistItemSelected(MythUIButtonListItem*)));
    198198
    199199        updateUIPlaylist();
     
    836836    {
    837837        curMeta->incRating();
    838838        curMeta->persist();
     839        if (gPlayer->getDecoder())
     840            gPlayer->getDecoder()->commitRating(curMeta);
    839841        m_ratingState->DisplayState(QString("%1").arg(curMeta->Rating()));
    840842
    841843        // if all_music is still in scope we need to keep that in sync
     
    843845        {
    844846            Metadata *mdata = gMusicData->all_music->getMetadata(curMeta->ID());
    845847            if (mdata)
     848            {
    846849                mdata->incRating();
     850            }
    847851        }
    848852    }
    849853}
     
    859863    {
    860864        curMeta->decRating();
    861865        curMeta->persist();
     866        if (gPlayer->getDecoder())
     867            gPlayer->getDecoder()->commitRating(curMeta);
    862868        m_ratingState->DisplayState(QString("%1").arg(curMeta->Rating()));
    863869
    864870        // if all_music is still in scope we need to keep that in sync
     
    12561262    MetadataMap metadataMap;
    12571263    mdata->toMap(metadataMap);
    12581264    SetTextFromMap(metadataMap);
    1259    
     1265
    12601266    m_maxTime = mdata->Length() / 1000;
    12611267    if (m_coverartImage)
    12621268    {
     
    13831389        Metadata *mdata = gMusicData->all_music->getMetadata(trackid);
    13841390        if (mdata)
    13851391        {
    1386             MythUIButtonListItem *item = 
     1392            MythUIButtonListItem *item =
    13871393                new MythUIButtonListItem(m_currentPlaylist, "", qVariantFromValue(mdata));
    13881394
    13891395            MetadataMap metadataMap;