Merge tag 'v0.23.6'
release v0.23.6
This commit is contained in:
@@ -21,12 +21,16 @@
|
||||
#include "TagStream.hxx"
|
||||
#include "TagFile.hxx"
|
||||
#include "tag/Generic.hxx"
|
||||
#include "song/LightSong.hxx"
|
||||
#include "db/Interface.hxx"
|
||||
#include "storage/StorageInterface.hxx"
|
||||
#include "client/Client.hxx"
|
||||
#include "protocol/Ack.hxx"
|
||||
#include "fs/AllocatedPath.hxx"
|
||||
#include "input/InputStream.hxx"
|
||||
#include "util/Compiler.h"
|
||||
#include "util/ScopeExit.hxx"
|
||||
#include "util/StringCompare.hxx"
|
||||
#include "util/UriExtract.hxx"
|
||||
#include "LocateUri.hxx"
|
||||
|
||||
@@ -51,10 +55,67 @@ TagScanFile(const Path path_fs, TagHandler &handler)
|
||||
ScanGenericTags(path_fs, handler);
|
||||
}
|
||||
|
||||
#ifdef ENABLE_DATABASE
|
||||
|
||||
/**
|
||||
* Collapse "../" prefixes in a URI relative to the specified base
|
||||
* URI.
|
||||
*/
|
||||
static std::string
|
||||
ResolveUri(std::string_view base, const char *relative)
|
||||
{
|
||||
while (true) {
|
||||
const char *rest = StringAfterPrefix(relative, "../");
|
||||
if (rest == nullptr)
|
||||
break;
|
||||
|
||||
if (base == ".")
|
||||
throw ProtocolError(ACK_ERROR_NO_EXIST, "Bad real URI");
|
||||
|
||||
base = PathTraitsUTF8::GetParent(base);
|
||||
relative = rest;
|
||||
}
|
||||
|
||||
return PathTraitsUTF8::Build(base, relative);
|
||||
}
|
||||
|
||||
/**
|
||||
* Look up the specified song in the database and return its
|
||||
* (resolved) "real" URI.
|
||||
*/
|
||||
static std::string
|
||||
GetRealSongUri(Client &client, std::string_view uri)
|
||||
{
|
||||
const auto &db = client.GetDatabaseOrThrow();
|
||||
|
||||
const auto *song = db.GetSong(uri);
|
||||
if (song == nullptr)
|
||||
throw ProtocolError(ACK_ERROR_NO_EXIST, "No such song");
|
||||
|
||||
AtScopeExit(&db, song) { db.ReturnSong(song); };
|
||||
|
||||
if (song->real_uri == nullptr)
|
||||
return {};
|
||||
|
||||
return ResolveUri(PathTraitsUTF8::GetParent(uri), song->real_uri);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static void
|
||||
TagScanDatabase(Client &client, const char *uri, TagHandler &handler)
|
||||
{
|
||||
#ifdef ENABLE_DATABASE
|
||||
const auto real_uri = GetRealSongUri(client, uri);
|
||||
|
||||
if (!real_uri.empty()) {
|
||||
uri = real_uri.c_str();
|
||||
|
||||
// TODO: support absolute paths?
|
||||
if (uri_has_scheme(uri))
|
||||
return TagScanStream(uri, handler);
|
||||
}
|
||||
|
||||
const Storage *storage = client.GetStorage();
|
||||
if (storage == nullptr) {
|
||||
#else
|
||||
|
@@ -160,8 +160,7 @@ find_stream_art(std::string_view directory, Mutex &mutex)
|
||||
static constexpr auto art_names = std::array {
|
||||
"cover.png",
|
||||
"cover.jpg",
|
||||
"cover.tiff",
|
||||
"cover.bmp",
|
||||
"cover.webp",
|
||||
};
|
||||
|
||||
for(const auto name : art_names) {
|
||||
|
@@ -21,6 +21,7 @@
|
||||
#define __STDC_CONSTANT_MACROS
|
||||
|
||||
#include "FfmpegIo.hxx"
|
||||
#include "libavutil/mem.h"
|
||||
#include "../DecoderAPI.hxx"
|
||||
#include "input/InputStream.hxx"
|
||||
|
||||
@@ -35,7 +36,11 @@ AvioStream::~AvioStream()
|
||||
inline int
|
||||
AvioStream::Read(void *dest, int size)
|
||||
{
|
||||
return decoder_read(client, input, dest, size);
|
||||
const auto nbytes = decoder_read(client, input, dest, size);
|
||||
if (nbytes == 0)
|
||||
return AVERROR_EOF;
|
||||
|
||||
return nbytes;
|
||||
}
|
||||
|
||||
inline int64_t
|
||||
|
@@ -1,14 +0,0 @@
|
||||
Index: libnfs-libnfs-4.0.0/include/win32/win32_compat.h
|
||||
===================================================================
|
||||
--- libnfs-libnfs-4.0.0.orig/include/win32/win32_compat.h
|
||||
+++ libnfs-libnfs-4.0.0/include/win32/win32_compat.h
|
||||
@@ -133,7 +133,9 @@ struct pollfd {
|
||||
|
||||
/* Wrapper macros to call misc. functions win32 is missing */
|
||||
#define poll(x, y, z) win32_poll(x, y, z)
|
||||
+#ifndef __MINGW32__
|
||||
#define snprintf sprintf_s
|
||||
+#endif
|
||||
#define inet_pton(x,y,z) win32_inet_pton(x,y,z)
|
||||
#define open(x, y, z) _open(x, y, z)
|
||||
#ifndef lseek
|
@@ -1 +0,0 @@
|
||||
no_sprintf_s
|
@@ -1,4 +1,11 @@
|
||||
libflac_dep = dependency('flac', version: '>= 1.2', required: get_option('flac'))
|
||||
|
||||
if is_windows
|
||||
# Our Windows build generates a static libFLAC build
|
||||
libflac_dep = declare_dependency(compile_args: '-DFLAC__NO_DLL',
|
||||
dependencies: libflac_dep)
|
||||
endif
|
||||
|
||||
libopus_dep = dependency('opus', required: get_option('opus'))
|
||||
|
||||
if get_option('tremor').enabled()
|
||||
|
@@ -336,6 +336,8 @@ PipeWireOutput::Enable()
|
||||
throw MakeErrno("pw_thread_loop_new() failed");
|
||||
|
||||
pw_thread_loop_start(thread_loop);
|
||||
|
||||
stream = nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
|
@@ -471,6 +471,16 @@ try {
|
||||
}
|
||||
|
||||
UINT32 write_in_frames = buffer_size_in_frames;
|
||||
DWORD mode = 0;
|
||||
AtScopeExit(&) {
|
||||
render_client->ReleaseBuffer(write_in_frames, mode);
|
||||
|
||||
if (!started) {
|
||||
Start(client);
|
||||
started = true;
|
||||
}
|
||||
};
|
||||
|
||||
if (!is_exclusive) {
|
||||
UINT32 data_in_frames =
|
||||
GetCurrentPaddingFrames(client);
|
||||
@@ -481,7 +491,6 @@ try {
|
||||
}
|
||||
|
||||
BYTE *data;
|
||||
DWORD mode = 0;
|
||||
|
||||
if (HRESULT result =
|
||||
render_client->GetBuffer(write_in_frames, &data);
|
||||
@@ -489,15 +498,6 @@ try {
|
||||
throw MakeHResultError(result, "Failed to get buffer");
|
||||
}
|
||||
|
||||
AtScopeExit(&) {
|
||||
render_client->ReleaseBuffer(write_in_frames, mode);
|
||||
|
||||
if (!started) {
|
||||
Start(client);
|
||||
started = true;
|
||||
}
|
||||
};
|
||||
|
||||
const UINT32 write_size = write_in_frames * frame_size;
|
||||
UINT32 new_data_size = 0;
|
||||
new_data_size = spsc_buffer.pop(data, write_size);
|
||||
|
Reference in New Issue
Block a user