Ticket #341: dbupdate9.patch
File dbupdate9.patch, 38.4 KB (added by , 15 years ago) |
---|
-
mythtv/libs/libmyth/lcddevice.cpp
192 192 #endif 193 193 // Just stream the text out the socket 194 194 195 os << someText << "\n" ;195 os << someText << "\n" << flush; 196 196 } 197 197 else 198 198 { … … 387 387 else if (value > 1.0) 388 388 value = 1.0; 389 389 390 sendToServer("SET_GENERIC_PROGRESS " + QString().setNum(value)); 390 sendToServer("SET_GENERIC_PROGRESS " + QString().setNum (false) + 391 " " + QString().setNum(value)); 391 392 } 392 393 394 void LCD::setGenericBusy () 395 { 396 if (!lcd_ready || !lcd_showgeneric) 397 return; 398 399 sendToServer("SET_GENERIC_PROGRESS 1 0.0"); 400 } 401 393 402 void LCD::setMusicProgress(QString time, float value) 394 403 { 395 404 if (!lcd_ready || !lcd_showmusic) -
mythtv/libs/libmyth/mythdialogs.cpp
1520 1520 progress->setBackgroundOrigin(ParentOrigin); 1521 1521 progress->setProgress(0); 1522 1522 1523 m_totalSteps = totalSteps; 1524 steps = totalSteps / 1000; 1525 if (steps == 0) 1526 steps = 1; 1523 setTotalSteps (totalSteps); 1527 1524 1528 1525 if (class LCD * lcddev = LCD::Get()) 1529 1526 { … … 1588 1585 MythDialog::keyPressEvent(e); 1589 1586 } 1590 1587 1588 void MythProgressDialog::setTotalSteps (int totalSteps) { 1589 m_totalSteps = totalSteps; 1590 steps = totalSteps / 1000; 1591 if (steps == 0) 1592 steps = 1; 1593 } 1594 1595 MythBusyDialog::MythBusyDialog (const QString &title) : 1596 MythProgressDialog (title, 0), 1597 timer (NULL) 1598 { 1599 } 1600 1601 MythBusyDialog::~MythBusyDialog () { 1602 if (timer) 1603 delete timer; 1604 } 1605 1606 void 1607 MythBusyDialog::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 1615 void 1616 MythBusyDialog::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 1626 void 1627 MythBusyDialog::setProgress () { 1628 progress->setProgress (progress->progress () + 10); 1629 qApp->processEvents (); 1630 if (LCD *lcddev = LCD::Get()) 1631 lcddev->setGenericBusy (); 1632 } 1633 1634 void 1635 MythBusyDialog::timeout () { 1636 setProgress (); 1637 } 1638 1591 1639 MythThemedDialog::MythThemedDialog(MythMainWindow *parent, QString window_name, 1592 1640 QString theme_filename, const char* name, 1593 1641 bool setsize) -
mythtv/libs/libmyth/lcddevice.h
147 147 // define the screen, row, and alignment of the text 148 148 void switchToGeneric(QPtrList<LCDTextItem> *textItems); 149 149 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 */ 151 153 void setGenericProgress(float generic_progress); 152 154 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 153 162 // Do a music progress bar with the generic level between 0 and 1.0 154 163 void setMusicProgress(QString time, float generic_progress); 155 164 -
mythtv/libs/libmyth/mythdialogs.h
11 11 #include <qevent.h> 12 12 #include <qvaluevector.h> 13 13 #include <qscrollview.h> 14 #include <qthread.h> 14 15 15 16 #include <vector> 16 17 using namespace std; … … 229 230 bool arrowAccel; 230 231 }; 231 232 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 */ 232 246 class MythProgressDialog: public MythDialog 233 247 { 234 248 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 */ 235 254 MythProgressDialog(const QString& message, int totalSteps); 236 255 256 /* \brief Close the dialog. 257 This will close the dialog and return the LCD to the Time screen 258 */ 237 259 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 */ 238 268 void setProgress(int curprogress); 269 239 270 void keyPressEvent(QKeyEvent *); 240 271 272 protected: 273 QProgressBar *progress; 274 241 275 private: 242 QProgressBar *progress; 276 void setTotalSteps (int totalSteps); 243 277 int steps; 244 278 int m_totalSteps; 245 279 QPtrList<class LCDTextItem> * textItems; 280 }; 246 281 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 */ 288 class 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; 248 322 }; 249 323 250 324 class MythThemedDialog : public MythDialog 251 325 { 252 Q_OBJECT 253 326 Q_OBJECT 327 public: 254 328 MythThemedDialog(MythMainWindow *parent, QString window_name, 255 329 QString theme_filename = "", const char *name = 0, 256 330 bool setsize = true); -
mythtv/programs/mythlcdserver/lcdprocclient.cpp
959 959 void LCDProcClient::startMusic(QString artist, QString album, QString track) 960 960 { 961 961 QString aString; 962 music_progress = 0.0; 962 963 if (lcd_showmusic) 963 964 setPriority("Music", HIGH); 964 965 aString = artist; … … 1016 1017 QString aString; 1017 1018 1018 1019 if (lcd_showgeneric) 1019 setPriority("Generic", HIGH);1020 setPriority("Generic", TOP); 1020 1021 1021 1022 // Clear out the LCD. Do this before checking if its empty incase the user 1022 1023 // wants to just clear the lcd … … 1029 1030 return; 1030 1031 1031 1032 activeScreen = "Generic"; 1033 1034 busy_progress = false; 1035 busy_pos = 1; 1036 busy_direction = 1; 1037 busy_indicator_size = 2.0; 1032 1038 generic_progress = 0.0; 1033 1039 1034 1040 // Return if there are no more items … … 1505 1511 outputChannel(); 1506 1512 } 1507 1513 1508 void LCDProcClient::setGenericProgress( float value)1514 void LCDProcClient::setGenericProgress(bool b, float value) 1509 1515 { 1510 1516 if (!lcd_ready) 1511 1517 return; … … 1517 1523 else if (generic_progress > 1.0) 1518 1524 generic_progress = 1.0; 1519 1525 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 1520 1541 outputGeneric(); 1521 1542 } 1522 1543 … … 1794 1815 void LCDProcClient::outputGeneric() 1795 1816 { 1796 1817 QString aString; 1797 aString = "widget_set Generic progressBar 1 "; 1818 aString = "widget_set Generic progressBar "; 1819 aString += QString::number (busy_pos); 1820 aString += " "; 1798 1821 aString += QString::number(lcdHeight); 1799 1822 aString += " "; 1800 1823 aString += QString::number((int)rint(generic_progress * lcdWidth * … … 2003 2026 "- is the master server running?\n\t\t\t" 2004 2027 "Will retry in 30 seconds"); 2005 2028 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(); 2007 2035 return; 2008 2036 } 2009 2037 } -
mythtv/programs/mythlcdserver/lcdserver.cpp
39 39 time is a string 40 40 progress is a float between 0.0 and 1.0 41 41 42 SET_GENERIC_PROGRESS <progress> 42 SET_GENERIC_PROGRESS <busy> <progress> 43 busy is 0 for busy spinner, 0 for normal progess bar 43 44 progress is a float between 0.0 and 1.0 44 45 45 46 UPDATE_LEDS … … 577 578 578 579 QString flat = tokens.join(" "); 579 580 580 if (tokens.count() != 2)581 if (tokens.count() != 3) 581 582 { 582 583 VERBOSE(VB_IMPORTANT, "LCDServer: bad SET_GENERIC_PROGRESS command: " 583 584 << flat); … … 586 587 } 587 588 588 589 bool bOK; 589 float progress = tokens[1].toFloat(&bOK);590 bool busy = tokens[1].toInt (&bOK); 590 591 if (!bOK) 591 592 { 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 { 592 601 VERBOSE(VB_IMPORTANT, "LCDServer: bad float value in " 593 602 "SET_GENERIC_PROGRESS command: %1" << tokens[1]); 594 603 sendMessage(socket, "HUH?"); … … 596 605 } 597 606 598 607 if (m_lcd) 599 m_lcd->setGenericProgress( progress);608 m_lcd->setGenericProgress(busy, progress); 600 609 601 610 sendMessage(socket, "OK"); 602 611 } -
mythtv/programs/mythlcdserver/lcdprocclient.h
49 49 bool popMenu = true); 50 50 51 51 void switchToGeneric(QPtrList<LCDTextItem> *textItems); 52 void setGenericProgress( float generic_progress);52 void setGenericProgress(bool busy, float generic_progress); 53 53 54 54 void switchToVolume(QString app_name); 55 55 void setVolumeLevel(float volume_level); … … 162 162 163 163 float EQlevels[10]; 164 164 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; 165 173 float generic_progress; 166 174 float volume_level; 167 175 -
mythplugins/mythmusic/mythmusic/decoder.h
8 8 #include <qptrlist.h> 9 9 10 10 class Metadata; 11 class MetaIO; 11 12 class Decoder; 12 13 class DecoderFactory; 13 14 … … 79 80 static Decoder *create(const QString &, QIODevice *, AudioOutput *, 80 81 bool = FALSE); 81 82 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(); 84 91 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 85 131 static void SetLocationFormatUseTags(void); 86 132 87 133 QString getFilename(void) { return filename; } -
mythplugins/mythmusic/mythmusic/aacdecoder.cpp
614 614 deinit(); 615 615 } 616 616 617 Meta data* aacDecoder::getMetadata()617 MetaIO* aacDecoder::doCreateTagger() 618 618 { 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; 650 620 } 651 621 652 622 uint32_t aacDecoder::aacRead(char *buffer, uint32_t length) -
mythplugins/mythmusic/mythmusic/metadata.cpp
1 1 #include <iostream> 2 #include <qapplication.h> 2 3 #include <qregexp.h> 3 4 #include <qdatetime.h> 4 5 #include <qdir.h> … … 148 149 playcount = query.value(10).toInt(); 149 150 lastplay = query.value(11).toString(); 150 151 compilation = (query.value(12).toInt() > 0); 151 152 152 153 retval = true; 153 154 } 154 155 … … 194 195 return; 195 196 196 197 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 " 198 200 "(:ARTIST, :COMPILATION_ARTIST, :ALBUM, :TITLE, :GENRE, :YEAR, :TRACKNUM, " 199 ":LENGTH, :FILENAME, :COMPILATION, :DATE_ADDED );");201 ":LENGTH, :FILENAME, :COMPILATION, :DATE_ADDED, :DATE_MODIFIED );"); 200 202 query.bindValue(":ARTIST", artist.utf8()); 201 203 query.bindValue(":COMPILATION_ARTIST", compilation_artist.utf8()); 202 204 query.bindValue(":ALBUM", album.utf8()); … … 207 209 query.bindValue(":LENGTH", length); 208 210 query.bindValue(":FILENAME", sqlfilename.utf8()); 209 211 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()); 211 214 212 215 query.exec(); 213 216 … … 364 367 "compilation_artist = :COMPILATION_ARTIST, " 365 368 "title = :TITLE, genre = :GENRE, year = :YEAR, " 366 369 "tracknum = :TRACKNUM, rating = :RATING, " 367 "compilation = :COMPILATION " 370 "compilation = :COMPILATION, " 371 "date_modified= :DATE_MODIFIED " 368 372 "WHERE intid = :ID;"); 369 373 query.bindValue(":ARTIST", artist.utf8()); 370 374 query.bindValue(":COMPILATION_ARTIST", compilation_artist.utf8()); … … 375 379 query.bindValue(":TRACKNUM", tracknum); 376 380 query.bindValue(":RATING", rating); 377 381 query.bindValue(":COMPILATION", compilation); 382 query.bindValue(":DATE_MODIFIED", QDateTime::currentDateTime()); 378 383 query.bindValue(":ID", id); 379 384 380 385 if (!query.exec()) … … 660 665 void MetadataLoadingThread::run() 661 666 { 662 667 //if you want to simulate a big music collection load 663 //sleep (3);668 //sleep (10); 664 669 parent->resync(); 665 670 } 666 671 … … 683 688 // loading and sorting 684 689 // 685 690 686 metadata_loader = new MetadataLoadingThread(this);687 metadata_loader->start();691 metadata_loader = NULL; 692 startLoading (); 688 693 689 694 all_music.setAutoDelete(true); 690 695 top_nodes.setAutoDelete(true); … … 718 723 return false; 719 724 } 720 725 726 bool 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 721 742 void AllMusic::resync() 722 743 { 723 744 done_loading = false; … … 736 757 query.exec(aquery); 737 758 738 759 all_music.clear(); 739 760 761 /* Create the medata objects */ 740 762 if (query.isActive() && query.size() > 0) 741 763 { 742 764 while (query.next()) … … 1193 1215 if( *it != "genre" && 1194 1216 *it != "artist" && 1195 1217 *it != "splitartist" && 1218 *it != "splitartist1" && 1196 1219 *it != "album" && 1197 1220 *it != "title") 1198 1221 { … … 1502 1525 ++iter; 1503 1526 } 1504 1527 } 1505 -
mythplugins/mythmusic/mythmusic/decoder.cpp
6 6 7 7 #include "decoder.h" 8 8 #include "constants.h" 9 #include "metadata.h" 10 #include "metaio.h" 9 11 #include <mythtv/output.h> 10 12 #include <mythtv/visual.h> 11 13 … … 87 89 listeners.remove(object); 88 90 } 89 91 92 Metadata *Decoder::readMetadata () { 93 Metadata *mdata = NULL; 94 MetaIO* p_tagger = doCreateTagger (); 90 95 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 111 Metadata* 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 125 void 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 134 MetaIO *Decoder::doCreateTagger () { 135 return NULL; 136 } 137 91 138 // static methods 92 139 93 140 int Decoder::ignore_id3 = 0; -
mythplugins/mythmusic/mythmusic/aacdecoder.h
29 29 void seek(double); 30 30 void stop(); 31 31 32 Metadata *getMetadata(); 33 void commitMetadata(Metadata *mdata); 32 MetaIO *doCreateTagger(); 34 33 35 34 bool initializeMP4(); 36 35 int getAACTrack(mp4ff_t *infile); -
mythplugins/mythmusic/mythmusic/metadata.h
244 244 Metadata* getMetadata(int an_id); 245 245 bool updateMetadata(int an_id, Metadata *the_track); 246 246 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 (); 247 257 void resync(); // After a CD rip, for example 248 258 void clearCDData(); 249 259 void addCDTrack(Metadata *the_track); … … 264 274 bool cleanOutThreads(); 265 275 int getCDTrackCount(){return cd_data.count();} 266 276 void resetListings(){last_listed = -1;} 267 268 277 private: 269 278 270 279 QPtrList<Metadata> all_music; -
mythplugins/mythmusic/mythmusic/vorbisdecoder.cpp
293 293 deinit(); 294 294 } 295 295 296 Meta data *VorbisDecoder::getMetadata()296 MetaIO *VorbisDecoder::doCreateTagger() 297 297 { 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; 328 299 } 329 300 330 301 -
mythplugins/mythmusic/mythmusic/flacdecoder.h
22 22 void doWrite(const FLAC__Frame *frame, const FLAC__int32 * const buffer[]); 23 23 void setFlacMetadata(const FLAC__StreamMetadata *metadata); 24 24 25 Metadata *getMetadata(); 26 void commitMetadata(Metadata *mdata); 25 MetaIO *doCreateTagger(); 27 26 28 27 private: 29 28 void run(); -
mythplugins/mythmusic/mythmusic/avfdecoder.cpp
357 357 deinit(); 358 358 } 359 359 360 Meta data* avfDecoder::getMetadata()360 MetaIO* avfDecoder::doCreateTagger() 361 361 { 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; 385 363 } 386 364 387 void avfDecoder::commitMetadata(Metadata *mdata)388 {389 MetaIOAVFComment* p_tagger = new MetaIOAVFComment;390 p_tagger->write(mdata);391 delete p_tagger;392 }393 394 365 bool avfDecoderFactory::supports(const QString &source) const 395 366 { 396 367 return (source.right(extension().length()).lower() == extension()); -
mythplugins/mythmusic/mythmusic/main.cpp
6 6 #include <qapplication.h> 7 7 #include <qsqldatabase.h> 8 8 #include <qregexp.h> 9 #include <sys/types.h> 10 #include <sys/stat.h> 9 11 #include <unistd.h> 10 12 11 13 #include <cdaudio.h> … … 65 67 return decoder; 66 68 } 67 69 68 void CheckFile(const QString &filename) 70 // Add a file to the database 71 void AddFileToDB(const QString &directory, const QString &filename) 69 72 { 70 73 Decoder *decoder = getDecoder(filename); 71 74 72 75 if (decoder) 73 76 { 74 77 Metadata *data = decoder->getMetadata(); 75 if (data) 78 if (data) 79 { 80 data->dumpToDatabase(directory); 76 81 delete data; 82 } 83 delete decoder; 84 } 85 } 77 86 87 // Remove a file from the database 88 void 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 100 void 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 78 121 delete decoder; 79 122 } 80 123 } … … 83 126 { 84 127 kFileSystem, 85 128 kDatabase, 86 k Both129 kNeedUpdate, 87 130 }; 88 131 89 132 typedef QMap <QString, MusicFileLocation> MusicLoadedMap; … … 102 145 QFileInfoListIterator it(*list); 103 146 QFileInfo *fi; 104 147 148 /* Recursively traverse directory, calling 149 QApplication::processEvents every now and then to ensure the UI 150 updates */ 151 int update_int = 0; 105 152 while ((fi = it.current()) != 0) 106 153 { 107 154 ++it; 108 155 if (fi->fileName() == "." || fi->fileName() == "..") 109 156 continue; 110 157 QString filename = fi->absFilePath(); 111 if (fi->isDir()) 158 if (fi->isDir()) { 159 qApp->processEvents (); 112 160 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 } 115 169 } 116 170 } 117 171 172 /* Check if the file's mdate is after the date_modified */ 173 bool 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 118 184 void SavePending(int pending) 119 185 { 120 186 // Temporary Hack until mythmusic … … 176 242 { 177 243 MusicLoadedMap music_files; 178 244 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 } 179 256 180 BuildFileList(directory, music_files);181 182 257 MSqlQuery query(MSqlQuery::InitCon()); 183 query.exec("SELECT filename FROM musicmetadata "258 query.exec("SELECT filename, date_modified FROM musicmetadata " 184 259 "WHERE filename NOT LIKE ('%://%');"); 185 260 261 MythProgressDialog *progress; 262 progress = new MythProgressDialog(QObject::tr("Scanning music files"), 263 query.numRowsAffected()); 264 186 265 int counter = 0; 187 266 188 MythProgressDialog *file_checking;189 file_checking = new MythProgressDialog(QObject::tr("Searching for music files"),190 query.numRowsAffected());191 192 267 if (query.isActive() && query.size() > 0) 193 268 { 194 269 while (query.next()) … … 196 271 QString name = directory + QString::fromUtf8(query.value(0).toString()); 197 272 if (name != QString::null) 198 273 { 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 { 202 281 music_files[name] = kDatabase; 282 } 203 283 } 204 file_checking->setProgress(++counter);284 progress->setProgress(++counter); 205 285 } 206 286 } 207 287 208 file_checking->Close();209 delete file_checking;288 progress->Close(); 289 delete progress; 210 290 211 file_checking = new MythProgressDialog(QObject::tr("Updating music database"), 291 counter = 0; 292 progress = new MythProgressDialog(QObject::tr("Updating music database"), 212 293 music_files.size()); 213 294 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 214 306 QRegExp quote_regex("\""); 215 307 for (iter = music_files.begin(); iter != music_files.end(); iter++) 216 308 { 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; 220 319 } 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); 233 321 } 234 file_checking->Close();235 delete file_checking;322 progress->Close(); 323 delete progress; 236 324 } 237 325 238 326 void startPlayback(PlaylistsContainer *all_playlists, AllMusic *all_music) … … 283 371 AllMusic *all_music; 284 372 }; 285 373 374 void 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 286 386 void MusicCallback(void *data, QString &selection) 287 387 { 288 388 MusicData *mdata = (MusicData *)data; … … 302 402 // Reconcile with the database 303 403 SearchDir(mdata->startdir); 304 404 // Tell the metadata to reset itself 305 mdata->all_music->resync(); 306 mdata->all_playlists->postLoad(); 405 RebuildMusicTree (mdata); 307 406 } 308 407 } 309 408 else if (sel == "settings_scan") … … 311 410 if ("" != mdata->startdir) 312 411 { 313 412 SearchDir(mdata->startdir); 314 mdata->all_music->resync(); 315 mdata->all_playlists->postLoad(); 413 RebuildMusicTree (mdata); 316 414 } 317 415 } 318 416 else if (sel == "music_set_general") … … 554 652 // if startRipper returns true, then new files should be present 555 653 // so we should look for them. 556 654 SearchDir(mdata.startdir); 557 mdata.all_music->resync(); 558 mdata.all_playlists->postLoad(); 655 RebuildMusicTree (&mdata); 559 656 } 560 657 postMusic(&mdata); 561 658 } -
mythplugins/mythmusic/mythmusic/flacdecoder.cpp
385 385 char *field_value; 386 386 } Argument_VcField; 387 387 388 Meta data *FlacDecoder::getMetadata()388 MetaIO *FlacDecoder::doCreateTagger() 389 389 { 390 Metadata *mdata = new Metadata(filename); 391 if (mdata->isInDatabase(musiclocation)) 392 { 393 return mdata; 394 } 390 return new MetaIOFLACVorbisComment; 391 } 395 392 396 delete mdata;397 393 398 MetaIOFLACVorbisComment* p_tagger = new MetaIOFLACVorbisComment;399 if (ignore_id3)400 mdata = p_tagger->readFromFilename(filename);401 else402 mdata = p_tagger->read(filename);403 404 delete p_tagger;405 406 if (mdata)407 mdata->dumpToDatabase(musiclocation);408 else409 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 422 394 bool FlacDecoderFactory::supports(const QString &source) const 423 395 { 424 396 return (source.right(extension().length()).lower() == extension()); -
mythplugins/mythmusic/mythmusic/maddecoder.h
24 24 static const int maxFrameCheck; 25 25 static const int initialFrameSize; 26 26 27 Metadata *getMetadata(); 28 void commitMetadata(Metadata *mdata); 27 MetaIO *doCreateTagger(); 29 28 30 29 private: 31 30 void run(); -
mythplugins/mythmusic/mythmusic/vorbisdecoder.h
18 18 void seek(double); 19 19 void stop(); 20 20 21 Metadata *getMetadata(); 22 void commitMetadata(Metadata *mdata); 21 MetaIO *doCreateTagger(); 23 22 24 23 private: 25 24 void run(); -
mythplugins/mythmusic/mythmusic/avfdecoder.h
18 18 void seek(double); 19 19 void stop(); 20 20 21 Metadata *getMetadata(); 22 void commitMetadata(Metadata *mdata); 21 MetaIO *doCreateTagger(); 23 22 24 23 private: 25 24 void run(); -
mythplugins/mythmusic/mythmusic/maddecoder.cpp
512 512 return MAD_FLOW_STOP; 513 513 } 514 514 515 Meta data *MadDecoder::getMetadata()515 MetaIO *MadDecoder::doCreateTagger() 516 516 { 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; 540 518 } 541 519 542 void MadDecoder::commitMetadata(Metadata *mdata)543 {544 MetaIOID3v2* p_tagger = new MetaIOID3v2;545 p_tagger->write(mdata);546 delete p_tagger;547 }548 549 520 bool MadDecoderFactory::supports(const QString &source) const 550 521 { 551 522 bool res = false;