Ticket #341: dbupdate9.patch

File dbupdate9.patch, 38.4 KB (added by eskil <myth@…>, 15 years ago)

fixed patch

  • mythtv/libs/libmyth/lcddevice.cpp

     
    192192#endif
    193193        // Just stream the text out the socket
    194194
    195         os << someText << "\n";
     195        os << someText << "\n" << flush;
    196196    }
    197197    else
    198198    {
     
    387387    else if (value > 1.0)
    388388        value = 1.0;
    389389       
    390     sendToServer("SET_GENERIC_PROGRESS " + QString().setNum(value));   
     390    sendToServer("SET_GENERIC_PROGRESS " + QString().setNum (false) +
     391                 " " + QString().setNum(value));   
    391392}
    392393
     394void LCD::setGenericBusy ()
     395{
     396    if (!lcd_ready || !lcd_showgeneric)
     397        return;
     398
     399    sendToServer("SET_GENERIC_PROGRESS 1 0.0");
     400}
     401
    393402void LCD::setMusicProgress(QString time, float value)
    394403{
    395404    if (!lcd_ready || !lcd_showmusic)
  • mythtv/libs/libmyth/mythdialogs.cpp

     
    15201520    progress->setBackgroundOrigin(ParentOrigin);
    15211521    progress->setProgress(0);
    15221522
    1523     m_totalSteps = totalSteps;
    1524     steps = totalSteps / 1000;
    1525     if (steps == 0)
    1526         steps = 1;
     1523    setTotalSteps (totalSteps);
    15271524
    15281525    if (class LCD * lcddev = LCD::Get())
    15291526    {
     
    15881585        MythDialog::keyPressEvent(e);
    15891586}
    15901587
     1588void MythProgressDialog::setTotalSteps (int totalSteps) {
     1589    m_totalSteps = totalSteps;
     1590    steps = totalSteps / 1000;
     1591    if (steps == 0)
     1592        steps = 1;
     1593}
     1594
     1595MythBusyDialog::MythBusyDialog (const QString &title) :
     1596    MythProgressDialog (title, 0),
     1597    timer (NULL)
     1598{
     1599}
     1600
     1601MythBusyDialog::~MythBusyDialog () {
     1602    if (timer)
     1603        delete timer;
     1604}
     1605
     1606void
     1607MythBusyDialog::start (int interval) {
     1608    if (timer == NULL) {
     1609        timer = new QTimer (this);
     1610    }
     1611    connect (timer, SIGNAL (timeout ()), SLOT (timeout ()));
     1612    timer->start (interval);
     1613}
     1614
     1615void
     1616MythBusyDialog::Close () {
     1617    if (timer) {
     1618        disconnect (timer, SIGNAL (timeout ()), this, SLOT (timeout ()));
     1619        delete timer;
     1620        timer = 0;
     1621    }
     1622
     1623    MythProgressDialog::Close ();
     1624}
     1625
     1626void
     1627MythBusyDialog::setProgress ()  {
     1628    progress->setProgress (progress->progress () + 10);
     1629    qApp->processEvents ();
     1630    if (LCD *lcddev = LCD::Get())
     1631        lcddev->setGenericBusy ();
     1632}
     1633
     1634void
     1635MythBusyDialog::timeout ()  {
     1636    setProgress ();
     1637}
     1638
    15911639MythThemedDialog::MythThemedDialog(MythMainWindow *parent, QString window_name,
    15921640                                   QString theme_filename, const char* name,
    15931641                                   bool setsize)
  • mythtv/libs/libmyth/lcddevice.h

     
    147147    // define the screen, row, and alignment of the text
    148148    void switchToGeneric(QPtrList<LCDTextItem> *textItems);
    149149
    150     // Do a progress bar with the generic level between 0 and 1.0
     150    /** Update the generic progress bar.
     151        \param generic_progress a value between 0 and 1.0
     152    */
    151153    void setGenericProgress(float generic_progress);
    152154
     155    /** Update the generic screen to display a busy spinner.
     156
     157                \note The LCD busy spinner only 'moves' when this is called
     158                instead of the lcdserver just handling it itself.
     159    */
     160    void setGenericBusy();
     161
    153162    // Do a music progress bar with the generic level between 0 and 1.0
    154163    void setMusicProgress(QString time, float generic_progress);
    155164
  • mythtv/libs/libmyth/mythdialogs.h

     
    1111#include <qevent.h>
    1212#include <qvaluevector.h>
    1313#include <qscrollview.h>
     14#include <qthread.h>
    1415
    1516#include <vector>
    1617using namespace std;
     
    229230    bool arrowAccel;
    230231};
    231232
     233/** The MythTV progress bar dialog.
     234
     235    This dialog is responsible for displaying a progress bar box on
     236    the screen. This is used when you have a known set of steps to
     237    perform and the possibility of calling the \p setProgress call at
     238    the end of each step.
     239
     240        If you do not know the number of steps, use \p MythBusyDialog
     241        instead.
     242
     243    The dialog widget also updates the LCD display if present.
     244
     245*/
    232246class MythProgressDialog: public MythDialog
    233247{
    234248  public:
     249    /** Create a progress bar dialog.
     250       
     251        \param message the title string to appear in the progress dialog.
     252        \param totalSteps the total number of steps
     253     */
    235254    MythProgressDialog(const QString& message, int totalSteps);
    236255
     256        /* \brief Close the dialog.
     257           This will close the dialog and return the LCD to the Time screen
     258        */
    237259    void Close(void);
     260        /* \brief Update thr progress bar. 
     261
     262            This will move the progress bar the percentage-completed as
     263            determined by \p curprogress and the totalsteps as set by the
     264            call to the constructor.
     265
     266                The LCD is updated as well.
     267         */
    238268    void setProgress(int curprogress);
     269
    239270    void keyPressEvent(QKeyEvent *);
    240271
     272  protected:
     273    QProgressBar *progress;
     274
    241275  private:
    242     QProgressBar *progress;
     276        void setTotalSteps (int totalSteps);   
    243277    int steps;
    244 
     278    int m_totalSteps;
    245279    QPtrList<class LCDTextItem> * textItems;
     280};
    246281
    247     int m_totalSteps;
     282/** MythDialog box that displays a busy spinner-style dialog box to
     283    indicate the program is busy, but that the number of steps needed
     284    is unknown.
     285
     286        Ie. used by MythMusic when scanning the filesystem for musicfiles.
     287 */
     288class MythBusyDialog : public MythProgressDialog {
     289    Q_OBJECT
     290  public:
     291    /** \brief Create the busy indicator. 
     292
     293            Creates the dialog widget and sets up the timer that causes
     294            the widget to indicate progress every 100msec;
     295
     296        \param title the title to appear in the progress bar dialog
     297    */
     298    MythBusyDialog (const QString &title);
     299
     300    ~MythBusyDialog ();
     301
     302        /** \brief Setup a timer to 'move' the spinner
     303
     304                This will create a \p QTimer object that will update the
     305                spinner ever \p interval msecs.
     306
     307                \param interval msecs between movement, default is 100
     308        */
     309        void start (int interval = 100);
     310
     311    /** \brief Close the dialog.
     312        This will close the dialog and stop the timer.         
     313     */
     314    void Close ();
     315
     316  protected slots:
     317        void setProgress();
     318        void timeout ();
     319
     320  private:
     321        QTimer *timer;
    248322};
    249323
    250324class MythThemedDialog : public MythDialog
    251325{
    252     Q_OBJECT
    253   public:
     326    Q_OBJECT 
     327 public:
    254328    MythThemedDialog(MythMainWindow *parent, QString window_name,
    255329                     QString theme_filename = "", const char *name = 0,
    256330                     bool setsize = true);
  • mythtv/programs/mythlcdserver/lcdprocclient.cpp

     
    959959void LCDProcClient::startMusic(QString artist, QString album, QString track)
    960960{
    961961    QString aString;
     962    music_progress = 0.0;
    962963    if (lcd_showmusic)
    963964      setPriority("Music", HIGH);
    964965    aString = artist;
     
    10161017    QString aString;
    10171018
    10181019    if (lcd_showgeneric)
    1019       setPriority("Generic", HIGH);
     1020      setPriority("Generic", TOP);
    10201021
    10211022    // Clear out the LCD.  Do this before checking if its empty incase the user
    10221023    //  wants to just clear the lcd
     
    10291030        return;
    10301031
    10311032    activeScreen = "Generic";
     1033
     1034    busy_progress = false;
     1035    busy_pos = 1;
     1036    busy_direction = 1;
     1037    busy_indicator_size = 2.0;
    10321038    generic_progress = 0.0;
    10331039
    10341040    // Return if there are no more items
     
    15051511    outputChannel();   
    15061512}
    15071513
    1508 void LCDProcClient::setGenericProgress(float value)
     1514void LCDProcClient::setGenericProgress(bool b, float value)
    15091515{
    15101516    if (!lcd_ready)
    15111517        return;
     
    15171523    else if (generic_progress > 1.0)
    15181524        generic_progress = 1.0;
    15191525
     1526    // Note, this will let us switch to/from busy indicator by alternating between
     1527    // being passed true or false for b.
     1528    busy_progress = b;
     1529    if (busy_progress) {
     1530        // If we're at either end of the line, switch direction
     1531        if (busy_pos + busy_direction > (signed int)lcdWidth - busy_indicator_size ||
     1532            busy_pos + busy_direction < 1) {
     1533            busy_direction = -busy_direction;
     1534        }
     1535        busy_pos += busy_direction;
     1536        generic_progress = busy_indicator_size / (float)lcdWidth;
     1537    } else {
     1538        busy_pos = 1;
     1539    }
     1540
    15201541    outputGeneric();
    15211542}
    15221543
     
    17941815void LCDProcClient::outputGeneric()
    17951816{
    17961817    QString aString;
    1797     aString = "widget_set Generic progressBar 1 ";
     1818    aString = "widget_set Generic progressBar ";
     1819    aString += QString::number (busy_pos);
     1820    aString += " ";
    17981821    aString += QString::number(lcdHeight);
    17991822    aString += " ";
    18001823    aString += QString::number((int)rint(generic_progress * lcdWidth *
     
    20032026                                  "- is the master server running?\n\t\t\t"
    20042027                                  "Will retry in 30 seconds");
    20052028            QTimer::singleShot(30 * 1000, this, SLOT(updateRecordingList()));
    2006             switchToTime();
     2029
     2030            // If we can't get the recording status and we're showing
     2031            // it, switch back to time. Maybe it would be even better
     2032            // to show that the backend is unreachable ?
     2033            if  (activeScreen == "RecStatus")
     2034                switchToTime();
    20072035            return;
    20082036        }   
    20092037    }
  • mythtv/programs/mythlcdserver/lcdserver.cpp

     
    3939        time is a string
    4040        progress is a float between 0.0 and 1.0
    4141
    42     SET_GENERIC_PROGRESS <progress>
     42    SET_GENERIC_PROGRESS <busy> <progress>
     43        busy is 0 for busy spinner, 0 for normal progess bar
    4344        progress is a float between 0.0 and 1.0
    4445   
    4546    UPDATE_LEDS
     
    577578
    578579    QString flat = tokens.join(" ");
    579580   
    580     if (tokens.count() != 2)
     581    if (tokens.count() != 3)
    581582    {
    582583        VERBOSE(VB_IMPORTANT, "LCDServer: bad SET_GENERIC_PROGRESS command: "
    583584                << flat);
     
    586587    }
    587588     
    588589    bool bOK;
    589     float progress = tokens[1].toFloat(&bOK);
     590    bool busy = tokens[1].toInt (&bOK);
    590591    if (!bOK)
    591592    {
     593        VERBOSE(VB_IMPORTANT, "LCDServer: bad bool value in "
     594                "SET_GENERIC_PROGRESS command: %1 %2" << tokens[1] << tokens[2]);
     595        sendMessage(socket, "HUH?");
     596        return;
     597    }
     598    float progress = tokens[2].toFloat(&bOK);
     599    if (!bOK)
     600    {
    592601        VERBOSE(VB_IMPORTANT, "LCDServer: bad float value in "
    593602                "SET_GENERIC_PROGRESS command: %1" << tokens[1]);
    594603        sendMessage(socket, "HUH?");
     
    596605    }
    597606   
    598607    if (m_lcd)
    599         m_lcd->setGenericProgress(progress);
     608        m_lcd->setGenericProgress(busy, progress);
    600609       
    601610    sendMessage(socket, "OK");
    602611}
  • mythtv/programs/mythlcdserver/lcdprocclient.h

     
    4949                      bool popMenu = true);
    5050   
    5151    void switchToGeneric(QPtrList<LCDTextItem> *textItems);
    52     void setGenericProgress(float generic_progress);
     52    void setGenericProgress(bool busy, float generic_progress);
    5353
    5454    void switchToVolume(QString app_name);
    5555    void setVolumeLevel(float volume_level);
     
    162162       
    163163    float EQlevels[10];
    164164    float progress;
     165    /** TRUE if the generic progress indicator is a busy (ie. doesn't have a known total steps */
     166    bool busy_progress;
     167    /** Current position of the busy indicator, used if @p busy_progress is true. */
     168    int busy_pos;
     169    /** How many "blocks" the busy indicator must be, used if @p busy_progress is true. */
     170    float busy_indicator_size;
     171    /** Dicrection of the busy indicator on the, -1 or 1, used if @p busy_progress is true. */
     172    int busy_direction;
    165173    float generic_progress;
    166174    float volume_level;
    167175
  • mythplugins/mythmusic/mythmusic/decoder.h

     
    88#include <qptrlist.h>
    99
    1010class Metadata;
     11class MetaIO;
    1112class Decoder;
    1213class DecoderFactory;
    1314
     
    7980    static Decoder *create(const QString &, QIODevice *, AudioOutput *,
    8081                           bool = FALSE);
    8182
    82     virtual Metadata *getMetadata() = 0;
    83     virtual void commitMetadata(Metadata *mdata) = 0;
     83    /** \brief Read the metadata from \p filename directly.
     84       
     85        Creates a \p MetaIO object using \p Decoder::doCreateTagger and uses
     86        the MetaIO object to read the metadata.
     87       
     88        \returns an instance of \p Metadata owned by the caller
     89     */
     90    virtual Metadata *readMetadata();
    8491
     92    /** \brief Get the metadata  for \p filename
     93       
     94        Tries first to read the metadata from the database. If there
     95        is no database entry, it'll call \p Decoder::readMetadata
     96
     97                @returns an instance of \p Metadata owned by the caller
     98    */
     99    virtual Metadata *getMetadata();
     100
     101    /** \brife Create a \p MetaIO object for the format.
     102
     103        This method should be overwritten by subclasses to return an
     104        instance of the appropriate MetaIO subtype. It is used by \p
     105        Decoder::getMetadata, \p Decoder::readMetadata and \p
     106        Decoder::commitMetadata.
     107       
     108        The default implementation returns a NULL pointer, which
     109        essentially means, that if the decoder does not overrider this
     110        method or all of the users (see previous paragraph), files
     111        that the decoder supports cannot be indexed using metadata in
     112        the file.
     113
     114                Eg. the mp3 decoder (\p MadDecoder) implements this, whereas
     115                the audio CD decoder (\p CdDecoder) does not.
     116
     117                \returns an instance of \p MetaIO owned by the caller
     118     */
     119    virtual MetaIO *doCreateTagger ();
     120
     121    /** \brief Write the given metadata to the \p filename.
     122       
     123        Creates a \p MetaIO object using \p Decoder::createTagger and
     124        asks the MetaIO object to write the contents of mdata to \p
     125        filename.
     126
     127        @\arams mdata the metadata to write to the disk
     128     */
     129    virtual void commitMetadata(Metadata *mdata);
     130
    85131    static void SetLocationFormatUseTags(void);
    86132
    87133    QString getFilename(void) { return filename; }
  • mythplugins/mythmusic/mythmusic/aacdecoder.cpp

     
    614614    deinit();
    615615}
    616616
    617 Metadata* aacDecoder::getMetadata()
     617MetaIO* aacDecoder::doCreateTagger()
    618618{
    619 
    620     Metadata *mdata = new Metadata(filename);
    621     if (mdata->isInDatabase(musiclocation))
    622     {
    623       return mdata;
    624     }
    625    
    626     delete mdata;
    627 
    628     MetaIOMP4* p_tagger = new MetaIOMP4;
    629     if (ignore_id3) {
    630         mdata = p_tagger->readFromFilename(filename);
    631     } else {
    632         mdata = p_tagger->read(filename);
    633     }
    634    
    635     delete p_tagger;
    636 
    637     if (mdata)
    638         mdata->dumpToDatabase(musiclocation);
    639     else
    640       error(QString("aacdecoder.o: Could not read metadata from \"%1\"").arg(filename.local8Bit()));
    641 
    642     return mdata;
    643 }   
    644 
    645 void aacDecoder::commitMetadata(Metadata *mdata)
    646 {
    647     MetaIOMP4* p_tagger = new MetaIOMP4;
    648     p_tagger->write(mdata);
    649     delete p_tagger;
     619    return new MetaIOMP4;
    650620}
    651621
    652622uint32_t aacDecoder::aacRead(char *buffer, uint32_t length)
  • mythplugins/mythmusic/mythmusic/metadata.cpp

     
    11#include <iostream>
     2#include <qapplication.h>
    23#include <qregexp.h>
    34#include <qdatetime.h>
    45#include <qdir.h>
     
    148149        playcount = query.value(10).toInt();
    149150        lastplay = query.value(11).toString();
    150151        compilation = (query.value(12).toInt() > 0);
    151        
     152
    152153        retval = true;
    153154    }
    154155
     
    194195        return;
    195196
    196197    query.prepare("INSERT INTO musicmetadata (artist,compilation_artist,album,title,"
    197                   "genre,year,tracknum,length,filename,compilation,date_added) VALUES "
     198                  "genre,year,tracknum,length,filename,compilation,date_added,"
     199                  "date_modified) VALUES "
    198200                  "(:ARTIST, :COMPILATION_ARTIST, :ALBUM, :TITLE, :GENRE, :YEAR, :TRACKNUM, "
    199                   ":LENGTH, :FILENAME, :COMPILATION, :DATE_ADDED );");
     201                  ":LENGTH, :FILENAME, :COMPILATION, :DATE_ADDED, :DATE_MODIFIED );");
    200202    query.bindValue(":ARTIST", artist.utf8());
    201203    query.bindValue(":COMPILATION_ARTIST", compilation_artist.utf8());
    202204    query.bindValue(":ALBUM", album.utf8());
     
    207209    query.bindValue(":LENGTH", length);
    208210    query.bindValue(":FILENAME", sqlfilename.utf8());
    209211    query.bindValue(":COMPILATION", compilation);
    210     query.bindValue(":DATE_ADDED", QDate::currentDate());
     212    query.bindValue(":DATE_ADDED", QDateTime::currentDateTime());
     213    query.bindValue(":DATE_MODIFIED", QDateTime::currentDateTime());
    211214   
    212215    query.exec();
    213216
     
    364367                  "compilation_artist = :COMPILATION_ARTIST, "
    365368                  "title = :TITLE, genre = :GENRE, year = :YEAR, "
    366369                  "tracknum = :TRACKNUM, rating = :RATING, "
    367                   "compilation = :COMPILATION "
     370                  "compilation = :COMPILATION, "
     371                  "date_modified= :DATE_MODIFIED "
    368372                  "WHERE intid = :ID;");
    369373    query.bindValue(":ARTIST", artist.utf8());
    370374    query.bindValue(":COMPILATION_ARTIST", compilation_artist.utf8());
     
    375379    query.bindValue(":TRACKNUM", tracknum);
    376380    query.bindValue(":RATING", rating);
    377381    query.bindValue(":COMPILATION", compilation);
     382    query.bindValue(":DATE_MODIFIED", QDateTime::currentDateTime());
    378383    query.bindValue(":ID", id);
    379384
    380385    if (!query.exec())
     
    660665void MetadataLoadingThread::run()
    661666{
    662667    //if you want to simulate a big music collection load
    663     //sleep(3);
     668    //sleep (10);
    664669    parent->resync();
    665670}
    666671
     
    683688    //  loading and sorting
    684689    //
    685690   
    686     metadata_loader = new MetadataLoadingThread(this);
    687     metadata_loader->start();
     691    metadata_loader = NULL;
     692    startLoading ();
    688693
    689694    all_music.setAutoDelete(true);
    690695    top_nodes.setAutoDelete(true);
     
    718723    return false;
    719724}
    720725
     726bool AllMusic::startLoading () {
     727    // Set this to false early rather than letting it be delayed till
     728    // the thread calls resync.
     729    done_loading = false;
     730
     731    if (metadata_loader) {
     732        cleanOutThreads ();
     733        delete metadata_loader;
     734    }
     735
     736    metadata_loader = new MetadataLoadingThread(this);
     737    metadata_loader->start ();   
     738   
     739    return true;
     740}
     741
    721742void AllMusic::resync()
    722743{
    723744    done_loading = false;
     
    736757    query.exec(aquery);
    737758
    738759    all_music.clear();
    739    
     760
     761    /* Create the medata objects */
    740762    if (query.isActive() && query.size() > 0)
    741763    {
    742764        while (query.next())
     
    11931215        if( *it != "genre"  &&
    11941216            *it != "artist" &&
    11951217            *it != "splitartist" &&
     1218            *it != "splitartist1" &&
    11961219            *it != "album"  &&
    11971220            *it != "title")
    11981221        {
     
    15021525        ++iter;
    15031526    }
    15041527}
    1505 
  • mythplugins/mythmusic/mythmusic/decoder.cpp

     
    66
    77#include "decoder.h"
    88#include "constants.h"
     9#include "metadata.h"
     10#include "metaio.h"
    911#include <mythtv/output.h>
    1012#include <mythtv/visual.h>
    1113
     
    8789    listeners.remove(object);
    8890}
    8991
     92Metadata *Decoder::readMetadata () {
     93    Metadata *mdata = NULL;
     94    MetaIO* p_tagger = doCreateTagger ();
    9095
     96    if (p_tagger) {
     97        if (ignore_id3)
     98            mdata = p_tagger->readFromFilename(filename);
     99        else
     100            mdata = p_tagger->read(filename);
     101       
     102        delete p_tagger;
     103    } else {
     104        if (!mdata)
     105            cerr << "maddecoder.o: Could not read metadata from " << filename.local8Bit() << endl;
     106    }
     107
     108    return mdata;   
     109}
     110
     111Metadata* Decoder::getMetadata()
     112{
     113
     114    Metadata *mdata = new Metadata(filename);
     115    if (mdata->isInDatabase(musiclocation))
     116    {
     117      return mdata;
     118    }
     119   
     120    delete mdata;
     121
     122    return readMetadata ();
     123}   
     124
     125void Decoder::commitMetadata(Metadata *mdata)
     126{
     127    MetaIO* p_tagger = doCreateTagger ();
     128    if (p_tagger) {
     129        p_tagger->write(mdata);
     130        delete p_tagger;
     131    }
     132}
     133
     134MetaIO *Decoder::doCreateTagger () {
     135    return NULL;
     136}
     137
    91138// static methods
    92139
    93140int Decoder::ignore_id3 = 0;
  • mythplugins/mythmusic/mythmusic/aacdecoder.h

     
    2929    void seek(double);
    3030    void stop();
    3131
    32     Metadata *getMetadata();
    33     void commitMetadata(Metadata *mdata);
     32    MetaIO *doCreateTagger();
    3433
    3534    bool     initializeMP4();
    3635    int      getAACTrack(mp4ff_t *infile);
  • mythplugins/mythmusic/mythmusic/metadata.h

     
    244244    Metadata*   getMetadata(int an_id);
    245245    bool        updateMetadata(int an_id, Metadata *the_track);
    246246    void        save();
     247        /** \brief Start loading metadata.
     248                Makes the AllMusic object run it's resync in a thread. Once done, it's
     249                doneLoading method will return true.
     250
     251                @note Alternatively, it could be made to emit a signal so the
     252                caller won't have to poll for completion.
     253
     254                \returns true if the loader thread was started
     255        */
     256        bool        startLoading ();
    247257    void        resync();   //  After a CD rip, for example
    248258    void        clearCDData();
    249259    void        addCDTrack(Metadata *the_track);
     
    264274    bool        cleanOutThreads();
    265275    int         getCDTrackCount(){return cd_data.count();}
    266276    void        resetListings(){last_listed = -1;}
    267    
    268277  private:
    269278 
    270279    QPtrList<Metadata>  all_music;
  • mythplugins/mythmusic/mythmusic/vorbisdecoder.cpp

     
    293293    deinit();
    294294}
    295295
    296 Metadata *VorbisDecoder::getMetadata()
     296MetaIO *VorbisDecoder::doCreateTagger()
    297297{
    298     Metadata *mdata = new Metadata(filename);
    299     if (mdata->isInDatabase(musiclocation))
    300     {
    301         return mdata;
    302     }
    303 
    304     delete mdata;
    305 
    306 
    307     MetaIOOggVorbisComment* p_tagger = new MetaIOOggVorbisComment;
    308     if (ignore_id3)
    309         mdata = p_tagger->readFromFilename(filename);
    310     else
    311         mdata = p_tagger->read(filename);
    312 
    313     delete p_tagger;
    314 
    315     if (mdata)
    316         mdata->dumpToDatabase(musiclocation);
    317     else
    318         cerr << "vorbisdecoder.o: Could not read metadata from " << filename.local8Bit() << endl;   
    319 
    320     return mdata;
    321 }   
    322 
    323 void VorbisDecoder::commitMetadata(Metadata *mdata)
    324 {
    325     MetaIOOggVorbisComment* p_tagger = new MetaIOOggVorbisComment;
    326     p_tagger->write(mdata);
    327     delete p_tagger;
     298    return new MetaIOOggVorbisComment;
    328299}
    329300
    330301
  • mythplugins/mythmusic/mythmusic/flacdecoder.h

     
    2222    void doWrite(const FLAC__Frame *frame, const FLAC__int32 * const buffer[]);
    2323    void setFlacMetadata(const FLAC__StreamMetadata *metadata);
    2424
    25     Metadata *getMetadata();
    26     void commitMetadata(Metadata *mdata);
     25    MetaIO *doCreateTagger();
    2726
    2827  private:
    2928    void run();
  • mythplugins/mythmusic/mythmusic/avfdecoder.cpp

     
    357357    deinit();
    358358}
    359359
    360 Metadata* avfDecoder::getMetadata()
     360MetaIO* avfDecoder::doCreateTagger()
    361361{
    362     Metadata *mdata = new Metadata(filename);
    363     if (mdata->isInDatabase(musiclocation))
    364     {
    365         return mdata;
    366     }
    367 
    368     delete mdata;
    369 
    370 
    371     MetaIOAVFComment* p_tagger = new MetaIOAVFComment;
    372     if (ignore_id3)
    373         mdata = p_tagger->readFromFilename(filename);
    374     else
    375         mdata = p_tagger->read(filename);
    376    
    377     delete p_tagger;
    378 
    379     if (mdata)
    380         mdata->dumpToDatabase(musiclocation);
    381     else
    382         cerr << "avfdecoder.o: Could not read metadata from " << filename << endl;
    383 
    384     return mdata;
     362    return new MetaIOAVFComment;
    385363}   
    386364
    387 void avfDecoder::commitMetadata(Metadata *mdata)
    388 {
    389     MetaIOAVFComment* p_tagger = new MetaIOAVFComment;
    390     p_tagger->write(mdata);
    391     delete p_tagger;
    392 }
    393 
    394365bool avfDecoderFactory::supports(const QString &source) const
    395366{
    396367    return (source.right(extension().length()).lower() == extension());
  • mythplugins/mythmusic/mythmusic/main.cpp

     
    66#include <qapplication.h>
    77#include <qsqldatabase.h>
    88#include <qregexp.h>
     9#include <sys/types.h>
     10#include <sys/stat.h>
    911#include <unistd.h>
    1012
    1113#include <cdaudio.h>
     
    6567    return decoder;
    6668}
    6769
    68 void CheckFile(const QString &filename)
     70// Add a file to the database
     71void AddFileToDB(const QString &directory, const QString &filename)
    6972{
    7073    Decoder *decoder = getDecoder(filename);
    7174
    7275    if (decoder)
    7376    {
    7477        Metadata *data = decoder->getMetadata();
    75         if (data)
     78        if (data)
     79        {
     80            data->dumpToDatabase(directory);
    7681            delete data;
     82        }
     83        delete decoder;
     84    }
     85}
    7786
     87// Remove a file from the database
     88void RemoveFileFromDB (const QString &directory, const QString &filename)
     89{
     90    QString name(filename);
     91    name.remove(0, directory.length());
     92    MSqlQuery query(MSqlQuery::InitCon());
     93    query.prepare("DELETE FROM musicmetadata WHERE "
     94                  "filename = :NAME ;");
     95    query.bindValue(":NAME", name.utf8());
     96    query.exec();
     97}
     98
     99// Update a file's metadata in the database, preserving it's id
     100void UpdateFileInDB (const QString &directory, const QString &filename)
     101{
     102    Decoder *decoder = getDecoder (filename);
     103
     104    if (decoder)
     105    {
     106        Metadata *db_meta = decoder->getMetadata ();
     107        Metadata *disk_meta = decoder->readMetadata ();
     108
     109        if (db_meta && disk_meta)
     110        {
     111            disk_meta->setID (db_meta->ID ());
     112            disk_meta->updateDatabase (directory);
     113        }
     114
     115        if (disk_meta)
     116            delete disk_meta;
     117
     118        if (db_meta)
     119            delete db_meta;
     120
    78121        delete decoder;
    79122    }
    80123}
     
    83126{
    84127    kFileSystem,
    85128    kDatabase,
    86     kBoth
     129    kNeedUpdate,
    87130};
    88131
    89132typedef QMap <QString, MusicFileLocation> MusicLoadedMap;
     
    102145    QFileInfoListIterator it(*list);
    103146    QFileInfo *fi;
    104147
     148    /* Recursively traverse directory, calling
     149       QApplication::processEvents every now and then to ensure the UI
     150       updates */
     151    int update_int = 0;
    105152    while ((fi = it.current()) != 0)
    106153    {
    107154        ++it;
    108155        if (fi->fileName() == "." || fi->fileName() == "..")
    109156            continue;
    110157        QString filename = fi->absFilePath();
    111         if (fi->isDir())
     158        if (fi->isDir()) {
     159            qApp->processEvents ();
    112160            BuildFileList(filename, music_files);
    113         else
    114             music_files[filename] = kFileSystem;
     161        } else {
     162            // ensure UI updates for dirs with many many files
     163            if (++update_int > 100) {
     164                qApp->processEvents ();
     165                update_int = 0;
     166            }
     167            music_files[filename] = kFileSystem;           
     168        }
    115169    }
    116170}
    117171
     172/* Check if the file's mdate is after the date_modified */
     173bool HasFileChanged (const QString &filename, const QString &date_modified)
     174{
     175    struct stat sbuf;
     176    if (stat (filename.ascii (), &sbuf) == 0) {
     177        if (sbuf.st_mtime > (time_t)QDateTime::fromString (date_modified, Qt::ISODate).toTime_t ()) {
     178            return true;
     179        }
     180    }
     181    return false;
     182}
     183
    118184void SavePending(int pending)
    119185{
    120186    //  Temporary Hack until mythmusic
     
    176242{
    177243    MusicLoadedMap music_files;
    178244    MusicLoadedMap::Iterator iter;
     245   
     246    {
     247        /* Let the user know we're doing something, since ie. building
     248           the filelist over NFS can take quite a while, so progress
     249           bar now...
     250        */
     251        MythBusyDialog busy (QObject::tr("Searching for music files"));
     252        busy.start ();
     253        BuildFileList(directory, music_files);
     254        busy.Close ();
     255    }
    179256
    180     BuildFileList(directory, music_files);
    181 
    182257    MSqlQuery query(MSqlQuery::InitCon());
    183     query.exec("SELECT filename FROM musicmetadata "
     258    query.exec("SELECT filename, date_modified FROM musicmetadata "
    184259                    "WHERE filename NOT LIKE ('%://%');");
    185260
     261    MythProgressDialog *progress;
     262    progress = new MythProgressDialog(QObject::tr("Scanning music files"),
     263                                      query.numRowsAffected());
     264
    186265    int counter = 0;
    187266
    188     MythProgressDialog *file_checking;
    189     file_checking = new MythProgressDialog(QObject::tr("Searching for music files"),
    190                                            query.numRowsAffected());
    191 
    192267    if (query.isActive() && query.size() > 0)
    193268    {
    194269        while (query.next())
     
    196271            QString name = directory + QString::fromUtf8(query.value(0).toString());
    197272            if (name != QString::null)
    198273            {
    199                 if ((iter = music_files.find(name)) != music_files.end())
    200                     music_files.remove(iter);
    201                 else
     274                if ((iter = music_files.find(name)) != music_files.end()) {
     275                    if (HasFileChanged (name, query.value (1).toString ())) {
     276                        music_files[name] = kNeedUpdate;
     277                    } else {
     278                        music_files.remove(iter);
     279                    }
     280                } else {
    202281                    music_files[name] = kDatabase;
     282                }
    203283            }
    204             file_checking->setProgress(++counter);
     284            progress->setProgress(++counter);
    205285        }
    206286    }
    207287
    208     file_checking->Close();
    209     delete file_checking;
     288    progress->Close();
     289    delete progress;
    210290
    211     file_checking = new MythProgressDialog(QObject::tr("Updating music database"),
     291    counter = 0;
     292    progress = new MythProgressDialog(QObject::tr("Updating music database"),
    212293                                           music_files.size());
    213294
     295    // This can be optimised quite a bit by consolidating all commands
     296    // via a lot of refactoring.
     297
     298    // 1) group all files of the same decoder type, and don't
     299    // create/delete a Decoder pr. AddFileToDB. Maybe make Decoders be
     300    // singletons ?
     301
     302    // 2) RemoveFileFromDB should group the remove into one big SQL.
     303
     304    // 3) UpdateFileInDB, see 1).
     305
    214306    QRegExp quote_regex("\"");
    215307    for (iter = music_files.begin(); iter != music_files.end(); iter++)
    216308    {
    217         if (*iter == kFileSystem)
    218         {
    219             CheckFile(iter.key());
     309        switch (*iter) {
     310        case kFileSystem:
     311            AddFileToDB(directory, iter.key());
     312            break;
     313        case kDatabase:
     314            RemoveFileFromDB (directory, iter.key());
     315            break;
     316        case kNeedUpdate:
     317            UpdateFileInDB (directory, iter.key ());
     318            break;
    220319        }
    221         else if (*iter == kDatabase)
    222         {
    223             QString name(iter.key());
    224             name.remove(0, directory.length());
    225 
    226             query.prepare("DELETE FROM musicmetadata WHERE "
    227                           "filename = :NAME ;");
    228             query.bindValue(":NAME", name.utf8());
    229             query.exec();
    230         }
    231 
    232         file_checking->setProgress(++counter);
     320        progress->setProgress(++counter);
    233321    }
    234     file_checking->Close();
    235     delete file_checking;
     322    progress->Close();
     323    delete progress;
    236324}
    237325
    238326void startPlayback(PlaylistsContainer *all_playlists, AllMusic *all_music)
     
    283371    AllMusic *all_music;
    284372};
    285373
     374void RebuildMusicTree (MusicData *mdata) {
     375    MythBusyDialog busy (QObject::tr("Rebuilding music tree"));           
     376    busy.start ();
     377    mdata->all_music->startLoading ();
     378    while (!mdata->all_music->doneLoading ()) {               
     379        qApp->processEvents ();
     380        usleep (50000);
     381    }
     382    mdata->all_playlists->postLoad();
     383    busy.Close ();
     384}
     385
    286386void MusicCallback(void *data, QString &selection)
    287387{
    288388    MusicData *mdata = (MusicData *)data;
     
    302402            //  Reconcile with the database
    303403            SearchDir(mdata->startdir);
    304404            //  Tell the metadata to reset itself
    305             mdata->all_music->resync();
    306             mdata->all_playlists->postLoad();
     405            RebuildMusicTree (mdata);
    307406        }
    308407    }
    309408    else if (sel == "settings_scan")
     
    311410        if ("" != mdata->startdir)
    312411        {
    313412            SearchDir(mdata->startdir);
    314             mdata->all_music->resync();
    315             mdata->all_playlists->postLoad();
     413            RebuildMusicTree (mdata);
    316414        }
    317415    }
    318416    else if (sel == "music_set_general")
     
    554652        // if startRipper returns true, then new files should be present
    555653        // so we should look for them.
    556654        SearchDir(mdata.startdir);
    557         mdata.all_music->resync();
    558         mdata.all_playlists->postLoad();
     655        RebuildMusicTree (&mdata);
    559656    }
    560657    postMusic(&mdata);
    561658}
  • mythplugins/mythmusic/mythmusic/flacdecoder.cpp

     
    385385        char *field_value;
    386386} Argument_VcField;
    387387
    388 Metadata *FlacDecoder::getMetadata()
     388MetaIO *FlacDecoder::doCreateTagger()
    389389{
    390     Metadata *mdata = new Metadata(filename);
    391     if (mdata->isInDatabase(musiclocation))
    392     {
    393         return mdata;
    394     }
     390    return new MetaIOFLACVorbisComment;
     391}
    395392
    396     delete mdata;
    397393
    398     MetaIOFLACVorbisComment* p_tagger = new MetaIOFLACVorbisComment;
    399     if (ignore_id3)
    400         mdata = p_tagger->readFromFilename(filename);
    401     else
    402         mdata = p_tagger->read(filename);
    403 
    404     delete p_tagger;
    405 
    406     if (mdata)
    407         mdata->dumpToDatabase(musiclocation);
    408     else
    409         cerr << "flacdecoder.o: Could not read metadata from " << filename.local8Bit() << endl;
    410 
    411     return mdata;
    412 }   
    413 
    414 void FlacDecoder::commitMetadata(Metadata *mdata)
    415 {
    416     MetaIOFLACVorbisComment* p_tagger = new MetaIOFLACVorbisComment;
    417     p_tagger->write(mdata);
    418     delete p_tagger;
    419     }
    420 
    421 
    422394bool FlacDecoderFactory::supports(const QString &source) const
    423395{
    424396    return (source.right(extension().length()).lower() == extension());
  • mythplugins/mythmusic/mythmusic/maddecoder.h

     
    2424    static const int maxFrameCheck;
    2525    static const int initialFrameSize;
    2626
    27     Metadata *getMetadata();
    28     void commitMetadata(Metadata *mdata);
     27    MetaIO *doCreateTagger();
    2928
    3029private:
    3130    void run();
  • mythplugins/mythmusic/mythmusic/vorbisdecoder.h

     
    1818    void seek(double);
    1919    void stop();
    2020
    21     Metadata *getMetadata();
    22     void commitMetadata(Metadata *mdata);
     21    MetaIO *doCreateTagger();
    2322
    2423  private:
    2524    void run();
  • mythplugins/mythmusic/mythmusic/avfdecoder.h

     
    1818    void seek(double);
    1919    void stop();
    2020
    21     Metadata *getMetadata();
    22     void commitMetadata(Metadata *mdata);
     21    MetaIO *doCreateTagger();
    2322
    2423  private:
    2524    void run();
  • mythplugins/mythmusic/mythmusic/maddecoder.cpp

     
    512512    return MAD_FLOW_STOP;
    513513}
    514514
    515 Metadata *MadDecoder::getMetadata()
     515MetaIO *MadDecoder::doCreateTagger()
    516516{
    517     Metadata *mdata = new Metadata(filename);
    518     if (mdata->isInDatabase(musiclocation))
    519     {
    520         return mdata;
    521     }
    522 
    523     delete mdata;
    524 
    525 
    526     MetaIOID3v2* p_tagger = new MetaIOID3v2;
    527     if (ignore_id3)
    528         mdata = p_tagger->readFromFilename(filename);
    529     else
    530         mdata = p_tagger->read(filename);
    531 
    532     delete p_tagger;
    533 
    534     if (mdata)
    535         mdata->dumpToDatabase(musiclocation);
    536     else
    537         cerr << "maddecoder.o: Could not read metadata from " << filename.local8Bit() << endl;
    538 
    539     return mdata;
     517    return new MetaIOID3v2;
    540518}
    541519
    542 void MadDecoder::commitMetadata(Metadata *mdata)
    543 {
    544     MetaIOID3v2* p_tagger = new MetaIOID3v2;
    545     p_tagger->write(mdata);
    546     delete p_tagger;
    547 }
    548 
    549520bool MadDecoderFactory::supports(const QString &source) const
    550521{
    551522    bool res = false;