diff --git a/NEWS b/NEWS index 0a33ffe8c..19df7e53e 100644 --- a/NEWS +++ b/NEWS @@ -40,6 +40,8 @@ ver 0.22 (not yet released) - GCC 7 or clang 4 (or newer) recommended ver 0.21.26 (not yet released) +* database + - inotify: obey ".mpdignore" files * output - osx: fix crash bug - sles: support floating point samples @@ -50,7 +52,11 @@ ver 0.21.26 (not yet released) - iso9660: support seeking - zzip: fix crash on corrupt ZIP file * decoder + - ffmpeg: remove "rtsp://" from the list of supported protocols + - ffmpeg: add "hls+http://" to the list of supported protocols - sndfile: fix lost samples at end of file +* fix "single" mode bug after resuming playback +* the default log_level is "default", not "info" ver 0.21.25 (2020/07/06) * protocol: diff --git a/src/command/FileCommands.cxx b/src/command/FileCommands.cxx index ebe229ebd..814289321 100644 --- a/src/command/FileCommands.cxx +++ b/src/command/FileCommands.cxx @@ -50,9 +50,7 @@ gcc_pure static bool SkipNameFS(PathTraitsFS::const_pointer name_fs) noexcept { - return name_fs[0] == '.' && - (name_fs[1] == 0 || - (name_fs[1] == '.' && name_fs[2] == 0)); + return PathTraitsFS::IsSpecialFilename(name_fs); } gcc_pure diff --git a/src/db/update/InotifyUpdate.cxx b/src/db/update/InotifyUpdate.cxx index ff6257b99..957f4cf8d 100644 --- a/src/db/update/InotifyUpdate.cxx +++ b/src/db/update/InotifyUpdate.cxx @@ -21,19 +21,25 @@ #include "InotifySource.hxx" #include "InotifyQueue.hxx" #include "InotifyDomain.hxx" +#include "ExcludeList.hxx" #include "storage/StorageInterface.hxx" +#include "input/InputStream.hxx" +#include "input/Error.hxx" #include "fs/AllocatedPath.hxx" +#include "fs/DirectoryReader.hxx" #include "fs/FileInfo.hxx" #include "fs/Traits.hxx" +#include "thread/Mutex.hxx" +#include "util/Compiler.h" #include "Log.hxx" #include +#include #include #include #include #include -#include #include static constexpr unsigned IN_MASK = @@ -50,17 +56,28 @@ struct WatchDirectory { int descriptor; + ExcludeList exclude_list; + std::forward_list children; template - WatchDirectory(WatchDirectory *_parent, N &&_name, + WatchDirectory(N &&_name, int _descriptor) - :parent(_parent), name(std::forward(_name)), + :parent(nullptr), name(std::forward(_name)), descriptor(_descriptor) {} + template + WatchDirectory(WatchDirectory &_parent, N &&_name, + int _descriptor) + :parent(&_parent), name(std::forward(_name)), + descriptor(_descriptor), + exclude_list(_parent.exclude_list) {} + WatchDirectory(const WatchDirectory &) = delete; WatchDirectory &operator=(const WatchDirectory &) = delete; + void LoadExcludeList(Path directory_path) noexcept; + [[nodiscard]] gcc_pure unsigned GetDepth() const noexcept; @@ -68,6 +85,18 @@ struct WatchDirectory { AllocatedPath GetUriFS() const noexcept; }; +void +WatchDirectory::LoadExcludeList(Path directory_path) noexcept +try { + Mutex mutex; + auto is = InputStream::OpenReady((directory_path / Path::FromFS(".mpdignore")).c_str(), + mutex); + exclude_list.Load(std::move(is)); +} catch (...) { + if (!IsFileNotFound(std::current_exception())) + LogError(std::current_exception()); +} + static InotifySource *inotify_source; static InotifyQueue *inotify_queue; @@ -145,20 +174,19 @@ WatchDirectory::GetUriFS() const noexcept } /* we don't look at "." / ".." nor files with newlines in their name */ -static bool skip_path(const char *path) +gcc_pure +static bool +SkipFilename(Path name) noexcept { - return PathTraitsFS::IsSpecialFilename(path) || - std::strchr(path, '\n') != nullptr; + return PathTraitsFS::IsSpecialFilename(name.c_str()) || + name.HasNewline(); } static void -recursive_watch_subdirectories(WatchDirectory *directory, - const AllocatedPath &path_fs, unsigned depth) -{ - DIR *dir; - struct dirent *ent; - - assert(directory != nullptr); +recursive_watch_subdirectories(WatchDirectory &parent, + const Path path_fs, + unsigned depth) +try { assert(depth <= inotify_max_depth); assert(!path_fs.IsNull()); @@ -167,20 +195,17 @@ recursive_watch_subdirectories(WatchDirectory *directory, if (depth > inotify_max_depth) return; - dir = opendir(path_fs.c_str()); - if (dir == nullptr) { - FormatErrno(inotify_domain, - "Failed to open directory %s", path_fs.c_str()); - return; - } - - while ((ent = readdir(dir))) { + DirectoryReader dir(path_fs); + while (dir.ReadEntry()) { int ret; - if (skip_path(ent->d_name)) + const Path name_fs = dir.GetEntry(); + if (SkipFilename(name_fs)) + continue; + + if (parent.exclude_list.Check(name_fs)) continue; - const auto name_fs = Path::FromFS(ent->d_name); const auto child_path_fs = path_fs / name_fs; FileInfo fi; @@ -209,17 +234,18 @@ recursive_watch_subdirectories(WatchDirectory *directory, /* already being watched */ continue; - directory->children.emplace_front(directory, - name_fs, - ret); - child = &directory->children.front(); + parent.children.emplace_front(parent, + name_fs, + ret); + child = &parent.children.front(); + child->LoadExcludeList(child_path_fs); tree_add_watch_directory(child); - recursive_watch_subdirectories(child, child_path_fs, depth); + recursive_watch_subdirectories(*child, child_path_fs, depth); } - - closedir(dir); +} catch (...) { + LogError(std::current_exception()); } gcc_pure @@ -240,8 +266,6 @@ mpd_inotify_callback(int wd, unsigned mask, { WatchDirectory *directory; - /*FormatDebug(inotify_domain, "wd=%d mask=0x%x name='%s'", wd, mask, name);*/ - directory = tree_find_watch_directory(wd); if (directory == nullptr) return; @@ -263,7 +287,7 @@ mpd_inotify_callback(int wd, unsigned mask, ? root : (root / uri_fs); - recursive_watch_subdirectories(directory, path_fs, + recursive_watch_subdirectories(*directory, path_fs, directory->GetDepth()); } @@ -318,11 +342,12 @@ mpd_inotify_init(EventLoop &loop, Storage &storage, UpdateService &update, return; } - inotify_root = new WatchDirectory(nullptr, path, descriptor); + inotify_root = new WatchDirectory(path, descriptor); + inotify_root->LoadExcludeList(path); tree_add_watch_directory(inotify_root); - recursive_watch_subdirectories(inotify_root, path, 0); + recursive_watch_subdirectories(*inotify_root, path, 0); inotify_queue = new InotifyQueue(loop, update); diff --git a/src/player/Thread.cxx b/src/player/Thread.cxx index e53c5832a..3a109f12d 100644 --- a/src/player/Thread.cxx +++ b/src/player/Thread.cxx @@ -443,7 +443,7 @@ Player::ActivateDecoder() noexcept pc.audio_format.Clear(); { - /* call syncPlaylistWithQueue() in the main thread */ + /* call playlist::SyncWithPlayer() in the main thread */ const ScopeUnlock unlock(pc.mutex); pc.listener.OnPlayerSync(); } @@ -684,6 +684,12 @@ Player::SeekDecoder(std::unique_lock &lock) noexcept /* re-fill the buffer after seeking */ buffering = true; + { + /* call syncPlaylistWithQueue() in the main thread */ + const ScopeUnlock unlock(pc.mutex); + pc.listener.OnPlayerSync(); + } + return true; } @@ -1175,6 +1181,11 @@ try { { const ScopeUnlock unlock(mutex); do_play(*this, dc, buffer); + + /* give the main thread a chance to + queue another song, just in case + we've stopped playback + spuriously */ listener.OnPlayerSync(); } diff --git a/src/storage/plugins/NfsStorage.cxx b/src/storage/plugins/NfsStorage.cxx index a93ccefb9..fbe18e96b 100644 --- a/src/storage/plugins/NfsStorage.cxx +++ b/src/storage/plugins/NfsStorage.cxx @@ -305,9 +305,7 @@ gcc_pure static bool SkipNameFS(PathTraitsFS::const_pointer name) noexcept { - return name[0] == '.' && - (name[1] == 0 || - (name[1] == '.' && name[2] == 0)); + return PathTraitsFS::IsSpecialFilename(name); } static void diff --git a/src/storage/plugins/SmbclientStorage.cxx b/src/storage/plugins/SmbclientStorage.cxx index e62c95902..390cb8c4a 100644 --- a/src/storage/plugins/SmbclientStorage.cxx +++ b/src/storage/plugins/SmbclientStorage.cxx @@ -151,11 +151,9 @@ SmbclientStorage::OpenDirectory(std::string_view uri_utf8) gcc_pure static bool -SkipNameFS(const char *name) noexcept +SkipNameFS(PathTraitsFS::const_pointer name) noexcept { - return name[0] == '.' && - (name[1] == 0 || - (name[1] == '.' && name[2] == 0)); + return PathTraitsFS::IsSpecialFilename(name); } SmbclientDirectoryReader::~SmbclientDirectoryReader()