Merge tag 'v0.22.2' into master

release v0.22.2
This commit is contained in:
Max Kellermann
2020-10-28 17:33:10 +01:00
22 changed files with 275 additions and 74 deletions

View File

@@ -31,6 +31,7 @@ db_glue_sources = [
'update/Remove.cxx',
'update/ExcludeList.cxx',
'update/VirtualDirectory.cxx',
'update/SpecialDirectory.cxx',
'DatabaseGlue.cxx',
'Configured.cxx',
'DatabaseSong.cxx',

View File

@@ -132,6 +132,14 @@ public:
return mounted_database != nullptr;
}
/**
* Checks whether this is a "special" directory
* (e.g. #DEVICE_PLAYLIST) and whether the underlying plugin
* is available.
*/
gcc_pure
bool IsPluginAvailable() const noexcept;
/**
* Remove this #Directory object from its parent and free it. This
* must not be called with the root Directory.

View File

@@ -34,6 +34,14 @@ Song::Song(DetachedSong &&other, Directory &_parent) noexcept
{
}
const char *
Song::GetFilenameSuffix() const noexcept
{
return target.empty()
? PathTraitsUTF8::GetFilenameSuffix(filename.c_str())
: PathTraitsUTF8::GetPathSuffix(target.c_str());
}
std::string
Song::GetURI() const noexcept
{

View File

@@ -108,6 +108,16 @@ struct Song {
Song(DetachedSong &&other, Directory &_parent) noexcept;
gcc_pure
const char *GetFilenameSuffix() const noexcept;
/**
* Checks whether the decoder plugin for this song is
* available.
*/
gcc_pure
bool IsPluginAvailable() const noexcept;
/**
* allocate a new song structure with a local file name and attempt to
* load its metadata. If all decoder plugin fail to read its meta

View File

@@ -0,0 +1,74 @@
/*
* Copyright 2003-2020 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "db/plugins/simple/Directory.hxx"
#include "archive/ArchiveList.hxx"
#include "decoder/DecoderList.hxx"
#include "playlist/PlaylistRegistry.hxx"
#include "fs/Traits.hxx"
gcc_pure
static bool
HaveArchivePluginForFilename(const char *filename) noexcept
{
#ifdef ENABLE_ARCHIVE
const char *suffix = PathTraitsUTF8::GetFilenameSuffix(filename);
return suffix != nullptr &&
archive_plugin_from_suffix(suffix) != nullptr;
#else
(void)filename;
return false;
#endif
}
gcc_pure
static bool
HaveContainerPluginForFilename(const char *filename) noexcept
{
const char *suffix = PathTraitsUTF8::GetFilenameSuffix(filename);
return suffix != nullptr &&
// TODO: check if this plugin really supports containers
decoder_plugins_supports_suffix(suffix);
}
gcc_pure
static bool
HavePlaylistPluginForFilename(const char *filename) noexcept
{
const char *suffix = PathTraitsUTF8::GetFilenameSuffix(filename);
return suffix != nullptr && playlist_suffix_supported(suffix);
}
bool
Directory::IsPluginAvailable() const noexcept
{
switch (device) {
case DEVICE_INARCHIVE:
return HaveArchivePluginForFilename(GetName());
case DEVICE_CONTAINER:
return HaveContainerPluginForFilename(GetName());
case DEVICE_PLAYLIST:
return HavePlaylistPluginForFilename(GetName());
default:
return true;
}
}

View File

@@ -69,46 +69,58 @@ UpdateWalk::RemoveExcludedFromDirectory(Directory &directory,
const ScopeDatabaseLock protect;
directory.ForEachChildSafe([&](Directory &child){
const auto name_fs =
AllocatedPath::FromUTF8(child.GetName());
const auto name_fs =
AllocatedPath::FromUTF8(child.GetName());
if (name_fs.IsNull() || exclude_list.Check(name_fs)) {
editor.DeleteDirectory(&child);
modified = true;
}
});
if (name_fs.IsNull() || exclude_list.Check(name_fs)) {
editor.DeleteDirectory(&child);
modified = true;
}
});
directory.ForEachSongSafe([&](Song &song){
assert(&song.parent == &directory);
assert(&song.parent == &directory);
const auto name_fs = AllocatedPath::FromUTF8(song.filename);
if (name_fs.IsNull() || exclude_list.Check(name_fs)) {
editor.DeleteSong(directory, &song);
modified = true;
}
});
const auto name_fs = AllocatedPath::FromUTF8(song.filename);
if (name_fs.IsNull() || exclude_list.Check(name_fs)) {
editor.DeleteSong(directory, &song);
modified = true;
}
});
}
inline void
UpdateWalk::PurgeDeletedFromDirectory(Directory &directory) noexcept
{
directory.ForEachChildSafe([&](Directory &child){
if (child.IsMount() || DirectoryExists(storage, child))
return;
if (child.IsMount())
/* mount points are always preserved */
return;
editor.LockDeleteDirectory(&child);
if (DirectoryExists(storage, child) &&
child.IsPluginAvailable())
return;
modified = true;
});
/* the directory was deleted (or the plugin which
handles this "virtual" directory is unavailable) */
editor.LockDeleteDirectory(&child);
modified = true;
});
directory.ForEachSongSafe([&](Song &song){
if (!directory_child_is_regular(storage, directory,
song.filename)) {
editor.LockDeleteSong(directory, &song);
if (!directory_child_is_regular(storage, directory,
song.filename) ||
!song.IsPluginAvailable()) {
/* the song file was deleted (or the decoder
plugin is unavailable) */
modified = true;
}
});
editor.LockDeleteSong(directory, &song);
modified = true;
}
});
for (auto i = directory.playlists.begin(),
end = directory.playlists.end();