release v0.23.13

-----BEGIN PGP SIGNATURE-----
 
 iQJBBAABCgArFiEEA5IzWngIOJSkMBxDI26KWMbbRRIFAmRrqn4NHG1heEBibGFy
 Zy5kZQAKCRAjbopYxttFErXiD/9QIaeO5d+U7BJK1yGkQgu5vHo4Pm34ewP8LTxs
 K2MYxQQ2jZc7PXqi5Z04wmUw8ymq1BVA2D0ytMdl1Ejcbrste7UrP+1TuD8L9JBj
 WCE+4otNVYDpx1PB32BN+gxCmJqiFtAQS+eMIz/SXdEXZ9sJvIgYRRkSiSFd0WHM
 dT3OeeZ0V8cANbXpgI+RLghRGkVdpZJo4uXh3c0OHog1fjEBWPw6+7tH/mkotM0n
 /hQjI5j14wnzZuIpkDR1kuzvGYmxJKG6LkuUqcm1WexNFbxMqDSbAlXeCmzJn7eK
 NQvtROOGNjQ84thxRPLlDlYa6vbxoTqdYgZsVHzsQZWejhqw8zsPsF+Ea0A4tkLd
 UKDQFTphZMVqx74+1u7IjQyW7x+k02iXWLwH2IheEl+BJhvEB7zEflN9TR81jek4
 RrGx7jcTArdpt7okAe2ONkHvTYtIpaK5E2voza8K4TGOMzpkVlOkyvJ+rpn8CDRf
 w0faVvmCQdSrgHKfwUUY8Z47a7d+kkKpFLlvvzNoDV8drQXfgIj5t9HOLATSVVux
 l2pbgauXFsKyd4IsByXj+m8cBSvmy2C4eLJCsmguiZEvcobdJtzwOr4KuwQDjBsC
 8HW0BD0t9S1dSL59vJdMG+CfK/QU5rmAIkxdydD42uo9UmSS78xw1uQgi9oDaPa8
 XNCGdQ==
 =nOGh
 -----END PGP SIGNATURE-----

Merge tag 'v0.23.13'

release v0.23.13
This commit is contained in:
Max Kellermann 2023-05-22 19:50:56 +02:00
commit 9027e5c5bb
13 changed files with 75 additions and 61 deletions

5
NEWS
View File

@ -43,11 +43,14 @@ ver 0.24 (not yet released)
* remove Boost dependency
* require libfmt 7 or later
ver 0.23.13 (not yet released)
ver 0.23.13 (2023/05/22)
* input
- curl: fix busy loop after connection failed
- curl: hide "404" log messages for non-existent ".mpdignore" files
* archive
- zzip: fix crash bug
* database
- simple: reveal hidden songs after deleting containing CUE
* decoder
- ffmpeg: reorder to a lower priority than "gme"
- gme: require GME 0.6 or later

View File

@ -670,6 +670,11 @@ If ReplayGain is enabled, then the setting ``replaygain_preamp`` is
set to a value (in dB) between ``-15`` and ``15``. This is the gain
applied to songs with ReplayGain tags.
On songs without ReplayGain tags, the setting
``replaygain_missing_preamp`` is used instead. If this setting is not
configured, then no ReplayGain is applied to such songs, and they will
appear too loud.
ReplayGain is usually implemented with a software volume filter (which
prevents `Bit-perfect playback`_). To use a hardware mixer, set
``replay_gain_handler`` to ``mixer`` in the ``audio_output`` section

View File

@ -111,6 +111,18 @@ Directory::LookupTargetSong(std::string_view target) noexcept
return lr.directory->FindSong(lr.rest);
}
void
Directory::ClearInPlaylist() noexcept
{
assert(holding_db_lock());
for (auto &child : children)
child.ClearInPlaylist();
for (auto &song : songs)
song.in_playlist = false;
}
void
Directory::PruneEmpty() noexcept
{

View File

@ -257,6 +257,14 @@ public:
*/
SongPtr RemoveSong(Song *song) noexcept;
/**
* Recursively walk through the whole tree and set all
* `Song::in_playlist` fields to `false`.
*
* Caller must lock the #db_mutex.
*/
void ClearInPlaylist() noexcept;
/**
* Caller must lock the #db_mutex.
*/

View File

@ -515,6 +515,7 @@ UpdateWalk::Walk(Directory &root, const char *path, bool discard) noexcept
{
const ScopeDatabaseLock protect;
root.ClearInPlaylist();
PurgeDanglingFromPlaylists(root);
}

View File

@ -275,10 +275,8 @@ EventLoop::Run() noexcept
#endif
assert(IsInside());
assert(!quit);
#ifdef HAVE_THREADED_EVENT_LOOP
assert(!quit_injected);
assert(alive);
assert(alive || quit_injected);
assert(busy);
wake_event.Schedule(SocketEvent::READ);
@ -303,7 +301,7 @@ EventLoop::Run() noexcept
FlushClockCaches();
do {
while (!quit) {
again = false;
/* invoke timers */
@ -365,7 +363,7 @@ EventLoop::Run() noexcept
socket_event.Dispatch();
}
} while (!quit);
}
#ifdef HAVE_THREADED_EVENT_LOOP
#ifndef NDEBUG

View File

@ -463,7 +463,6 @@ CurlInputStream::InitEasy()
request->SetOption(CURLOPT_HTTP200ALIASES, http_200_aliases);
request->SetOption(CURLOPT_FOLLOWLOCATION, 1L);
request->SetOption(CURLOPT_MAXREDIRS, 5L);
request->SetOption(CURLOPT_FAILONERROR, 1L);
/* this option eliminates the probe request when
username/password are specified */

