Minor cleanup

This commit is contained in:
emeric
2025-12-06 23:44:57 +01:00
parent 22ed424745
commit 66e4f9ef92
12 changed files with 91 additions and 92 deletions
+16 -16
View File
@@ -31,7 +31,7 @@
namespace lms::core::stringUtils namespace lms::core::stringUtils
{ {
namespace details namespace detail
{ {
constexpr std::pair<char, std::string_view> jsEscapeChars[]{ constexpr std::pair<char, std::string_view> jsEscapeChars[]{
{ '\\', "\\\\" }, { '\\', "\\\\" },
@@ -203,7 +203,7 @@ namespace lms::core::stringUtils
return std::distance(std::cbegin(months), str) + 1; return std::distance(std::cbegin(months), str) + 1;
} }
} // namespace details } // namespace detail
template<> template<>
std::optional<std::string> readAs(std::string_view str) std::optional<std::string> readAs(std::string_view str)
@@ -240,32 +240,32 @@ namespace lms::core::stringUtils
std::vector<std::string_view> splitString(std::string_view str, std::span<const std::string_view> separators) std::vector<std::string_view> splitString(std::string_view str, std::span<const std::string_view> separators)
{ {
return details::splitString(str, separators); return detail::splitString(str, separators);
} }
std::vector<std::string_view> splitString(std::string_view str, std::span<const std::string> separators) std::vector<std::string_view> splitString(std::string_view str, std::span<const std::string> separators)
{ {
return details::splitString(str, separators); return detail::splitString(str, separators);
} }
std::string joinStrings(std::span<const std::string_view> strings, std::string_view delimiter) std::string joinStrings(std::span<const std::string_view> strings, std::string_view delimiter)
{ {
return details::joinStrings(strings, delimiter); return detail::joinStrings(strings, delimiter);
} }
std::string joinStrings(std::span<const std::string> strings, std::string_view delimiter) std::string joinStrings(std::span<const std::string> strings, std::string_view delimiter)
{ {
return details::joinStrings(strings, delimiter); return detail::joinStrings(strings, delimiter);
} }
std::string joinStrings(std::span<const std::string> strings, char delimiter) std::string joinStrings(std::span<const std::string> strings, char delimiter)
{ {
return details::joinStrings(strings, std::string_view{ &delimiter, 1 }); return detail::joinStrings(strings, std::string_view{ &delimiter, 1 });
} }
std::string joinStrings(std::span<const std::string_view> strings, char delimiter) std::string joinStrings(std::span<const std::string_view> strings, char delimiter)
{ {
return details::joinStrings(strings, std::string_view{ &delimiter, 1 }); return detail::joinStrings(strings, std::string_view{ &delimiter, 1 });
} }
std::string escapeAndJoinStrings(std::span<const std::string_view> strings, char delimiter, char escapeChar) std::string escapeAndJoinStrings(std::span<const std::string_view> strings, char delimiter, char escapeChar)
@@ -434,32 +434,32 @@ namespace lms::core::stringUtils
std::string jsEscape(std::string_view str) std::string jsEscape(std::string_view str)
{ {
return details::escape(str, details::jsEscapeChars); return detail::escape(str, detail::jsEscapeChars);
} }
void writeJSEscapedString(std::ostream& os, std::string_view str) void writeJSEscapedString(std::ostream& os, std::string_view str)
{ {
details::writeEscapedString(os, str, details::jsEscapeChars); detail::writeEscapedString(os, str, detail::jsEscapeChars);
} }
std::string jsonEscape(std::string_view str) std::string jsonEscape(std::string_view str)
{ {
return details::escape(str, details::jsonEscapeChars); return detail::escape(str, detail::jsonEscapeChars);
} }
void writeJsonEscapedString(std::ostream& os, std::string_view str) void writeJsonEscapedString(std::ostream& os, std::string_view str)
{ {
details::writeEscapedString(os, str, details::jsonEscapeChars); detail::writeEscapedString(os, str, detail::jsonEscapeChars);
} }
std::string xmlEscape(std::string_view str) std::string xmlEscape(std::string_view str)
{ {
return details::escape(str, details::xmlEscapeChars); return detail::escape(str, detail::xmlEscapeChars);
} }
void writeXmlEscapedString(std::ostream& os, std::string_view str) void writeXmlEscapedString(std::ostream& os, std::string_view str)
{ {
details::writeEscapedString(os, str, details::xmlEscapeChars); detail::writeEscapedString(os, str, detail::xmlEscapeChars);
} }
std::string escapeString(std::string_view str, std::string_view charsToEscape, char escapeChar) std::string escapeString(std::string_view str, std::string_view charsToEscape, char escapeChar)
@@ -611,11 +611,11 @@ namespace lms::core::stringUtils
timeStr += ":00"; timeStr += ":00";
// Normalize zone // Normalize zone
const std::optional<std::chrono::minutes> offset{ details::getRFC822ZoneOffset(zoneStr) }; const std::optional<std::chrono::minutes> offset{ detail::getRFC822ZoneOffset(zoneStr) };
if (!offset) if (!offset)
return {}; return {};
std::optional<unsigned> month{ details::getRFC822Month(monthStr) }; std::optional<unsigned> month{ detail::getRFC822Month(monthStr) };
if (!month) if (!month)
return {}; return {};
+3 -3
View File
@@ -23,7 +23,7 @@
namespace lms::core namespace lms::core
{ {
namespace details namespace detail
{ {
template<int... Is> template<int... Is>
struct Seq struct Seq
@@ -45,11 +45,11 @@ namespace lms::core
{ {
auto l = { (f(std::get<Is>(t)), 0)... }; auto l = { (f(std::get<Is>(t)), 0)... };
} }
} // namespace details } // namespace detail
template<typename... Ts, typename Func> template<typename... Ts, typename Func>
void forEachTypeInTuple(std::tuple<Ts...> const& t, Func f) void forEachTypeInTuple(std::tuple<Ts...> const& t, Func f)
{ {
details::forEachTypeInTuple(t, f, details::GenSeq<sizeof...(Ts)>()); detail::forEachTypeInTuple(t, f, detail::GenSeq<sizeof...(Ts)>());
} }
} // namespace lms::core } // namespace lms::core
+6 -6
View File
@@ -42,7 +42,7 @@ namespace lms::db::utils
Wt::WDateTime normalizeDateTime(const Wt::WDateTime& dateTime); Wt::WDateTime normalizeDateTime(const Wt::WDateTime& dateTime);
namespace details namespace detail
{ {
template<typename Query> template<typename Query>
void recordQueryPlanIfNeeded(const Query& query) void recordQueryPlanIfNeeded(const Query& query)
@@ -50,7 +50,7 @@ namespace lms::db::utils
if (IQueryPlanRecorder * recorder{ core::Service<IQueryPlanRecorder>::get() }) if (IQueryPlanRecorder * recorder{ core::Service<IQueryPlanRecorder>::get() })
static_cast<QueryPlanRecorder*>(recorder)->recordQueryPlanIfNeeded(query.session(), query.asString()); static_cast<QueryPlanRecorder*>(recorder)->recordQueryPlanIfNeeded(query.session(), query.asString());
} }
} // namespace details } // namespace detail
template<typename Query> template<typename Query>
void applyRange(Query& query, std::optional<Range> range) void applyRange(Query& query, std::optional<Range> range)
@@ -100,7 +100,7 @@ namespace lms::db::utils
template<typename Query, typename UnaryFunc> template<typename Query, typename UnaryFunc>
void forEachQueryResult(const Query& query, UnaryFunc&& func) void forEachQueryResult(const Query& query, UnaryFunc&& func)
{ {
details::recordQueryPlanIfNeeded(query); detail::recordQueryPlanIfNeeded(query);
LMS_SCOPED_TRACE_DETAILED_WITH_ARG("Database", "ForEachQueryResult", "Query", query.asString()); LMS_SCOPED_TRACE_DETAILED_WITH_ARG("Database", "ForEachQueryResult", "Query", query.asString());
@@ -110,7 +110,7 @@ namespace lms::db::utils
template<typename T, typename Query> template<typename T, typename Query>
std::vector<T> fetchQueryResults(const Query& query) std::vector<T> fetchQueryResults(const Query& query)
{ {
details::recordQueryPlanIfNeeded(query); detail::recordQueryPlanIfNeeded(query);
LMS_SCOPED_TRACE_DETAILED_WITH_ARG("Database", "FetchQueryResults", "Query", query.asString()); LMS_SCOPED_TRACE_DETAILED_WITH_ARG("Database", "FetchQueryResults", "Query", query.asString());
@@ -121,7 +121,7 @@ namespace lms::db::utils
template<typename Query> template<typename Query>
std::vector<typename QueryResultType<Query>::type> fetchQueryResults(const Query& query) std::vector<typename QueryResultType<Query>::type> fetchQueryResults(const Query& query)
{ {
details::recordQueryPlanIfNeeded(query); detail::recordQueryPlanIfNeeded(query);
LMS_SCOPED_TRACE_DETAILED_WITH_ARG("Database", "FetchQueryResults", "Query", query.asString()); LMS_SCOPED_TRACE_DETAILED_WITH_ARG("Database", "FetchQueryResults", "Query", query.asString());
@@ -132,7 +132,7 @@ namespace lms::db::utils
template<typename Query> template<typename Query>
auto fetchQuerySingleResult(const Query& query) auto fetchQuerySingleResult(const Query& query)
{ {
details::recordQueryPlanIfNeeded(query); detail::recordQueryPlanIfNeeded(query);
LMS_SCOPED_TRACE_DETAILED_WITH_ARG("Database", "FetchQuerySingleResult", "Query", query.asString()); LMS_SCOPED_TRACE_DETAILED_WITH_ARG("Database", "FetchQuerySingleResult", "Query", query.asString());
return query.resultValue(); return query.resultValue();
@@ -27,7 +27,7 @@
namespace lms::feedback namespace lms::feedback
{ {
namespace details namespace detail
{ {
template<typename StarredObjType> template<typename StarredObjType>
void onStarred(db::Session& session, typename StarredObjType::IdType id) void onStarred(db::Session& session, typename StarredObjType::IdType id)
@@ -46,7 +46,7 @@ namespace lms::feedback
if (auto starredObj{ StarredObjType::find(session, id) }) if (auto starredObj{ StarredObjType::find(session, id) })
starredObj.remove(); starredObj.remove();
} }
} // namespace details } // namespace detail
InternalBackend::InternalBackend(db::IDb& db) InternalBackend::InternalBackend(db::IDb& db)
: _db{ db } : _db{ db }
@@ -55,31 +55,31 @@ namespace lms::feedback
void InternalBackend::onStarred(db::StarredArtistId artistId) void InternalBackend::onStarred(db::StarredArtistId artistId)
{ {
details::onStarred<db::StarredArtist>(_db.getTLSSession(), artistId); detail::onStarred<db::StarredArtist>(_db.getTLSSession(), artistId);
} }
void InternalBackend::onUnstarred(db::StarredArtistId artistId) void InternalBackend::onUnstarred(db::StarredArtistId artistId)
{ {
details::onUnstarred<db::StarredArtist>(_db.getTLSSession(), artistId); detail::onUnstarred<db::StarredArtist>(_db.getTLSSession(), artistId);
} }
void InternalBackend::onStarred(db::StarredReleaseId releaseId) void InternalBackend::onStarred(db::StarredReleaseId releaseId)
{ {
details::onStarred<db::StarredRelease>(_db.getTLSSession(), releaseId); detail::onStarred<db::StarredRelease>(_db.getTLSSession(), releaseId);
} }
void InternalBackend::onUnstarred(db::StarredReleaseId releaseId) void InternalBackend::onUnstarred(db::StarredReleaseId releaseId)
{ {
details::onUnstarred<db::StarredRelease>(_db.getTLSSession(), releaseId); detail::onUnstarred<db::StarredRelease>(_db.getTLSSession(), releaseId);
} }
void InternalBackend::onStarred(db::StarredTrackId trackId) void InternalBackend::onStarred(db::StarredTrackId trackId)
{ {
details::onStarred<db::StarredTrack>(_db.getTLSSession(), trackId); detail::onStarred<db::StarredTrack>(_db.getTLSSession(), trackId);
} }
void InternalBackend::onUnstarred(db::StarredTrackId trackId) void InternalBackend::onUnstarred(db::StarredTrackId trackId)
{ {
details::onUnstarred<db::StarredTrack>(_db.getTLSSession(), trackId); detail::onUnstarred<db::StarredTrack>(_db.getTLSSession(), trackId);
} }
} // namespace lms::feedback } // namespace lms::feedback
@@ -32,7 +32,7 @@
namespace lms::feedback::listenBrainz namespace lms::feedback::listenBrainz
{ {
namespace details namespace detail
{ {
template<typename StarredObjType> template<typename StarredObjType>
void onStarred(db::Session& session, typename StarredObjType::IdType id) void onStarred(db::Session& session, typename StarredObjType::IdType id)
@@ -54,7 +54,7 @@ namespace lms::feedback::listenBrainz
if (auto starredObj{ StarredObjType::find(session, id) }) if (auto starredObj{ StarredObjType::find(session, id) })
starredObj.remove(); starredObj.remove();
} }
} // namespace details } // namespace detail
ListenBrainzBackend::ListenBrainzBackend(boost::asio::io_context& ioContext, db::IDb& db) ListenBrainzBackend::ListenBrainzBackend(boost::asio::io_context& ioContext, db::IDb& db)
: _ioContext{ ioContext } : _ioContext{ ioContext }
@@ -73,22 +73,22 @@ namespace lms::feedback::listenBrainz
void ListenBrainzBackend::onStarred(db::StarredArtistId starredArtistId) void ListenBrainzBackend::onStarred(db::StarredArtistId starredArtistId)
{ {
details::onStarred<db::StarredArtist>(_db.getTLSSession(), starredArtistId); detail::onStarred<db::StarredArtist>(_db.getTLSSession(), starredArtistId);
} }
void ListenBrainzBackend::onUnstarred(db::StarredArtistId starredArtistId) void ListenBrainzBackend::onUnstarred(db::StarredArtistId starredArtistId)
{ {
details::onUnstarred<db::StarredArtist>(_db.getTLSSession(), starredArtistId); detail::onUnstarred<db::StarredArtist>(_db.getTLSSession(), starredArtistId);
} }
void ListenBrainzBackend::onStarred(db::StarredReleaseId starredReleaseId) void ListenBrainzBackend::onStarred(db::StarredReleaseId starredReleaseId)
{ {
details::onStarred<db::StarredRelease>(_db.getTLSSession(), starredReleaseId); detail::onStarred<db::StarredRelease>(_db.getTLSSession(), starredReleaseId);
} }
void ListenBrainzBackend::onUnstarred(db::StarredReleaseId starredReleaseId) void ListenBrainzBackend::onUnstarred(db::StarredReleaseId starredReleaseId)
{ {
details::onUnstarred<db::StarredRelease>(_db.getTLSSession(), starredReleaseId); detail::onUnstarred<db::StarredRelease>(_db.getTLSSession(), starredReleaseId);
} }
void ListenBrainzBackend::onStarred(db::StarredTrackId starredTrackId) void ListenBrainzBackend::onStarred(db::StarredTrackId starredTrackId)
@@ -92,25 +92,25 @@ namespace lms::api::subsonic
transcodeNode.addChild("sourceStream", createStreamDetails(sourceStream)); transcodeNode.addChild("sourceStream", createStreamDetails(sourceStream));
} }
const details::TranscodeDecisionResult transcodeDecision{ details::computeTranscodeDecision(clientInfo, audioFileInfo.audioProperties) }; const detail::TranscodeDecisionResult transcodeDecision{ detail::computeTranscodeDecision(clientInfo, audioFileInfo.audioProperties) };
std::visit(core::utils::overloads{ std::visit(core::utils::overloads{
[&](const details::DirectPlayResult&) { [&](const detail::DirectPlayResult&) {
transcodeNode.setAttribute("canDirectPlay", true); transcodeNode.setAttribute("canDirectPlay", true);
transcodeNode.setAttribute("canTranscode", false); transcodeNode.setAttribute("canTranscode", false);
}, },
[&](const details::TranscodeResult& transcodeRes) { [&](const detail::TranscodeResult& transcodeRes) {
transcodeNode.setAttribute("canDirectPlay", false); transcodeNode.setAttribute("canDirectPlay", false);
transcodeNode.setAttribute("canTranscode", true); transcodeNode.setAttribute("canTranscode", true);
for (details::TranscodeReason reason : transcodeRes.reasons) for (detail::TranscodeReason reason : transcodeRes.reasons)
transcodeNode.addArrayValue("transcodeReason", transcodeReasonToString(reason).str()); transcodeNode.addArrayValue("transcodeReason", transcodeReasonToString(reason).str());
const core::UUID uuid{ getTranscodeDecisionTracker().add(audioFileId, transcodeRes.targetStreamInfo) }; const core::UUID uuid{ getTranscodeDecisionTracker().add(audioFileId, transcodeRes.targetStreamInfo) };
transcodeNode.addChild("transcodeStream", createStreamDetails(transcodeRes.targetStreamInfo)); transcodeNode.addChild("transcodeStream", createStreamDetails(transcodeRes.targetStreamInfo));
transcodeNode.setAttribute("transcodeParams", uuid.getAsString()); transcodeNode.setAttribute("transcodeParams", uuid.getAsString());
}, },
[&](const details::FailureResult& failureRes) { [&](const detail::FailureResult& failureRes) {
transcodeNode.setAttribute("canDirectPlay", false); transcodeNode.setAttribute("canDirectPlay", false);
transcodeNode.setAttribute("canTranscode", false); transcodeNode.setAttribute("canTranscode", false);
transcodeNode.setAttribute("errorReason", failureRes.reason); transcodeNode.setAttribute("errorReason", failureRes.reason);
@@ -149,7 +149,7 @@ namespace lms::api::subsonic
params.outputParameters.stripMetadata = false; params.outputParameters.stripMetadata = false;
const audio::TranscodeOutputFormat* transcodeOutputFormat{ details::selectTranscodeOutputFormat(entry->targetStreamInfo.container, entry->targetStreamInfo.codec) }; const audio::TranscodeOutputFormat* transcodeOutputFormat{ detail::selectTranscodeOutputFormat(entry->targetStreamInfo.container, entry->targetStreamInfo.codec) };
if (!transcodeOutputFormat) if (!transcodeOutputFormat)
throw InternalErrorGenericError{ "Unsupported output format" }; throw InternalErrorGenericError{ "Unsupported output format" };
@@ -29,7 +29,7 @@
#include "SubsonicResponse.hpp" #include "SubsonicResponse.hpp"
#include "payloads/ClientInfo.hpp" #include "payloads/ClientInfo.hpp"
namespace lms::api::subsonic::details namespace lms::api::subsonic::detail
{ {
namespace namespace
{ {
@@ -592,4 +592,4 @@ namespace lms::api::subsonic::details
return FailureResult{ "No compatible direct play or transcoding profile found" }; return FailureResult{ "No compatible direct play or transcoding profile found" };
} }
} // namespace lms::api::subsonic::details } // namespace lms::api::subsonic::detail
@@ -33,7 +33,7 @@ namespace lms::api::subsonic
{ {
struct ClientInfo; struct ClientInfo;
namespace details namespace detail
{ {
enum class TranscodeReason enum class TranscodeReason
{ {
@@ -72,5 +72,5 @@ namespace lms::api::subsonic
TranscodeDecisionResult computeTranscodeDecision(const ClientInfo& clientInfo, const audio::AudioProperties& source); TranscodeDecisionResult computeTranscodeDecision(const ClientInfo& clientInfo, const audio::AudioProperties& source);
const audio::TranscodeOutputFormat* selectTranscodeOutputFormat(std::string_view containerName, std::string_view codecName); const audio::TranscodeOutputFormat* selectTranscodeOutputFormat(std::string_view containerName, std::string_view codecName);
} // namespace details } // namespace detail
} // namespace lms::api::subsonic } // namespace lms::api::subsonic
+26 -26
View File
@@ -30,14 +30,14 @@
namespace lms::api::subsonic namespace lms::api::subsonic
{ {
namespace details namespace detail
{ {
std::ostream& operator<<(std::ostream& os, const details::TranscodeDecisionResult& result) std::ostream& operator<<(std::ostream& os, const detail::TranscodeDecisionResult& result)
{ {
std::visit(core::utils::overloads{ std::visit(core::utils::overloads{
[&](const details::DirectPlayResult&) { os << "direct play"; }, [&](const detail::DirectPlayResult&) { os << "direct play"; },
[&](const details::FailureResult& res) { os << "failure: " << res.reason; }, [&](const detail::FailureResult& res) { os << "failure: " << res.reason; },
[&](const details::TranscodeResult& res) { [&](const detail::TranscodeResult& res) {
os << "transcode: reasons = {"; os << "transcode: reasons = {";
bool firstReason{ true }; bool firstReason{ true };
@@ -66,7 +66,7 @@ namespace lms::api::subsonic
return os; return os;
} // namespace } // namespace
}; // namespace details }; // namespace detail
namespace namespace
{ {
@@ -75,7 +75,7 @@ namespace lms::api::subsonic
ClientInfo clientInfo; ClientInfo clientInfo;
audio::AudioProperties source; audio::AudioProperties source;
details::TranscodeDecisionResult expected; detail::TranscodeDecisionResult expected;
}; };
void processTests(std::span<const TestCase> testCases) void processTests(std::span<const TestCase> testCases)
@@ -83,7 +83,7 @@ namespace lms::api::subsonic
for (std::size_t testCaseIndex{ 0 }; testCaseIndex < std::size(testCases); ++testCaseIndex) for (std::size_t testCaseIndex{ 0 }; testCaseIndex < std::size(testCases); ++testCaseIndex)
{ {
const auto& testCase{ testCases[testCaseIndex] }; const auto& testCase{ testCases[testCaseIndex] };
const details::TranscodeDecisionResult decision{ details::computeTranscodeDecision(testCase.clientInfo, testCase.source) }; const detail::TranscodeDecisionResult decision{ detail::computeTranscodeDecision(testCase.clientInfo, testCase.source) };
EXPECT_EQ(testCase.expected, decision) << "testCaseIndex: " << testCaseIndex; EXPECT_EQ(testCase.expected, decision) << "testCaseIndex: " << testCaseIndex;
} }
@@ -120,7 +120,7 @@ namespace lms::api::subsonic
.bitsPerSample = std::nullopt, .bitsPerSample = std::nullopt,
}, },
.expected = { details::DirectPlayResult{} }, .expected = { detail::DirectPlayResult{} },
}, },
// Needs transcode due to codec limitation // Needs transcode due to codec limitation
@@ -150,7 +150,7 @@ namespace lms::api::subsonic
.bitsPerSample = std::nullopt, .bitsPerSample = std::nullopt,
}, },
.expected = { details::TranscodeResult{ .reasons = { details::TranscodeReason::AudioBitrateNotSupported }, .targetStreamInfo = { .protocol = "http", .container = "mp3", .codec = "mp3", .audioChannels = std::nullopt, .audioBitrate = 96000, .audioProfile = "", .audioSamplerate = std::nullopt, .audioBitdepth = std::nullopt } } }, .expected = { detail::TranscodeResult{ .reasons = { detail::TranscodeReason::AudioBitrateNotSupported }, .targetStreamInfo = { .protocol = "http", .container = "mp3", .codec = "mp3", .audioChannels = std::nullopt, .audioBitrate = 96000, .audioProfile = "", .audioSamplerate = std::nullopt, .audioBitdepth = std::nullopt } } },
}, },
// Needs transcode due to global limitation on the direct play bitrate // Needs transcode due to global limitation on the direct play bitrate
@@ -180,7 +180,7 @@ namespace lms::api::subsonic
.bitsPerSample = std::nullopt, .bitsPerSample = std::nullopt,
}, },
.expected = { details::TranscodeResult{ .reasons = { details::TranscodeReason::AudioBitrateNotSupported }, .targetStreamInfo = { .protocol = "http", .container = "mp3", .codec = "mp3", .audioChannels = std::nullopt, .audioBitrate = 96000, .audioProfile = "", .audioSamplerate = std::nullopt, .audioBitdepth = std::nullopt } } }, .expected = { detail::TranscodeResult{ .reasons = { detail::TranscodeReason::AudioBitrateNotSupported }, .targetStreamInfo = { .protocol = "http", .container = "mp3", .codec = "mp3", .audioChannels = std::nullopt, .audioBitrate = 96000, .audioProfile = "", .audioSamplerate = std::nullopt, .audioBitdepth = std::nullopt } } },
}, },
// Needs transcode due to codec limitation, but global limitation is even more restrictive // Needs transcode due to codec limitation, but global limitation is even more restrictive
@@ -210,7 +210,7 @@ namespace lms::api::subsonic
.bitsPerSample = std::nullopt, .bitsPerSample = std::nullopt,
}, },
.expected = { details::TranscodeResult{ .reasons = { details::TranscodeReason::AudioBitrateNotSupported }, .targetStreamInfo = { .protocol = "http", .container = "mp3", .codec = "mp3", .audioChannels = std::nullopt, .audioBitrate = 96'000, .audioProfile = "", .audioSamplerate = std::nullopt, .audioBitdepth = std::nullopt } } }, .expected = { detail::TranscodeResult{ .reasons = { detail::TranscodeReason::AudioBitrateNotSupported }, .targetStreamInfo = { .protocol = "http", .container = "mp3", .codec = "mp3", .audioChannels = std::nullopt, .audioBitrate = 96'000, .audioProfile = "", .audioSamplerate = std::nullopt, .audioBitdepth = std::nullopt } } },
}, },
// Needs transcode due to max audio sample rate not handle by codec limitation // Needs transcode due to max audio sample rate not handle by codec limitation
@@ -240,7 +240,7 @@ namespace lms::api::subsonic
.bitsPerSample = std::nullopt, .bitsPerSample = std::nullopt,
}, },
.expected = { details::TranscodeResult{ .reasons = { details::TranscodeReason::AudioSampleRateNotSupported }, .targetStreamInfo = { .protocol = "http", .container = "mp3", .codec = "mp3", .audioChannels = std::nullopt, .audioBitrate = 192'000, .audioProfile = "", .audioSamplerate = 48'000, .audioBitdepth = std::nullopt } } }, .expected = { detail::TranscodeResult{ .reasons = { detail::TranscodeReason::AudioSampleRateNotSupported }, .targetStreamInfo = { .protocol = "http", .container = "mp3", .codec = "mp3", .audioChannels = std::nullopt, .audioBitrate = 192'000, .audioProfile = "", .audioSamplerate = 48'000, .audioBitdepth = std::nullopt } } },
}, },
// Needs transcode due to max nb channels not handle by profile // Needs transcode due to max nb channels not handle by profile
@@ -264,7 +264,7 @@ namespace lms::api::subsonic
.bitsPerSample = std::nullopt, .bitsPerSample = std::nullopt,
}, },
.expected = { details::TranscodeResult{ .reasons = { details::TranscodeReason::AudioChannelsNotSupported }, .targetStreamInfo = { .protocol = "http", .container = "mp3", .codec = "mp3", .audioChannels = 2, .audioBitrate = 192'000, .audioProfile = "", .audioSamplerate = std::nullopt, .audioBitdepth = std::nullopt } } }, .expected = { detail::TranscodeResult{ .reasons = { detail::TranscodeReason::AudioChannelsNotSupported }, .targetStreamInfo = { .protocol = "http", .container = "mp3", .codec = "mp3", .audioChannels = 2, .audioBitrate = 192'000, .audioProfile = "", .audioSamplerate = std::nullopt, .audioBitdepth = std::nullopt } } },
}, },
// Needs transcode due to max nb channels not handle by codec. TODO take channel reduction into account for bitrate // Needs transcode due to max nb channels not handle by codec. TODO take channel reduction into account for bitrate
@@ -292,7 +292,7 @@ namespace lms::api::subsonic
.bitsPerSample = std::nullopt, .bitsPerSample = std::nullopt,
}, },
.expected = { details::TranscodeResult{ .reasons = { details::TranscodeReason::AudioChannelsNotSupported }, .targetStreamInfo = { .protocol = "http", .container = "mp3", .codec = "mp3", .audioChannels = 2, .audioBitrate = 192'000, .audioProfile = "", .audioSamplerate = std::nullopt, .audioBitdepth = std::nullopt } } }, .expected = { detail::TranscodeResult{ .reasons = { detail::TranscodeReason::AudioChannelsNotSupported }, .targetStreamInfo = { .protocol = "http", .container = "mp3", .codec = "mp3", .audioChannels = 2, .audioBitrate = 192'000, .audioProfile = "", .audioSamplerate = std::nullopt, .audioBitdepth = std::nullopt } } },
}, },
// needs transcode because codec not handled // needs transcode because codec not handled
@@ -320,7 +320,7 @@ namespace lms::api::subsonic
.bitsPerSample = std::nullopt, .bitsPerSample = std::nullopt,
}, },
.expected = { details::TranscodeResult{ .reasons = { details::TranscodeReason::ContainerNotSupported }, .targetStreamInfo = { .protocol = "http", .container = "mp3", .codec = "mp3", .audioChannels = std::nullopt, .audioBitrate = 128'000, .audioProfile = "", .audioSamplerate = std::nullopt, .audioBitdepth = std::nullopt } } }, .expected = { detail::TranscodeResult{ .reasons = { detail::TranscodeReason::ContainerNotSupported }, .targetStreamInfo = { .protocol = "http", .container = "mp3", .codec = "mp3", .audioChannels = std::nullopt, .audioBitrate = 128'000, .audioProfile = "", .audioSamplerate = std::nullopt, .audioBitdepth = std::nullopt } } },
}, },
// needs transcode because codec not handled (lossless source => using max bitrate) // needs transcode because codec not handled (lossless source => using max bitrate)
@@ -348,7 +348,7 @@ namespace lms::api::subsonic
.bitsPerSample = 16, .bitsPerSample = 16,
}, },
.expected = { details::TranscodeResult{ .reasons = { details::TranscodeReason::ContainerNotSupported }, .targetStreamInfo = { .protocol = "http", .container = "mp3", .codec = "mp3", .audioChannels = std::nullopt, .audioBitrate = 320000, .audioProfile = "", .audioSamplerate = std::nullopt, .audioBitdepth = std::nullopt } } }, .expected = { detail::TranscodeResult{ .reasons = { detail::TranscodeReason::ContainerNotSupported }, .targetStreamInfo = { .protocol = "http", .container = "mp3", .codec = "mp3", .audioChannels = std::nullopt, .audioBitrate = 320000, .audioProfile = "", .audioSamplerate = std::nullopt, .audioBitdepth = std::nullopt } } },
}, },
// needs transcode because codec not handled (lossless source => using a default good bitrate) // needs transcode because codec not handled (lossless source => using a default good bitrate)
@@ -371,7 +371,7 @@ namespace lms::api::subsonic
.bitsPerSample = 16, .bitsPerSample = 16,
}, },
.expected = { details::TranscodeResult{ .reasons = { details::TranscodeReason::ContainerNotSupported }, .targetStreamInfo = { .protocol = "http", .container = "mp3", .codec = "mp3", .audioChannels = std::nullopt, .audioBitrate = 256000, .audioProfile = "", .audioSamplerate = std::nullopt, .audioBitdepth = std::nullopt } } }, .expected = { detail::TranscodeResult{ .reasons = { detail::TranscodeReason::ContainerNotSupported }, .targetStreamInfo = { .protocol = "http", .container = "mp3", .codec = "mp3", .audioChannels = std::nullopt, .audioBitrate = 256000, .audioProfile = "", .audioSamplerate = std::nullopt, .audioBitdepth = std::nullopt } } },
}, },
// check protocol * and codec * are properly handled // check protocol * and codec * are properly handled
@@ -397,7 +397,7 @@ namespace lms::api::subsonic
.bitsPerSample = std::nullopt, .bitsPerSample = std::nullopt,
}, },
.expected = { details::DirectPlayResult{} }, .expected = { detail::DirectPlayResult{} },
}, },
// check container * is properly handled // check container * is properly handled
@@ -423,7 +423,7 @@ namespace lms::api::subsonic
.bitsPerSample = std::nullopt, .bitsPerSample = std::nullopt,
}, },
.expected = { details::DirectPlayResult{} }, .expected = { detail::DirectPlayResult{} },
}, },
// want flac but bitrate too high // want flac but bitrate too high
@@ -449,7 +449,7 @@ namespace lms::api::subsonic
.bitsPerSample = 16, .bitsPerSample = 16,
}, },
.expected = { details::TranscodeResult{ .reasons = { details::TranscodeReason::AudioBitrateNotSupported }, .targetStreamInfo = { .protocol = "http", .container = "ogg", .codec = "opus", .audioChannels = std::nullopt, .audioBitrate = 320'000, .audioProfile = "", .audioSamplerate = std::nullopt, .audioBitdepth = std::nullopt } } }, .expected = { detail::TranscodeResult{ .reasons = { detail::TranscodeReason::AudioBitrateNotSupported }, .targetStreamInfo = { .protocol = "http", .container = "ogg", .codec = "opus", .audioChannels = std::nullopt, .audioBitrate = 320'000, .audioProfile = "", .audioSamplerate = std::nullopt, .audioBitdepth = std::nullopt } } },
}, },
// want flac but source sample rate is too high // want flac but source sample rate is too high
@@ -487,7 +487,7 @@ namespace lms::api::subsonic
.bitsPerSample = 24, .bitsPerSample = 24,
}, },
.expected = { details::TranscodeResult{ .reasons = { details::TranscodeReason::AudioSampleRateNotSupported, details::TranscodeReason::ContainerNotSupported, details::TranscodeReason::ContainerNotSupported }, .targetStreamInfo = { .protocol = "http", .container = "flac", .codec = "flac", .audioChannels = std::nullopt, .audioBitrate = std::nullopt, .audioProfile = "", .audioSamplerate = 48'000, .audioBitdepth = std::nullopt } } }, .expected = { detail::TranscodeResult{ .reasons = { detail::TranscodeReason::AudioSampleRateNotSupported, detail::TranscodeReason::ContainerNotSupported, detail::TranscodeReason::ContainerNotSupported }, .targetStreamInfo = { .protocol = "http", .container = "flac", .codec = "flac", .audioChannels = std::nullopt, .audioBitrate = std::nullopt, .audioProfile = "", .audioSamplerate = 48'000, .audioBitdepth = std::nullopt } } },
}, },
// want flac but source sample rate is too high, no max bitrate // want flac but source sample rate is too high, no max bitrate
@@ -526,7 +526,7 @@ namespace lms::api::subsonic
.bitsPerSample = 24, .bitsPerSample = 24,
}, },
.expected = { details::TranscodeResult{ .reasons = { details::TranscodeReason::AudioSampleRateNotSupported, details::TranscodeReason::ContainerNotSupported, details::TranscodeReason::ContainerNotSupported }, .targetStreamInfo = { .protocol = "http", .container = "flac", .codec = "flac", .audioChannels = std::nullopt, .audioBitrate = std::nullopt, .audioProfile = "", .audioSamplerate = 48'000, .audioBitdepth = std::nullopt } } }, .expected = { detail::TranscodeResult{ .reasons = { detail::TranscodeReason::AudioSampleRateNotSupported, detail::TranscodeReason::ContainerNotSupported, detail::TranscodeReason::ContainerNotSupported }, .targetStreamInfo = { .protocol = "http", .container = "flac", .codec = "flac", .audioChannels = std::nullopt, .audioBitrate = std::nullopt, .audioProfile = "", .audioSamplerate = 48'000, .audioBitdepth = std::nullopt } } },
}, },
// wants a lossy codec not handled -> transcode to lossy // wants a lossy codec not handled -> transcode to lossy
@@ -564,7 +564,7 @@ namespace lms::api::subsonic
.bitsPerSample = 16, .bitsPerSample = 16,
}, },
.expected = { details::TranscodeResult{ .reasons = { details::TranscodeReason::ContainerNotSupported, details::TranscodeReason::ContainerNotSupported, details::TranscodeReason::ContainerNotSupported }, .targetStreamInfo = { .protocol = "http", .container = "mp3", .codec = "mp3", .audioChannels = std::nullopt, .audioBitrate = 128000, .audioProfile = "", .audioSamplerate = std::nullopt, .audioBitdepth = std::nullopt } } }, .expected = { detail::TranscodeResult{ .reasons = { detail::TranscodeReason::ContainerNotSupported, detail::TranscodeReason::ContainerNotSupported, detail::TranscodeReason::ContainerNotSupported }, .targetStreamInfo = { .protocol = "http", .container = "mp3", .codec = "mp3", .audioChannels = std::nullopt, .audioBitrate = 128000, .audioProfile = "", .audioSamplerate = std::nullopt, .audioBitdepth = std::nullopt } } },
}, },
// wants a lossless codec not handled -> transcode to lossless // wants a lossless codec not handled -> transcode to lossless
@@ -602,7 +602,7 @@ namespace lms::api::subsonic
.bitsPerSample = 24, .bitsPerSample = 24,
}, },
.expected = { details::TranscodeResult{ .reasons = { details::TranscodeReason::ContainerNotSupported, details::TranscodeReason::ContainerNotSupported, details::TranscodeReason::ContainerNotSupported }, .targetStreamInfo = { .protocol = "http", .container = "flac", .codec = "flac", .audioChannels = std::nullopt, .audioBitrate = std::nullopt, .audioProfile = "", .audioSamplerate = 48'000, .audioBitdepth = std::nullopt } } }, .expected = { detail::TranscodeResult{ .reasons = { detail::TranscodeReason::ContainerNotSupported, detail::TranscodeReason::ContainerNotSupported, detail::TranscodeReason::ContainerNotSupported }, .targetStreamInfo = { .protocol = "http", .container = "flac", .codec = "flac", .audioChannels = std::nullopt, .audioBitrate = std::nullopt, .audioProfile = "", .audioSamplerate = 48'000, .audioBitdepth = std::nullopt } } },
}, },
// no protocol specified // no protocol specified
@@ -632,7 +632,7 @@ namespace lms::api::subsonic
.bitsPerSample = std::nullopt, .bitsPerSample = std::nullopt,
}, },
.expected = { details::TranscodeResult{ .reasons = { details::TranscodeReason::AudioBitrateNotSupported }, .targetStreamInfo = { .protocol = "http", .container = "mp3", .codec = "mp3", .audioChannels = std::nullopt, .audioBitrate = 96000, .audioProfile = "", .audioSamplerate = std::nullopt, .audioBitdepth = std::nullopt } } }, .expected = { detail::TranscodeResult{ .reasons = { detail::TranscodeReason::AudioBitrateNotSupported }, .targetStreamInfo = { .protocol = "http", .container = "mp3", .codec = "mp3", .audioChannels = std::nullopt, .audioBitrate = 96000, .audioProfile = "", .audioSamplerate = std::nullopt, .audioBitdepth = std::nullopt } } },
}, },
}; };
+2 -3
View File
@@ -25,7 +25,7 @@
#include "LmsApplication.hpp" #include "LmsApplication.hpp"
namespace lms::ui::state::details namespace lms::ui::state::detail
{ {
void writeValue(std::string_view item, std::string_view value) void writeValue(std::string_view item, std::string_view value)
{ {
@@ -81,5 +81,4 @@ namespace lms::ui::state::details
state.remove(); state.remove();
} }
} }
} // namespace lms::ui::state::detail
} // namespace lms::ui::state::details
+6 -6
View File
@@ -27,12 +27,12 @@
namespace lms::ui::state namespace lms::ui::state
{ {
namespace details namespace detail
{ {
std::optional<std::string> readValue(std::string_view item); std::optional<std::string> readValue(std::string_view item);
void writeValue(std::string_view item, std::string_view value); void writeValue(std::string_view item, std::string_view value);
void eraseValue(std::string_view item); void eraseValue(std::string_view item);
} // namespace details } // namespace detail
template<typename T> template<typename T>
void writeValue(std::string_view item, std::optional<T> value) void writeValue(std::string_view item, std::optional<T> value)
@@ -40,18 +40,18 @@ namespace lms::ui::state
if (value.has_value()) if (value.has_value())
{ {
if constexpr (std::is_enum_v<T>) if constexpr (std::is_enum_v<T>)
details::writeValue(item, std::to_string(static_cast<std::underlying_type_t<T>>(*value))); detail::writeValue(item, std::to_string(static_cast<std::underlying_type_t<T>>(*value)));
else else
details::writeValue(item, std::to_string(*value)); detail::writeValue(item, std::to_string(*value));
} }
else else
details::eraseValue(item); detail::eraseValue(item);
} }
template<typename T> template<typename T>
std::optional<T> readValue(std::string_view item) std::optional<T> readValue(std::string_view item)
{ {
if (std::optional<std::string> res{ details::readValue(item) }) if (std::optional<std::string> res{ detail::readValue(item) })
return core::stringUtils::readAs<T>(*res); return core::stringUtils::readAs<T>(*res);
return std::nullopt; return std::nullopt;
+8 -8
View File
@@ -115,7 +115,7 @@ namespace lms::ui
} }
} // namespace } // namespace
namespace details namespace detail
{ {
std::string getTrackPathName(const db::Track::pointer& track) std::string getTrackPathName(const db::Track::pointer& track)
{ {
@@ -165,7 +165,7 @@ namespace lms::ui
return zip::createArchiveZipper(files); return zip::createArchiveZipper(files);
} }
} // namespace details } // namespace detail
DownloadArtistResource::DownloadArtistResource(db::ArtistId artistId) DownloadArtistResource::DownloadArtistResource(db::ArtistId artistId)
: _artistId{ artistId } : _artistId{ artistId }
@@ -182,7 +182,7 @@ namespace lms::ui
auto transaction{ LmsApp->getDbSession().createReadTransaction() }; auto transaction{ LmsApp->getDbSession().createReadTransaction() };
const auto trackResults{ db::Track::find(LmsApp->getDbSession(), db::Track::FindParameters{}.setArtist(_artistId).setSortMethod(db::TrackSortMethod::DateDescAndRelease)) }; const auto trackResults{ db::Track::find(LmsApp->getDbSession(), db::Track::FindParameters{}.setArtist(_artistId).setSortMethod(db::TrackSortMethod::DateDescAndRelease)) };
return details::createZipper(trackResults.results); return detail::createZipper(trackResults.results);
} }
DownloadReleaseResource::DownloadReleaseResource(db::ReleaseId releaseId) DownloadReleaseResource::DownloadReleaseResource(db::ReleaseId releaseId)
@@ -200,7 +200,7 @@ namespace lms::ui
auto transaction{ LmsApp->getDbSession().createReadTransaction() }; auto transaction{ LmsApp->getDbSession().createReadTransaction() };
auto tracks{ db::Track::find(LmsApp->getDbSession(), db::Track::FindParameters{}.setRelease(_releaseId).setSortMethod(db::TrackSortMethod::Release)) }; auto tracks{ db::Track::find(LmsApp->getDbSession(), db::Track::FindParameters{}.setRelease(_releaseId).setSortMethod(db::TrackSortMethod::Release)) };
return details::createZipper(tracks.results); return detail::createZipper(tracks.results);
} }
DownloadTrackResource::DownloadTrackResource(db::TrackId trackId) DownloadTrackResource::DownloadTrackResource(db::TrackId trackId)
@@ -210,7 +210,7 @@ namespace lms::ui
db::Track::pointer track{ db::Track::find(LmsApp->getDbSession(), trackId) }; db::Track::pointer track{ db::Track::find(LmsApp->getDbSession(), trackId) };
if (track) if (track)
suggestFileName(details::getTrackPathName(track) + ".zip"); suggestFileName(detail::getTrackPathName(track) + ".zip");
} }
std::unique_ptr<zip::IZipper> DownloadTrackResource::createZipper() std::unique_ptr<zip::IZipper> DownloadTrackResource::createZipper()
@@ -224,7 +224,7 @@ namespace lms::ui
return {}; return {};
} }
return details::createZipper({ track }); return detail::createZipper({ track });
} }
DownloadTrackListResource::DownloadTrackListResource(db::TrackListId trackListId) DownloadTrackListResource::DownloadTrackListResource(db::TrackListId trackListId)
@@ -234,7 +234,7 @@ namespace lms::ui
const db::TrackList::pointer trackList{ db::TrackList::find(LmsApp->getDbSession(), trackListId) }; const db::TrackList::pointer trackList{ db::TrackList::find(LmsApp->getDbSession(), trackListId) };
if (trackList) if (trackList)
suggestFileName(details::getTrackListPathName(trackList) + ".zip"); suggestFileName(detail::getTrackListPathName(trackList) + ".zip");
} }
std::unique_ptr<zip::IZipper> DownloadTrackListResource::createZipper() std::unique_ptr<zip::IZipper> DownloadTrackListResource::createZipper()
@@ -244,6 +244,6 @@ namespace lms::ui
db::Track::FindParameters params; db::Track::FindParameters params;
params.setTrackList(_trackListId); params.setTrackList(_trackListId);
const auto tracks{ db::Track::find(LmsApp->getDbSession(), params) }; const auto tracks{ db::Track::find(LmsApp->getDbSession(), params) };
return details::createZipper(tracks.results); return detail::createZipper(tracks.results);
} }
} // namespace lms::ui } // namespace lms::ui