From ae92f5c1565df815230d01af39a8978a682e63d7 Mon Sep 17 00:00:00 2001 From: emeric Date: Sun, 4 Jan 2026 00:07:43 +0100 Subject: [PATCH] Various build fixes, ref #802 --- .github/workflows/build-macos-basic.yml | 51 ++++++++ src/libs/core/include/core/Utils.hpp | 6 + .../steps/ScanStepCheckForRemovedFiles.cpp | 3 + .../impl/endpoints/MediaRetrieval.cpp | 2 +- .../subsonic/impl/endpoints/Transcoding.hpp | 2 +- .../transcoding/TranscodeDecisionTracker.hpp | 7 ++ .../subsonic/impl/payloads/ClientInfo.cpp | 5 +- src/libs/subsonic/test/TranscodeDecision.cpp | 119 ++++++++---------- 8 files changed, 127 insertions(+), 68 deletions(-) create mode 100644 .github/workflows/build-macos-basic.yml diff --git a/.github/workflows/build-macos-basic.yml b/.github/workflows/build-macos-basic.yml new file mode 100644 index 00000000..0a85d87a --- /dev/null +++ b/.github/workflows/build-macos-basic.yml @@ -0,0 +1,51 @@ +name: Basic Build (macOS) + +on: [pull_request] + +jobs: + build-macos: + runs-on: macos-14 + env: + PKG_CONFIG_PATH: /opt/homebrew/lib/pkgconfig:/opt/homebrew/share/pkgconfig + + steps: + - uses: actions/checkout@v4 + + - name: Install dependencies + run: | + brew update + brew install pkg-config cmake boost ffmpeg libconfig taglib libarchive xxhash pugixml googletest openssl git + + - name: Build and install Wt + run: | + WT_VERSION=4.12.1 + git clone https://github.com/emweb/wt.git /tmp/wt + cd /tmp/wt + git checkout ${WT_VERSION} + cmake -B build -S . \ + -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_INSTALL_PREFIX=/usr/local \ + -DBUILD_EXAMPLES=OFF \ + -DENABLE_LIBWTTEST=OFF \ + -DCONNECTOR_FCGI=OFF + cmake --build build --parallel 2 + sudo cmake --install build + + - name: Install Stb headers + run: | + git clone https://github.com/nothings/stb.git /opt/homebrew/include/stb + + - name: Configure LMS + run: | + export PKG_CONFIG_PATH="$(brew --prefix libarchive)/lib/pkgconfig:$PKG_CONFIG_PATH" + cmake -S . -B build \ + -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_UNITY_BUILD=ON \ + -DBUILD_TESTING=ON \ + -DSTB_IMAGE_INCLUDE_DIR=/opt/homebrew/include/stb + + - name: Build LMS + run: cmake --build build --parallel 2 + + - name: Test LMS + run: ctest --test-dir build --output-on-failure diff --git a/src/libs/core/include/core/Utils.hpp b/src/libs/core/include/core/Utils.hpp index 46430baa..8340c227 100644 --- a/src/libs/core/include/core/Utils.hpp +++ b/src/libs/core/include/core/Utils.hpp @@ -36,4 +36,10 @@ namespace lms::core::utils { using Ts::operator()...; }; + + template + overloads(Ts...) -> overloads; + + template + constexpr bool dependent_false_v{}; } // namespace lms::core::utils \ No newline at end of file diff --git a/src/libs/services/scanner/impl/steps/ScanStepCheckForRemovedFiles.cpp b/src/libs/services/scanner/impl/steps/ScanStepCheckForRemovedFiles.cpp index 2d71bde7..221f050f 100644 --- a/src/libs/services/scanner/impl/steps/ScanStepCheckForRemovedFiles.cpp +++ b/src/libs/services/scanner/impl/steps/ScanStepCheckForRemovedFiles.cpp @@ -50,6 +50,9 @@ namespace lms::scanner { IdType objectId; std::filesystem::path file; + + FileToCheck(IdType _objectId, const std::filesystem::path& _file) + : objectId{ _objectId }, file{ _file } {} }; template diff --git a/src/libs/subsonic/impl/endpoints/MediaRetrieval.cpp b/src/libs/subsonic/impl/endpoints/MediaRetrieval.cpp index 9f2db823..83467afd 100644 --- a/src/libs/subsonic/impl/endpoints/MediaRetrieval.cpp +++ b/src/libs/subsonic/impl/endpoints/MediaRetrieval.cpp @@ -52,7 +52,7 @@ namespace lms::api::subsonic { struct OutputFormat { - std::string name; + std::string_view name; core::media::Container container; core::media::Codec codec; }; diff --git a/src/libs/subsonic/impl/endpoints/Transcoding.hpp b/src/libs/subsonic/impl/endpoints/Transcoding.hpp index 67f52250..3165f49b 100644 --- a/src/libs/subsonic/impl/endpoints/Transcoding.hpp +++ b/src/libs/subsonic/impl/endpoints/Transcoding.hpp @@ -26,7 +26,7 @@ namespace lms::api::subsonic { - struct RequestContext; + class RequestContext; Response handleGetTranscodeDecision(RequestContext& context); void handleGetTranscodeStream(RequestContext& context, const Wt::Http::Request& request, Wt::Http::Response& response); diff --git a/src/libs/subsonic/impl/endpoints/transcoding/TranscodeDecisionTracker.hpp b/src/libs/subsonic/impl/endpoints/transcoding/TranscodeDecisionTracker.hpp index 5da0a4c8..00496e29 100644 --- a/src/libs/subsonic/impl/endpoints/transcoding/TranscodeDecisionTracker.hpp +++ b/src/libs/subsonic/impl/endpoints/transcoding/TranscodeDecisionTracker.hpp @@ -43,6 +43,13 @@ namespace lms::api::subsonic Clock::time_point addedTimePoint; AudioFileId audioFileId; StreamDetails targetStreamInfo; + + Entry(Clock::time_point _addedTimePoint, AudioFileId _audioFileId, const StreamDetails& _targetStreamInfo) + : addedTimePoint{ _addedTimePoint } + , audioFileId{ _audioFileId } + , targetStreamInfo{ _targetStreamInfo } + { + } }; virtual core::UUID add(AudioFileId audioFileId, const StreamDetails& targetStreamInfo) = 0; diff --git a/src/libs/subsonic/impl/payloads/ClientInfo.cpp b/src/libs/subsonic/impl/payloads/ClientInfo.cpp index 01c65a34..97bfd606 100644 --- a/src/libs/subsonic/impl/payloads/ClientInfo.cpp +++ b/src/libs/subsonic/impl/payloads/ClientInfo.cpp @@ -26,6 +26,7 @@ #include #include "core/String.hpp" +#include "core/Utils.hpp" #include "SubsonicResponse.hpp" @@ -61,7 +62,7 @@ namespace lms::api::subsonic } else { - static_assert(false, "Unhandled type"); + static_assert(core::utils::dependent_false_v, "Unhandled type"); } return static_cast(value); @@ -105,7 +106,7 @@ namespace lms::api::subsonic } else { - static_assert(false, "Unhandled type"); + static_assert(core::utils::dependent_false_v, "Unhandled type"); } res.emplace_back(static_cast(item)); diff --git a/src/libs/subsonic/test/TranscodeDecision.cpp b/src/libs/subsonic/test/TranscodeDecision.cpp index e9db7dcf..c8fa5ed0 100644 --- a/src/libs/subsonic/test/TranscodeDecision.cpp +++ b/src/libs/subsonic/test/TranscodeDecision.cpp @@ -100,9 +100,9 @@ namespace lms::api::subsonic .platform = "TestPlatform", .maxAudioBitrate = 512'000, .maxTranscodingAudioBitrate = 256'000, - .directPlayProfiles = { { + .directPlayProfiles = { { .containers = { "mp3" }, .audioCodecs = { "mp3" }, .protocols = { "http" }, .maxAudioChannels = 2 }, - } }, + }, .transcodingProfiles = { { .container = "mp3", .audioCodec = "mp3", .protocol = "http", .maxAudioChannels = 2 }, }, @@ -130,9 +130,9 @@ namespace lms::api::subsonic .platform = "TestPlatform", .maxAudioBitrate = 512'000, .maxTranscodingAudioBitrate = 96'000, - .directPlayProfiles = { { + .directPlayProfiles = { { .containers = { "mp3" }, .audioCodecs = { "mp3" }, .protocols = { "http" }, .maxAudioChannels = 2 }, - } }, + }, .transcodingProfiles = { { .container = "mp3", .audioCodec = "mp3", .protocol = "http", .maxAudioChannels = 2 }, }, @@ -160,9 +160,9 @@ namespace lms::api::subsonic .platform = "TestPlatform", .maxAudioBitrate = 96'000, .maxTranscodingAudioBitrate = 96'000, - .directPlayProfiles = { { + .directPlayProfiles = { { .containers = { "mp3" }, .audioCodecs = { "mp3" }, .protocols = { "http" }, .maxAudioChannels = 2 }, - } }, + }, .transcodingProfiles = { { .container = "mp3", .audioCodec = "mp3", .protocol = "http", .maxAudioChannels = 2 }, }, @@ -190,9 +190,9 @@ namespace lms::api::subsonic .platform = "TestPlatform", .maxAudioBitrate = 96'000, .maxTranscodingAudioBitrate = 96'000, - .directPlayProfiles = { { + .directPlayProfiles = { { .containers = { "mp3" }, .audioCodecs = { "mp3" }, .protocols = { "http" }, .maxAudioChannels = 2 }, - } }, + }, .transcodingProfiles = { { .container = "mp3", .audioCodec = "mp3", .protocol = "http", .maxAudioChannels = 2 }, }, @@ -220,9 +220,9 @@ namespace lms::api::subsonic .platform = "TestPlatform", .maxAudioBitrate = 320'000, .maxTranscodingAudioBitrate = 320'000, - .directPlayProfiles = { { + .directPlayProfiles = { { .containers = { "mp3" }, .audioCodecs = { "mp3" }, .protocols = { "http" }, .maxAudioChannels = 2 }, - } }, + }, .transcodingProfiles = { { .container = "mp3", .audioCodec = "mp3", .protocol = "http", .maxAudioChannels = 2 }, }, @@ -250,7 +250,7 @@ namespace lms::api::subsonic .platform = "TestPlatform", .maxAudioBitrate = 320'000, .maxTranscodingAudioBitrate = 320'000, - .directPlayProfiles = { { { .containers = { "mp3" }, .audioCodecs = { "mp3" }, .protocols = { "http" }, .maxAudioChannels = 2 } } }, + .directPlayProfiles = { { .containers = { "mp3" }, .audioCodecs = { "mp3" }, .protocols = { "http" }, .maxAudioChannels = 2 } }, .transcodingProfiles = { { .container = "mp3", .audioCodec = "mp3", .protocol = "http", .maxAudioChannels = 2 } }, .codecProfiles = { { .type = "AudioCodec", .name = "mp3", .limitations = {} } }, }, @@ -274,9 +274,9 @@ namespace lms::api::subsonic .platform = "TestPlatform", .maxAudioBitrate = 320'000, .maxTranscodingAudioBitrate = 320'000, - .directPlayProfiles = { { + .directPlayProfiles = { { .containers = { "mp3" }, .audioCodecs = { "mp3" }, .protocols = { "http" }, .maxAudioChannels = std::nullopt }, - } }, + }, .transcodingProfiles = { { .container = "mp3", .audioCodec = "mp3", .protocol = "http", .maxAudioChannels = std::nullopt }, }, @@ -302,9 +302,9 @@ namespace lms::api::subsonic .platform = "TestPlatform", .maxAudioBitrate = 320'000, .maxTranscodingAudioBitrate = 320'000, - .directPlayProfiles = { { + .directPlayProfiles = { { .containers = { "mp3" }, .audioCodecs = { "mp3" }, .protocols = { "http" }, .maxAudioChannels = std::nullopt }, - } }, + }, .transcodingProfiles = { { .container = "mp3", .audioCodec = "mp3", .protocol = "http", .maxAudioChannels = std::nullopt }, }, @@ -330,9 +330,9 @@ namespace lms::api::subsonic .platform = "TestPlatform", .maxAudioBitrate = 1'000'000, .maxTranscodingAudioBitrate = 320'000, - .directPlayProfiles = { { + .directPlayProfiles = { { .containers = { "mp3" }, .audioCodecs = { "mp3" }, .protocols = { "http" }, .maxAudioChannels = std::nullopt }, - } }, + }, .transcodingProfiles = { { .container = "mp3", .audioCodec = "mp3", .protocol = "http", .maxAudioChannels = std::nullopt }, }, @@ -356,7 +356,6 @@ namespace lms::api::subsonic .clientInfo = { .name = "TestClient", .platform = "TestPlatform", .maxAudioBitrate = std::nullopt, .maxTranscodingAudioBitrate = std::nullopt, .directPlayProfiles = { { { .containers = { "mp3" }, .audioCodecs = { "mp3" }, .protocols = { "http" }, .maxAudioChannels = std::nullopt }, } }, - .transcodingProfiles = { { .container = "mp3", .audioCodec = "mp3", .protocol = "http", .maxAudioChannels = std::nullopt }, }, @@ -381,9 +380,9 @@ namespace lms::api::subsonic .platform = "TestPlatform", .maxAudioBitrate = 1'000'000, .maxTranscodingAudioBitrate = 320'000, - .directPlayProfiles = { { + .directPlayProfiles = { { .containers = { "mp4", "flac", "mp3" }, .audioCodecs = {}, .protocols = {}, .maxAudioChannels = std::nullopt }, - } }, + }, .transcodingProfiles = {}, .codecProfiles = {}, }, @@ -407,9 +406,9 @@ namespace lms::api::subsonic .platform = "TestPlatform", .maxAudioBitrate = 1'000'000, .maxTranscodingAudioBitrate = 320'000, - .directPlayProfiles = { { + .directPlayProfiles = { { .containers = {}, .audioCodecs = { "mp3" }, .protocols = {}, .maxAudioChannels = std::nullopt }, - } }, + }, .transcodingProfiles = {}, .codecProfiles = {}, }, @@ -433,10 +432,10 @@ namespace lms::api::subsonic .platform = "Android", .maxAudioBitrate = 320'000, .maxTranscodingAudioBitrate = 320'000, - .directPlayProfiles = { { + .directPlayProfiles = { { .containers = { "flac" }, .audioCodecs = { "flac" }, .protocols = {}, .maxAudioChannels = 32 }, - } }, - .transcodingProfiles = { { { .container = "ogg", .audioCodec = "opus", .protocol = "http", .maxAudioChannels = std::nullopt }, { .container = "mp3", .audioCodec = "mp3", .protocol = "http", .maxAudioChannels = 2 } } }, + }, + .transcodingProfiles = { { .container = "ogg", .audioCodec = "opus", .protocol = "http", .maxAudioChannels = std::nullopt }, { .container = "mp3", .audioCodec = "mp3", .protocol = "http", .maxAudioChannels = 2 } }, .codecProfiles = {}, }, .source = { @@ -459,22 +458,20 @@ namespace lms::api::subsonic .platform = "UPnP", .maxAudioBitrate = 1'000'000, .maxTranscodingAudioBitrate = 1'000'000, - .directPlayProfiles = { { + .directPlayProfiles = { { .containers = { "flac" }, .audioCodecs = {}, .protocols = {}, .maxAudioChannels = std::nullopt }, { .containers = { "mp3" }, .audioCodecs = { "mp3" }, .protocols = {}, .maxAudioChannels = std::nullopt }, { .containers = { "m4a", "mp4" }, .audioCodecs = { "aac" }, .protocols = {}, .maxAudioChannels = std::nullopt }, - } }, - .transcodingProfiles = { { + }, + .transcodingProfiles = { { .container = "flac", .audioCodec = "flac", .protocol = "http", .maxAudioChannels = 6 }, { .container = "aac", .audioCodec = "aac", .protocol = "http", .maxAudioChannels = 6 }, { .container = "mp3", .audioCodec = "mp3", .protocol = "http", .maxAudioChannels = 2 }, - } }, + }, .codecProfiles = { - { - { .type = "AudioCodec", .name = "flac", .limitations = { { .name = Limitation::Type::AudioSamplerate, .comparison = Limitation::ComparisonOperator::LessThanEqual, .values = { "48000" }, .required = true } } }, - { .type = "AudioCodec", .name = "vorbis", .limitations = { { .name = Limitation::Type::AudioSamplerate, .comparison = Limitation::ComparisonOperator::LessThanEqual, .values = { "48000" }, .required = true } } }, - { .type = "AudioCodec", .name = "opus", .limitations = { { .name = Limitation::Type::AudioSamplerate, .comparison = Limitation::ComparisonOperator::LessThanEqual, .values = { "48000" }, .required = true } } }, - }, + { .type = "AudioCodec", .name = "flac", .limitations = { { .name = Limitation::Type::AudioSamplerate, .comparison = Limitation::ComparisonOperator::LessThanEqual, .values = { "48000" }, .required = true } } }, + { .type = "AudioCodec", .name = "vorbis", .limitations = { { .name = Limitation::Type::AudioSamplerate, .comparison = Limitation::ComparisonOperator::LessThanEqual, .values = { "48000" }, .required = true } } }, + { .type = "AudioCodec", .name = "opus", .limitations = { { .name = Limitation::Type::AudioSamplerate, .comparison = Limitation::ComparisonOperator::LessThanEqual, .values = { "48000" }, .required = true } } }, }, }, .source = { @@ -497,23 +494,21 @@ namespace lms::api::subsonic .platform = "UPnP", .maxAudioBitrate = std::nullopt, .maxTranscodingAudioBitrate = std::nullopt, - .directPlayProfiles = { { + .directPlayProfiles = { { .containers = { "opus", "ogg", "oga", "aac", "webma", "webm", "wav", "flac", "mka" }, .audioCodecs = {}, .protocols = {}, .maxAudioChannels = std::nullopt }, { .containers = { "mp3" }, .audioCodecs = { "mp3" }, .protocols = {}, .maxAudioChannels = std::nullopt }, { .containers = { "m4a", "mp4" }, .audioCodecs = { "aac" }, .protocols = {}, .maxAudioChannels = std::nullopt }, - } }, - .transcodingProfiles = { { + }, + .transcodingProfiles = { { .container = "flac", .audioCodec = "flac", .protocol = "http", .maxAudioChannels = 6 }, { .container = "mp4", .audioCodec = "aac", .protocol = "http", .maxAudioChannels = 6 }, { .container = "aac", .audioCodec = "aac", .protocol = "http", .maxAudioChannels = 6 }, { .container = "mp3", .audioCodec = "mp3", .protocol = "http", .maxAudioChannels = 2 }, - } }, + }, .codecProfiles = { - { - { .type = "AudioCodec", .name = "flac", .limitations = { { .name = Limitation::Type::AudioSamplerate, .comparison = Limitation::ComparisonOperator::LessThanEqual, .values = { "48000" }, .required = true } } }, - { .type = "AudioCodec", .name = "vorbis", .limitations = { { .name = Limitation::Type::AudioSamplerate, .comparison = Limitation::ComparisonOperator::LessThanEqual, .values = { "48000" }, .required = true } } }, - { .type = "AudioCodec", .name = "opus", .limitations = { { .name = Limitation::Type::AudioSamplerate, .comparison = Limitation::ComparisonOperator::LessThanEqual, .values = { "48000" }, .required = true } } }, - }, + { .type = "AudioCodec", .name = "flac", .limitations = { { .name = Limitation::Type::AudioSamplerate, .comparison = Limitation::ComparisonOperator::LessThanEqual, .values = { "48000" }, .required = true } } }, + { .type = "AudioCodec", .name = "vorbis", .limitations = { { .name = Limitation::Type::AudioSamplerate, .comparison = Limitation::ComparisonOperator::LessThanEqual, .values = { "48000" }, .required = true } } }, + { .type = "AudioCodec", .name = "opus", .limitations = { { .name = Limitation::Type::AudioSamplerate, .comparison = Limitation::ComparisonOperator::LessThanEqual, .values = { "48000" }, .required = true } } }, }, }, .source = { @@ -536,22 +531,20 @@ namespace lms::api::subsonic .platform = "UPnP", .maxAudioBitrate = 1'000'000, .maxTranscodingAudioBitrate = 1'000'000, - .directPlayProfiles = { { + .directPlayProfiles = { { .containers = { "flac" }, .audioCodecs = {}, .protocols = {}, .maxAudioChannels = std::nullopt }, { .containers = { "mp3" }, .audioCodecs = { "mp3" }, .protocols = {}, .maxAudioChannels = std::nullopt }, { .containers = { "m4a", "mp4" }, .audioCodecs = { "aac" }, .protocols = {}, .maxAudioChannels = std::nullopt }, - } }, - .transcodingProfiles = { { + }, + .transcodingProfiles = { { .container = "flac", .audioCodec = "flac", .protocol = "http", .maxAudioChannels = 6 }, { .container = "aac", .audioCodec = "aac", .protocol = "http", .maxAudioChannels = 6 }, { .container = "mp3", .audioCodec = "mp3", .protocol = "http", .maxAudioChannels = 2 }, - } }, + }, .codecProfiles = { - { - { .type = "AudioCodec", .name = "flac", .limitations = { { .name = Limitation::Type::AudioSamplerate, .comparison = Limitation::ComparisonOperator::LessThanEqual, .values = { "48000" }, .required = true } } }, - { .type = "AudioCodec", .name = "vorbis", .limitations = { { .name = Limitation::Type::AudioSamplerate, .comparison = Limitation::ComparisonOperator::LessThanEqual, .values = { "48000" }, .required = true } } }, - { .type = "AudioCodec", .name = "opus", .limitations = { { .name = Limitation::Type::AudioSamplerate, .comparison = Limitation::ComparisonOperator::LessThanEqual, .values = { "48000" }, .required = true } } }, - }, + { .type = "AudioCodec", .name = "flac", .limitations = { { .name = Limitation::Type::AudioSamplerate, .comparison = Limitation::ComparisonOperator::LessThanEqual, .values = { "48000" }, .required = true } } }, + { .type = "AudioCodec", .name = "vorbis", .limitations = { { .name = Limitation::Type::AudioSamplerate, .comparison = Limitation::ComparisonOperator::LessThanEqual, .values = { "48000" }, .required = true } } }, + { .type = "AudioCodec", .name = "opus", .limitations = { { .name = Limitation::Type::AudioSamplerate, .comparison = Limitation::ComparisonOperator::LessThanEqual, .values = { "48000" }, .required = true } } }, }, }, .source = { @@ -574,22 +567,20 @@ namespace lms::api::subsonic .platform = "UPnP", .maxAudioBitrate = 1'000'000, .maxTranscodingAudioBitrate = 1'000'000, - .directPlayProfiles = { { + .directPlayProfiles = { { .containers = { "flac" }, .audioCodecs = {}, .protocols = {}, .maxAudioChannels = std::nullopt }, { .containers = { "mp3" }, .audioCodecs = { "mp3" }, .protocols = {}, .maxAudioChannels = std::nullopt }, { .containers = { "m4a", "mp4" }, .audioCodecs = { "aac" }, .protocols = {}, .maxAudioChannels = std::nullopt }, - } }, - .transcodingProfiles = { { + }, + .transcodingProfiles = { { .container = "flac", .audioCodec = "flac", .protocol = "http", .maxAudioChannels = 6 }, { .container = "aac", .audioCodec = "aac", .protocol = "http", .maxAudioChannels = 6 }, { .container = "mp3", .audioCodec = "mp3", .protocol = "http", .maxAudioChannels = 2 }, - } }, + }, .codecProfiles = { - { - { .type = "AudioCodec", .name = "flac", .limitations = { { .name = Limitation::Type::AudioSamplerate, .comparison = Limitation::ComparisonOperator::LessThanEqual, .values = { "48000" }, .required = true } } }, - { .type = "AudioCodec", .name = "vorbis", .limitations = { { .name = Limitation::Type::AudioSamplerate, .comparison = Limitation::ComparisonOperator::LessThanEqual, .values = { "48000" }, .required = true } } }, - { .type = "AudioCodec", .name = "opus", .limitations = { { .name = Limitation::Type::AudioSamplerate, .comparison = Limitation::ComparisonOperator::LessThanEqual, .values = { "48000" }, .required = true } } }, - }, + { .type = "AudioCodec", .name = "flac", .limitations = { { .name = Limitation::Type::AudioSamplerate, .comparison = Limitation::ComparisonOperator::LessThanEqual, .values = { "48000" }, .required = true } } }, + { .type = "AudioCodec", .name = "vorbis", .limitations = { { .name = Limitation::Type::AudioSamplerate, .comparison = Limitation::ComparisonOperator::LessThanEqual, .values = { "48000" }, .required = true } } }, + { .type = "AudioCodec", .name = "opus", .limitations = { { .name = Limitation::Type::AudioSamplerate, .comparison = Limitation::ComparisonOperator::LessThanEqual, .values = { "48000" }, .required = true } } }, }, }, .source = { @@ -612,11 +603,11 @@ namespace lms::api::subsonic .platform = "TestPlatform", .maxAudioBitrate = 512'000, .maxTranscodingAudioBitrate = 96'000, - .directPlayProfiles = { { + .directPlayProfiles = { { .containers = { "mp3" }, .audioCodecs = { "mp3" }, .protocols = {}, .maxAudioChannels = 2 }, - } }, + }, .transcodingProfiles = { - { { .container = "mp3", .audioCodec = "mp3", .protocol = { "http" }, .maxAudioChannels = 2 } }, + { .container = "mp3", .audioCodec = "mp3", .protocol = { "http" }, .maxAudioChannels = 2 }, }, .codecProfiles = { { .type = "AudioCodec", .name = "mp3", .limitations = { { .name = Limitation::Type::AudioBitrate, .comparison = Limitation::ComparisonOperator::LessThanEqual, .values = { "96000" }, .required = true },