summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMax Kellermann <max@musicpd.org>2021-08-05 18:57:11 +0200
committerMax Kellermann <max@musicpd.org>2021-08-05 20:26:21 +0200
commit1985786ed25b82eddfdabe104c8698967dbb4cca (patch)
tree33f80183604ff01be40669935c01c1e53a388afb
parent8e0d39ae944263339773c6804846751701092fc6 (diff)
db/simple: prune CUE entries from database for non-existent songs
Closes https://github.com/MusicPlayerDaemon/MPD/issues/1019
-rw-r--r--NEWS1
-rw-r--r--src/db/plugins/simple/Directory.cxx17
-rw-r--r--src/db/plugins/simple/Directory.hxx9
-rw-r--r--src/db/update/Walk.cxx27
-rw-r--r--src/db/update/Walk.hxx6
5 files changed, 59 insertions, 1 deletions
diff --git a/NEWS b/NEWS
index 28a9acb36..3d6f0a112 100644
--- a/NEWS
+++ b/NEWS
@@ -4,6 +4,7 @@ ver 0.22.10 (not yet released)
* database
- simple: fix crash bug
- simple: fix absolute paths in CUE "as_directory" entries
+ - simple: prune CUE entries from database for non-existent songs
* input
- curl: fix crash bug after stream with Icy metadata was closed by peer
- tidal: remove defunct unmaintained plugin
diff --git a/src/db/plugins/simple/Directory.cxx b/src/db/plugins/simple/Directory.cxx
index 4c7bb2873..b03994730 100644
--- a/src/db/plugins/simple/Directory.cxx
+++ b/src/db/plugins/simple/Directory.cxx
@@ -109,6 +109,23 @@ Directory::FindChild(std::string_view name) const noexcept
return nullptr;
}
+bool
+Directory::TargetExists(std::string_view _target) const noexcept
+{
+ StringView target{_target};
+
+ if (target.SkipPrefix("../")) {
+ if (parent == nullptr)
+ return false;
+
+ return parent->TargetExists(target);
+ }
+
+ /* sorry for the const_cast ... */
+ const auto lr = const_cast<Directory *>(this)->LookupDirectory(target);
+ return lr.directory->FindSong(lr.rest) != nullptr;
+}
+
void
Directory::PruneEmpty() noexcept
{
diff --git a/src/db/plugins/simple/Directory.hxx b/src/db/plugins/simple/Directory.hxx
index 6b8899440..87e8351e7 100644
--- a/src/db/plugins/simple/Directory.hxx
+++ b/src/db/plugins/simple/Directory.hxx
@@ -118,13 +118,17 @@ public:
return new Directory(std::string(), nullptr);
}
+ bool IsPlaylist() const noexcept {
+ return device == DEVICE_PLAYLIST;
+ }
+
/**
* Is this really a regular file which is being treated like a
* directory?
*/
bool IsReallyAFile() const noexcept {
return device == DEVICE_INARCHIVE ||
- device == DEVICE_PLAYLIST ||
+ IsPlaylist() ||
device == DEVICE_CONTAINER;
}
@@ -210,6 +214,9 @@ public:
gcc_pure
LookupResult LookupDirectory(std::string_view uri) noexcept;
+ [[gnu::pure]]
+ bool TargetExists(std::string_view target) const noexcept;
+
gcc_pure
bool IsEmpty() const noexcept {
return children.empty() &&
diff --git a/src/db/update/Walk.cxx b/src/db/update/Walk.cxx
index b1fb675e6..c5fb8230d 100644
--- a/src/db/update/Walk.cxx
+++ b/src/db/update/Walk.cxx
@@ -133,6 +133,28 @@ UpdateWalk::PurgeDeletedFromDirectory(Directory &directory) noexcept
}
}
+void
+UpdateWalk::PurgeDanglingFromPlaylists(Directory &directory) noexcept
+{
+ /* recurse */
+ for (Directory &child : directory.children)
+ PurgeDanglingFromPlaylists(child);
+
+ if (!directory.IsPlaylist())
+ /* this check is only for virtual directories
+ representing a playlist file */
+ return;
+
+ directory.ForEachSongSafe([&](Song &song){
+ if (!song.target.empty() &&
+ !PathTraitsUTF8::IsAbsoluteOrHasScheme(song.target.c_str()) &&
+ !directory.TargetExists(song.target)) {
+ editor.DeleteSong(directory, &song);
+ modified = true;
+ }
+ });
+}
+
#ifndef _WIN32
static bool
update_directory_stat(Storage &storage, Directory &directory) noexcept
@@ -530,5 +552,10 @@ UpdateWalk::Walk(Directory &root, const char *path, bool discard) noexcept
UpdateDirectory(root, exclude_list, info);
}
+ {
+ const ScopeDatabaseLock protect;
+ PurgeDanglingFromPlaylists(root);
+ }
+
return modified;
}
diff --git a/src/db/update/Walk.hxx b/src/db/update/Walk.hxx
index 433d1a3a1..984230ce9 100644
--- a/src/db/update/Walk.hxx
+++ b/src/db/update/Walk.hxx
@@ -85,6 +85,12 @@ private:
void PurgeDeletedFromDirectory(Directory &directory) noexcept;
+ /**
+ * Remove all virtual songs inside playlists whose "target"
+ * field points to a non-existing song file.
+ */
+ void PurgeDanglingFromPlaylists(Directory &directory) noexcept;
+
void UpdateSongFile2(Directory &directory,
const char *name, const char *suffix,
const StorageFileInfo &info) noexcept;