diff --git a/src/collection/collectionwatcher.cpp b/src/collection/collectionwatcher.cpp index bdb048a69..6eb4ad6ba 100644 --- a/src/collection/collectionwatcher.cpp +++ b/src/collection/collectionwatcher.cpp @@ -503,7 +503,7 @@ void CollectionWatcher::ScanSubdirectory(const QString &path, const Subdirectory if (stop_requested_) return; // Associated CUE - QString new_cue = NoExtensionPart(file) + ".cue"; + QString new_cue = CueParser::FindCueFilename(file); SongList matching_songs; if (FindSongsByPath(songs_in_db, file, &matching_songs)) { // Found matching song in DB by path. @@ -525,13 +525,17 @@ void CollectionWatcher::ScanSubdirectory(const QString &path, const Subdirectory qint64 matching_song_cue_mtime = static_cast(GetMtimeForCue(matching_song.cue_path())); // CUE sheet's path from this file (if any). - qint64 new_cue_mtime = static_cast(GetMtimeForCue(new_cue)); + qint64 new_cue_mtime = 0; + if (!new_cue.isEmpty()) { + new_cue_mtime = static_cast(GetMtimeForCue(new_cue)); + } - bool cue_added = new_cue_mtime != 0 && !matching_song.has_cue(); - bool cue_deleted = matching_song_cue_mtime == 0 && matching_song.has_cue(); + const bool cue_added = new_cue_mtime != 0 && !matching_song.has_cue(); + const bool cue_changed = new_cue_mtime != 0 && matching_song.has_cue() && new_cue != matching_song.cue_path(); + const bool cue_deleted = matching_song.has_cue() && new_cue_mtime == 0; // Watch out for CUE songs which have their mtime equal to qMax(media_file_mtime, cue_sheet_mtime) - bool changed = (matching_song.mtime() != qMax(fileinfo.lastModified().toSecsSinceEpoch(), matching_song_cue_mtime)) || cue_deleted || cue_added; + bool changed = (matching_song.mtime() != qMax(fileinfo.lastModified().toSecsSinceEpoch(), matching_song_cue_mtime)) || cue_deleted || cue_added || cue_changed; // Also want to look to see whether the album art has changed QUrl image = ImageForSong(file, album_art); @@ -567,12 +571,13 @@ void CollectionWatcher::ScanSubdirectory(const QString &path, const Subdirectory } #endif - if (!cue_deleted && (matching_song.has_cue() || cue_added)) { // If CUE associated. - UpdateCueAssociatedSongs(file, path, fingerprint, new_cue, image, matching_songs, t); - } - else { // If no CUE or it's about to lose it. + if (new_cue.isEmpty() || new_cue_mtime == 0) { // If no CUE or it's about to lose it. UpdateNonCueAssociatedSong(file, fingerprint, matching_songs, image, cue_deleted, t); } + else { // If CUE associated. + UpdateCueAssociatedSongs(file, path, fingerprint, new_cue, image, matching_songs, t); + } + } // Nothing has changed - mark the song available without re-scanning @@ -604,7 +609,7 @@ void CollectionWatcher::ScanSubdirectory(const QString &path, const Subdirectory continue; } - // Make sure the songs aren't deleted, as they still exist elsewhere with a different fingerprint. + // Make sure the songs aren't deleted, as they still exist elsewhere with a different file path. bool matching_songs_has_cue = false; for (const Song &matching_song : matching_songs) { QString matching_filename = matching_song.url().toLocalFile(); @@ -621,19 +626,19 @@ void CollectionWatcher::ScanSubdirectory(const QString &path, const Subdirectory } // CUE sheet's path from this file (if any). - const qint64 new_cue_mtime = static_cast(GetMtimeForCue(new_cue)); - - const bool cue_deleted = new_cue_mtime == 0 && matching_songs_has_cue; - const bool cue_added = new_cue_mtime != 0 && !matching_songs_has_cue; + qint64 new_cue_mtime = 0; + if (!new_cue.isEmpty()) { + new_cue_mtime = static_cast(GetMtimeForCue(new_cue)); + } // Get new album art QUrl image = ImageForSong(file, album_art); - if (!cue_deleted && (matching_songs_has_cue || cue_added)) { // CUE associated. - UpdateCueAssociatedSongs(file, path, fingerprint, new_cue, image, matching_songs, t); + if (new_cue.isEmpty() || new_cue_mtime == 0) { // If no CUE or it's about to lose it. + UpdateNonCueAssociatedSong(file, fingerprint, matching_songs, image, matching_songs_has_cue && new_cue_mtime == 0, t); } - else { // If no CUE or it's about to lose it. - UpdateNonCueAssociatedSong(file, fingerprint, matching_songs, image, cue_deleted, t); + else { // If CUE associated. + UpdateCueAssociatedSongs(file, path, fingerprint, new_cue, image, matching_songs, t); } } diff --git a/src/collection/collectionwatcher.h b/src/collection/collectionwatcher.h index 80e0f984e..268ad97e6 100644 --- a/src/collection/collectionwatcher.h +++ b/src/collection/collectionwatcher.h @@ -194,6 +194,8 @@ class CollectionWatcher : public QObject { quint64 FilesCountForPath(ScanTransaction *t, const QString &path); quint64 FilesCountForSubdirs(ScanTransaction *t, const SubdirectoryList &subdirs, QMap &subdir_files_count); + QString FindCueFilename(const QString &filename); + private: Song::Source source_; CollectionBackend *backend_; diff --git a/src/core/songloader.cpp b/src/core/songloader.cpp index 7fb395918..c9c91e3b1 100644 --- a/src/core/songloader.cpp +++ b/src/core/songloader.cpp @@ -300,7 +300,7 @@ SongLoader::Result SongLoader::LoadLocalAsync(const QString &filename) { } // Check if it's a CUE file - QString matching_cue = filename.section('.', 0, -2) + ".cue"; + QString matching_cue = CueParser::FindCueFilename(filename); if (QFile::exists(matching_cue)) { // It's a CUE - create virtual tracks QFile cue(matching_cue); diff --git a/src/playlistparsers/cueparser.cpp b/src/playlistparsers/cueparser.cpp index 312aaaf82..e8bc32765 100644 --- a/src/playlistparsers/cueparser.cpp +++ b/src/playlistparsers/cueparser.cpp @@ -379,3 +379,16 @@ bool CueParser::TryMagic(const QByteArray &data) const { return false; } + +QString CueParser::FindCueFilename(const QString &filename) { + + QStringList cue_files = QStringList() << filename + ".cue" + << filename.section('.', 0, -2) + ".cue"; + + for (const QString &cuefile : cue_files) { + if (QFileInfo::exists(cuefile)) return cuefile; + } + + return QString(); + +} diff --git a/src/playlistparsers/cueparser.h b/src/playlistparsers/cueparser.h index 87d245dfa..b1f7b29f5 100644 --- a/src/playlistparsers/cueparser.h +++ b/src/playlistparsers/cueparser.h @@ -70,6 +70,8 @@ class CueParser : public ParserBase { SongList Load(QIODevice *device, const QString &playlist_path = "", const QDir &dir = QDir(), const bool collection_search = true) const override; void Save(const SongList &songs, QIODevice *device, const QDir &dir = QDir(), Playlist::Path path_type = Playlist::Path_Automatic) const override; + static QString FindCueFilename(const QString &filename); + private: // A single TRACK entry in .cue file. struct CueEntry {