diff -ruw ../decoder-refactor/mythplugins/mythmusic/mythmusic/main.cpp mythplugins/mythmusic/mythmusic/main.cpp
old
|
new
|
|
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> |
… |
… |
|
93 | 95 | query.exec(); |
94 | 96 | } |
95 | 97 | |
| 98 | void UpdateFileInDB(const QString &directory, const QString &filename) |
| 99 | { |
| 100 | Decoder *decoder = getDecoder(filename); |
| 101 | |
| 102 | if (decoder) |
| 103 | { |
| 104 | Metadata *db_meta = decoder->getMetadata(); |
| 105 | Metadata *disk_meta = decoder->readMetadata(); |
| 106 | |
| 107 | if (db_meta && disk_meta) |
| 108 | { |
| 109 | disk_meta->setID(db_meta->ID()); |
| 110 | disk_meta->updateDatabase(directory); |
| 111 | } |
| 112 | |
| 113 | if (disk_meta) |
| 114 | delete disk_meta; |
| 115 | |
| 116 | if (db_meta) |
| 117 | delete db_meta; |
| 118 | |
| 119 | delete decoder; |
| 120 | } |
| 121 | } |
| 122 | |
96 | 123 | enum MusicFileLocation |
97 | 124 | { |
98 | 125 | kFileSystem, |
99 | 126 | kDatabase, |
| 127 | kNeedUpdate, |
100 | 128 | kBoth |
101 | 129 | }; |
102 | 130 | |
… |
… |
|
142 | 170 | } |
143 | 171 | } |
144 | 172 | |
| 173 | bool HasFileChanged(const QString &filename, const QString &date_modified) |
| 174 | { |
| 175 | struct stat sbuf; |
| 176 | if (stat(filename.ascii(), &sbuf) == 0) |
| 177 | { |
| 178 | if (date_modified.isEmpty() || |
| 179 | sbuf.st_mtime > |
| 180 | (time_t)QDateTime::fromString(date_modified, |
| 181 | Qt::ISODate).toTime_t()) |
| 182 | { |
| 183 | return true; |
| 184 | } |
| 185 | } |
| 186 | return false; |
| 187 | } |
| 188 | |
145 | 189 | void SavePending(int pending) |
146 | 190 | { |
147 | 191 | // Temporary Hack until mythmusic |
… |
… |
|
213 | 257 | delete busy; |
214 | 258 | |
215 | 259 | MSqlQuery query(MSqlQuery::InitCon()); |
216 | | query.exec("SELECT filename " |
| 260 | query.exec("SELECT filename, date_modified " |
217 | 261 | "FROM musicmetadata " |
218 | 262 | "WHERE filename NOT LIKE ('%://%')"); |
219 | 263 | |
… |
… |
|
232 | 276 | |
233 | 277 | if (name != QString::null) |
234 | 278 | { |
235 | | if ((iter = music_files.find(name)) != music_files.end()) |
| 279 | if ((iter = music_files.find(name)) != music_files.end()) { |
| 280 | if (HasFileChanged(name, query.value(1).toString())) { |
| 281 | music_files[name] = kNeedUpdate; |
| 282 | } else { |
236 | 283 | music_files.remove(iter); |
237 | | else |
| 284 | } |
| 285 | } else { |
238 | 286 | music_files[name] = kDatabase; |
239 | 287 | } |
| 288 | } |
240 | 289 | file_checking->setProgress(++counter); |
241 | 290 | } |
242 | 291 | } |
… |
… |
|
247 | 296 | file_checking = new MythProgressDialog( |
248 | 297 | QObject::tr("Updating music database"), music_files.size()); |
249 | 298 | |
| 299 | /* |
| 300 | This can be optimised quite a bit by consolidating all commands |
| 301 | via a lot of refactoring. |
| 302 | |
| 303 | 1) group all files of the same decoder type, and don't |
| 304 | create/delete a Decoder pr. AddFileToDB. Or make Decoders be |
| 305 | singletons, it should be a fairly simple change. |
| 306 | |
| 307 | 2) RemoveFileFromDB should group the remove into one big SQL. |
| 308 | |
| 309 | 3) UpdateFileInDB, same as 1. |
| 310 | */ |
| 311 | |
250 | 312 | counter = 0; |
251 | 313 | for (iter = music_files.begin(); iter != music_files.end(); iter++) |
252 | 314 | { |
… |
… |
|
254 | 316 | AddFileToDB(directory, iter.key()); |
255 | 317 | else if (*iter == kDatabase) |
256 | 318 | RemoveFileFromDB(directory, iter.key ()); |
| 319 | else if (*iter == kNeedUpdate) |
| 320 | UpdateFileInDB(directory, iter.key()); |
257 | 321 | |
258 | 322 | file_checking->setProgress(++counter); |
259 | 323 | } |
… |
… |
|
309 | 373 | AllMusic *all_music; |
310 | 374 | }; |
311 | 375 | |
| 376 | void RebuildMusicTree(MusicData *mdata) |
| 377 | { |
| 378 | MythBusyDialog busy(QObject::tr("Rebuilding music tree")); |
| 379 | busy.start(); |
| 380 | mdata->all_music->startLoading(); |
| 381 | while (!mdata->all_music->doneLoading()) { |
| 382 | qApp->processEvents(); |
| 383 | usleep(50000); |
| 384 | } |
| 385 | mdata->all_playlists->postLoad(); |
| 386 | busy.Close(); |
| 387 | } |
| 388 | |
312 | 389 | void MusicCallback(void *data, QString &selection) |
313 | 390 | { |
314 | 391 | MusicData *mdata = (MusicData *)data; |
… |
… |
|
328 | 405 | // Reconcile with the database |
329 | 406 | SearchDir(mdata->startdir); |
330 | 407 | // Tell the metadata to reset itself |
331 | | mdata->all_music->resync(); |
332 | | mdata->all_playlists->postLoad(); |
| 408 | RebuildMusicTree(mdata); |
333 | 409 | } |
334 | 410 | } |
335 | 411 | else if (sel == "settings_scan") |
… |
… |
|
337 | 413 | if ("" != mdata->startdir) |
338 | 414 | { |
339 | 415 | SearchDir(mdata->startdir); |
340 | | mdata->all_music->resync(); |
341 | | mdata->all_playlists->postLoad(); |
| 416 | RebuildMusicTree(mdata); |
342 | 417 | } |
343 | 418 | } |
344 | 419 | else if (sel == "music_set_general") |
… |
… |
|
610 | 685 | // if startRipper returns true, then new files should be present |
611 | 686 | // so we should look for them. |
612 | 687 | SearchDir(mdata.startdir); |
613 | | mdata.all_music->resync(); |
614 | | mdata.all_playlists->postLoad(); |
| 688 | RebuildMusicTree(&mdata); |
615 | 689 | } |
616 | 690 | postMusic(&mdata); |
617 | 691 | } |
diff -ruw ../decoder-refactor/mythplugins/mythmusic/mythmusic/metadata.cpp mythplugins/mythmusic/mythmusic/metadata.cpp
old
|
new
|
|
1 | 1 | #include <iostream> |
| 2 | #include <qapplication.h> |
2 | 3 | #include <qregexp.h> |
3 | 4 | #include <qdatetime.h> |
4 | 5 | #include <qdir.h> |
… |
… |
|
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()) |
… |
… |
|
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(void) |
| 727 | { |
| 728 | // Set this to false early rather than letting it be delayed till |
| 729 | // the thread calls resync. |
| 730 | done_loading = false; |
| 731 | |
| 732 | if (metadata_loader) { |
| 733 | cleanOutThreads(); |
| 734 | delete metadata_loader; |
| 735 | } |
| 736 | |
| 737 | metadata_loader = new MetadataLoadingThread(this); |
| 738 | metadata_loader->start(); |
| 739 | |
| 740 | return true; |
| 741 | } |
| 742 | |
721 | 743 | void AllMusic::resync() |
722 | 744 | { |
723 | 745 | done_loading = false; |
… |
… |
|
1161 | 1183 | if( *it != "genre" && |
1162 | 1184 | *it != "artist" && |
1163 | 1185 | *it != "splitartist" && |
| 1186 | *it != "splitartist1" && |
1164 | 1187 | *it != "album" && |
1165 | 1188 | *it != "title") |
1166 | 1189 | { |
diff -ruw ../decoder-refactor/mythplugins/mythmusic/mythmusic/metadata.h mythplugins/mythmusic/mythmusic/metadata.h
old
|
new
|
|
274 | 274 | Metadata* getMetadata(int an_id); |
275 | 275 | bool updateMetadata(int an_id, Metadata *the_track); |
276 | 276 | void save(); |
| 277 | /** \brief Start loading metadata. |
| 278 | Makes the AllMusic object run it's resync in a thread. Once done, it's |
| 279 | doneLoading method will return true. |
| 280 | |
| 281 | \note Alternatively, it could be made to emit a signal so the |
| 282 | caller won't have to poll for completion. |
| 283 | |
| 284 | \returns true if the loader thread was started |
| 285 | */ |
| 286 | bool startLoading (void); |
277 | 287 | void resync(); // After a CD rip, for example |
278 | 288 | void clearCDData(); |
279 | 289 | void addCDTrack(Metadata *the_track); |