View File

@ -18,13 +18,13 @@ endif
conf.set('HAVE_MD5', crypto_md5_dep.found())
if libavutil_dep.found()
if ffmpeg_util_dep.found()
crypto_base64 = static_library(
'crypto_base64',
'Base64.cxx',
include_directories: inc,
dependencies: [
libavutil_dep,
ffmpeg_util_dep,
],
)

View File

@ -1,26 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-or-later
// Copyright The Music Player Daemon Project
#include "LogError.hxx"
#include "Domain.hxx"
#include "Log.hxx"
extern "C" {
#include <libavutil/error.h>
}
void
LogFfmpegError(int errnum)
{
char msg[256];
av_strerror(errnum, msg, sizeof(msg));
LogError(ffmpeg_domain, msg);
}
void
LogFfmpegError(int errnum, const char *prefix)
{
char msg[256];
av_strerror(errnum, msg, sizeof(msg));
FmtError(ffmpeg_domain, "{}: {}", prefix, msg);
}

View File

@ -1,13 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-or-later
// Copyright The Music Player Daemon Project
#ifndef MPD_FFMPEG_LOG_ERROR_HXX
#define MPD_FFMPEG_LOG_ERROR_HXX
void
LogFfmpegError(int errnum);
void
LogFfmpegError(int errnum, const char *prefix);
#endif

View File

@ -13,6 +13,30 @@ else
endif
conf.set('HAVE_LIBAVFILTER', libavfilter_dep.found())
if not libavutil_dep.found()
ffmpeg_util_dep = dependency('', required: false)
ffmpeg_dep = dependency('', required: false)
subdir_done()
endif
ffmpeg_util = static_library(
'ffmpeg_util',
'Interleave.cxx',
'Error.cxx',
include_directories: inc,
dependencies: [
fmt_dep,
libavutil_dep,
],
)
ffmpeg_util_dep = declare_dependency(
link_with: ffmpeg_util,
dependencies: [
libavutil_dep,
],
)
if not enable_ffmpeg
ffmpeg_dep = dependency('', required: false)
subdir_done()
@ -30,17 +54,16 @@ ffmpeg = static_library(
'ffmpeg',
'Init.cxx',
'Interleave.cxx',
'LogError.cxx',
'LogCallback.cxx',
'Error.cxx',
'Domain.cxx',
ffmpeg_sources,
include_directories: inc,
dependencies: [
ffmpeg_util_dep,
libavformat_dep,
libavcodec_dep,
libavfilter_dep,
libavutil_dep,
log_dep,
],
)
@ -48,9 +71,9 @@ ffmpeg = static_library(
ffmpeg_dep = declare_dependency(
link_with: ffmpeg,
dependencies: [
ffmpeg_util_dep,
libavformat_dep,
libavcodec_dep,
libavfilter_dep,
libavutil_dep,
],
)

View File

@ -6,6 +6,7 @@
#include "storage/StorageInterface.hxx"
#include "storage/FileInfo.hxx"
#include "storage/MemoryDirectoryReader.hxx"
#include "lib/curl/HttpStatusError.hxx"
#include "lib/curl/Init.hxx"
#include "lib/curl/Global.hxx"
#include "lib/curl/Slist.hxx"
@ -14,7 +15,6 @@
#include "lib/curl/Handler.hxx"
#include "lib/curl/Escape.hxx"
#include "lib/expat/ExpatParser.hxx"
#include "lib/fmt/RuntimeError.hxx"
#include "lib/fmt/ToBuffer.hxx"
#include "fs/Traits.hxx"
#include "event/InjectEvent.hxx"
@ -286,8 +286,9 @@ private:
/* virtual methods from CurlResponseHandler */
void OnHeaders(unsigned status, Curl::Headers &&headers) final {
if (status != 207)
throw FmtRuntimeError("Status {} from WebDAV server; expected \"207 Multi-Status\"",
status);
throw HttpStatusError(status,
FmtBuffer<80>("Status {} from WebDAV server; expected \"207 Multi-Status\"",
status));
if (!IsXmlContentType(headers))
throw std::runtime_error("Unexpected Content-Type from WebDAV server");

View File

@ -14,14 +14,17 @@ class ScopeExitGuard : F {
bool enabled = true;
public:
explicit ScopeExitGuard(F &&f):F(std::forward<F>(f)) {}
explicit ScopeExitGuard(F &&f) noexcept:F(std::forward<F>(f)) {}
ScopeExitGuard(ScopeExitGuard &&src)
:F(std::move(src)), enabled(src.enabled) {
src.enabled = false;
}
ScopeExitGuard(ScopeExitGuard &&src) noexcept
:F(std::move(src)),
enabled(std::exchange(src.enabled, false)) {}
~ScopeExitGuard() {
/* destructors are "noexcept" by default; this explicit
"noexcept" declaration allows the destructor to throw if
the function can throw; without this, a throwing function
would std::terminate() */
~ScopeExitGuard() noexcept(noexcept(std::declval<F>()())) {
if (enabled)
F::operator()();
}
@ -38,7 +41,7 @@ struct ScopeExitTag {
parantheses at the end of the expression AtScopeExit()
call */
template<typename F>
ScopeExitGuard<F> operator+(F &&f) {
ScopeExitGuard<F> operator+(F &&f) noexcept {
return ScopeExitGuard<F>(std::forward<F>(f));
}
};