diff --git a/Dockerfile-release b/Dockerfile-release
index 1bf40d82..0a162378 100644
--- a/Dockerfile-release
+++ b/Dockerfile-release
@@ -67,11 +67,12 @@ RUN \
--enable-libopenjpeg \
--enable-libopus \
--enable-libvorbis \
+ --enable-zlib \
--disable-everything \
- --enable-decoder=aac*,ac3*,alac,als,dsd*,flac,mp3*,libopus,pcm*,libvorbis,wavpack,wma*,libopenjpg,png \
+ --enable-decoder=aac*,ac3*,alac,als,ape,asf,dsd*,flac,libopus,pcm*,libvorbis,mp3*,mpc7,mpc8,shorten,tta,wavpack,wma*,libopenjpg,png \
--enable-encoder=libmp3lame,libopus,libvorbis \
- --enable-demuxer=aac,aiff,asf,dsf,flac,ipod,ogg,matroska,mov,mp3,mp4,wav,wv,webm \
- --enable-muxer=ogg,matroska,mp3,webm \
+ --enable-demuxer=aac,aiff,ape,asf,dsf,flac,m4a,mp3,mov,mpc,mpc8,ogg,shn,tta,wav,wv \
+ --enable-muxer=ogg,mp3 \
--enable-protocol=file,pipe \
--enable-filter=aresample \
--enable-lto \
diff --git a/approot/messages.xml b/approot/messages.xml
index 9a4fd79f..00d92c46 100644
--- a/approot/messages.xml
+++ b/approot/messages.xml
@@ -371,11 +371,9 @@
Never
Transcoding output bitrate
Transcoding output format
-Matroska/Opus
MP3
Ogg/Opus
Ogg/Vorbis
-WebM/Vorbis
User Interface
diff --git a/approot/messages_es.xml b/approot/messages_es.xml
index b60112a2..5800e983 100644
--- a/approot/messages_es.xml
+++ b/approot/messages_es.xml
@@ -370,11 +370,9 @@
Nunca
Bitrate de transcodificación
Formato de transcodificación
-Matroska/Opus
MP3
Ogg/Opus
Ogg/Vorbis
-WebM/Vorbis
Interfaz de usuario
diff --git a/approot/messages_fr.xml b/approot/messages_fr.xml
index ed0a2b30..4ca0b8a5 100644
--- a/approot/messages_fr.xml
+++ b/approot/messages_fr.xml
@@ -370,11 +370,9 @@
Jamais
Bitrate du transcodage
Format du transcodage
-Matroska/Opus
MP3
Ogg/Opus
Ogg/Vorbis
-WebM/Vorbis
Interface utilisateur
diff --git a/approot/messages_it.xml b/approot/messages_it.xml
index 13e74ee0..a1856a6b 100644
--- a/approot/messages_it.xml
+++ b/approot/messages_it.xml
@@ -370,11 +370,9 @@
Mai
Bitrate transcodifica
Formato di transcodifica
-Matroska/Opus
MP3
Ogg/Opus
Ogg/Vorbis
-WebM/Vorbis
Interfaccia utente
diff --git a/approot/messages_pl.xml b/approot/messages_pl.xml
index 2687adc6..6e8ff867 100644
--- a/approot/messages_pl.xml
+++ b/approot/messages_pl.xml
@@ -396,11 +396,9 @@
Nigdy
Przepływność transkodowania
Format wyjściowy transkodowania
-Matroska/Opus
MP3
Ogg/Opus
Ogg/Vorbis
-WebM/Vorbis
Interfejs użytkownika
diff --git a/approot/messages_zh.xml b/approot/messages_zh.xml
index e5f4cda8..37f11a77 100644
--- a/approot/messages_zh.xml
+++ b/approot/messages_zh.xml
@@ -367,11 +367,9 @@
从不
转码比特率
转码格式
-Matroska/Opus
MP3
Ogg/Opus
Ogg/Vorbis
-WebM/Vorbis
diff --git a/src/libs/audio/CMakeLists.txt b/src/libs/audio/CMakeLists.txt
index bd8d1d4f..0979b975 100644
--- a/src/libs/audio/CMakeLists.txt
+++ b/src/libs/audio/CMakeLists.txt
@@ -14,8 +14,6 @@ add_library(lmsaudio STATIC
impl/taglib/ImageReader.cpp
impl/taglib/TagReader.cpp
impl/taglib/Utils.cpp
- impl/AudioTypes.cpp
- impl/ImageReader.cpp
impl/AudioFileInfoParser.cpp
impl/TagReader.cpp
)
diff --git a/src/libs/audio/impl/ffmpeg/AudioFile.cpp b/src/libs/audio/impl/ffmpeg/AudioFile.cpp
index 9e5eed5c..2afd4617 100644
--- a/src/libs/audio/impl/ffmpeg/AudioFile.cpp
+++ b/src/libs/audio/impl/ffmpeg/AudioFile.cpp
@@ -35,7 +35,6 @@ extern "C"
#include "core/ITraceLogger.hpp"
#include "core/String.hpp"
-#include "audio/AudioTypes.hpp"
#include "audio/Exception.hpp"
namespace lms::audio::ffmpeg
@@ -71,83 +70,83 @@ namespace lms::audio::ffmpeg
res[core::stringUtils::stringToUpper(tag->key)] = tag->value;
}
- std::optional avdemuxerToContainerType(std::string_view name)
+ std::optional avdemuxerToContainerType(std::string_view name)
{
if (name == "aiff")
- return ContainerType::AIFF;
+ return core::media::ContainerType::AIFF;
if (name == "ape")
- return ContainerType::APE;
+ return core::media::ContainerType::APE;
if (name.starts_with("asf"))
- return ContainerType::ASF;
+ return core::media::ContainerType::ASF;
if (name == "dsf")
- return ContainerType::DSF;
+ return core::media::ContainerType::DSF;
if (name == "flac")
- return ContainerType::FLAC;
+ return core::media::ContainerType::FLAC;
if (name.find("mp4") != std::string_view::npos)
- return ContainerType::MP4;
+ return core::media::ContainerType::MP4;
if (name.starts_with("mpc"))
- return ContainerType::MPC;
+ return core::media::ContainerType::MPC;
if (name == "mp3")
- return ContainerType::MPEG;
+ return core::media::ContainerType::MPEG;
if (name == "ogg")
- return ContainerType::Ogg;
+ return core::media::ContainerType::Ogg;
if (name == "shn")
- return ContainerType::Shorten;
+ return core::media::ContainerType::Shorten;
if (name == "tta")
- return ContainerType::TrueAudio;
+ return core::media::ContainerType::TrueAudio;
if (name == "wav")
- return ContainerType::WAV;
+ return core::media::ContainerType::WAV;
if (name == "wv")
- return ContainerType::WavPack;
+ return core::media::ContainerType::WavPack;
return std::nullopt;
}
- std::optional avcodecToCodecType(AVCodecID codec)
+ std::optional avcodecToCodecType(AVCodecID codec)
{
switch (codec)
{
case AV_CODEC_ID_AAC:
- return CodecType::AAC;
+ return core::media::CodecType::AAC;
case AV_CODEC_ID_AC3:
- return CodecType::AC3;
+ return core::media::CodecType::AC3;
case AV_CODEC_ID_ALAC:
- return CodecType::ALAC;
+ return core::media::CodecType::ALAC;
case AV_CODEC_ID_APE:
- return CodecType::APE;
+ return core::media::CodecType::APE;
case AV_CODEC_ID_DSD_LSBF:
case AV_CODEC_ID_DSD_LSBF_PLANAR:
case AV_CODEC_ID_DSD_MSBF:
case AV_CODEC_ID_DSD_MSBF_PLANAR:
- return CodecType::DSD;
+ return core::media::CodecType::DSD;
case AV_CODEC_ID_EAC3:
- return CodecType::EAC3;
+ return core::media::CodecType::EAC3;
case AV_CODEC_ID_FLAC:
- return CodecType::FLAC;
+ return core::media::CodecType::FLAC;
case AV_CODEC_ID_MP3:
- return CodecType::MP3;
+ return core::media::CodecType::MP3;
case AV_CODEC_ID_MP4ALS:
- return CodecType::MP4ALS;
+ return core::media::CodecType::MP4ALS;
case AV_CODEC_ID_MUSEPACK7:
- return CodecType::MPC7;
+ return core::media::CodecType::MPC7;
case AV_CODEC_ID_MUSEPACK8:
- return CodecType::MPC8;
+ return core::media::CodecType::MPC8;
case AV_CODEC_ID_OPUS:
- return CodecType::Opus;
+ return core::media::CodecType::Opus;
case AV_CODEC_ID_SHORTEN:
- return CodecType::Shorten;
+ return core::media::CodecType::Shorten;
case AV_CODEC_ID_VORBIS:
- return CodecType::Vorbis;
+ return core::media::CodecType::Vorbis;
case AV_CODEC_ID_WAVPACK:
- return CodecType::WavPack;
+ return core::media::CodecType::WavPack;
case AV_CODEC_ID_WMALOSSLESS:
- return CodecType::WMA9Lossless;
+ return core::media::CodecType::WMA9Lossless;
case AV_CODEC_ID_WMAPRO:
- return CodecType::WMA9Pro;
+ return core::media::CodecType::WMA9Pro;
case AV_CODEC_ID_WMAV1:
- return CodecType::WMA1;
+ return core::media::CodecType::WMA1;
case AV_CODEC_ID_WMAV2:
- return CodecType::WMA2;
+ return core::media::CodecType::WMA2;
default:
return std::nullopt;
diff --git a/src/libs/audio/impl/ffmpeg/AudioFile.hpp b/src/libs/audio/impl/ffmpeg/AudioFile.hpp
index fde8a031..61aa973c 100644
--- a/src/libs/audio/impl/ffmpeg/AudioFile.hpp
+++ b/src/libs/audio/impl/ffmpeg/AudioFile.hpp
@@ -27,7 +27,8 @@
#include
#include
-#include "audio/AudioTypes.hpp"
+#include "core/media/CodecType.hpp"
+#include "core/media/ContainerType.hpp"
extern "C"
{
@@ -44,7 +45,7 @@ namespace lms::audio::ffmpeg
struct ContainerInfo
{
- std::optional container;
+ std::optional container;
std::string containerName;
std::optional bitrate;
@@ -54,7 +55,7 @@ namespace lms::audio::ffmpeg
struct StreamInfo
{
size_t index{};
- std::optional codec;
+ std::optional codec;
std::string codecName;
std::optional bitrate;
diff --git a/src/libs/audio/impl/ffmpeg/AudioFileInfo.cpp b/src/libs/audio/impl/ffmpeg/AudioFileInfo.cpp
index 62fe54e4..e987412e 100644
--- a/src/libs/audio/impl/ffmpeg/AudioFileInfo.cpp
+++ b/src/libs/audio/impl/ffmpeg/AudioFileInfo.cpp
@@ -24,7 +24,7 @@
#include "core/ILogger.hpp"
-#include "audio/AudioTypes.hpp"
+#include "audio/AudioProperties.hpp"
#include "audio/IAudioFileInfo.hpp"
#include "AudioFile.hpp"
diff --git a/src/libs/audio/impl/ffmpeg/AudioFileInfo.hpp b/src/libs/audio/impl/ffmpeg/AudioFileInfo.hpp
index 8d89a766..e0874668 100644
--- a/src/libs/audio/impl/ffmpeg/AudioFileInfo.hpp
+++ b/src/libs/audio/impl/ffmpeg/AudioFileInfo.hpp
@@ -22,7 +22,7 @@
#include
#include
-#include "audio/AudioTypes.hpp"
+#include "audio/AudioProperties.hpp"
#include "audio/IAudioFileInfo.hpp"
#include "audio/IAudioFileInfoParser.hpp"
diff --git a/src/libs/audio/impl/ffmpeg/ImageReader.cpp b/src/libs/audio/impl/ffmpeg/ImageReader.cpp
index 8014ea93..cedd6b8c 100644
--- a/src/libs/audio/impl/ffmpeg/ImageReader.cpp
+++ b/src/libs/audio/impl/ffmpeg/ImageReader.cpp
@@ -45,9 +45,9 @@ namespace lms::audio::ffmpeg
image.data = picture.data;
image.mimeType = picture.mimeType;
if (metaDataHasKeyword(metaData, "front"))
- image.type = Image::Type::FrontCover;
+ image.type = core::media::ImageType::FrontCover;
else if (metaDataHasKeyword(metaData, "back"))
- image.type = Image::Type::BackCover;
+ image.type = core::media::ImageType::BackCover;
visitor(image);
});
diff --git a/src/libs/audio/impl/ffmpeg/Transcoder.cpp b/src/libs/audio/impl/ffmpeg/Transcoder.cpp
index cd6ea9d5..72261de6 100644
--- a/src/libs/audio/impl/ffmpeg/Transcoder.cpp
+++ b/src/libs/audio/impl/ffmpeg/Transcoder.cpp
@@ -19,13 +19,14 @@
#include "Transcoder.hpp"
-#include
+#include
#include
#include "core/IChildProcessManager.hpp"
#include "core/IConfig.hpp"
#include "core/ILogger.hpp"
#include "core/Service.hpp"
+#include "core/media/MimeType.hpp"
#include "audio/Exception.hpp"
#include "audio/TranscodeTypes.hpp"
@@ -42,18 +43,29 @@ namespace lms::audio::ffmpeg
{
#define LOG(severity, message) LMS_LOG(TRANSCODING, severity, "[" << _debugId << "] - " << message)
- static std::atomic globalId{};
- static std::filesystem::path ffmpegPath;
-
- void Transcoder::init()
+ namespace
{
- ffmpegPath = core::Service::get()->getPath("ffmpeg-file", "/usr/bin/ffmpeg");
- if (!std::filesystem::exists(ffmpegPath))
- throw Exception{ "File '" + ffmpegPath.string() + "' does not exist!" };
- }
+ class FFmpegPath
+ {
+ public:
+ FFmpegPath()
+ {
+ path = core::Service::get()->getPath("ffmpeg-file", "/usr/bin/ffmpeg");
+ if (!std::filesystem::exists(path))
+ throw Exception{ "File '" + path.string() + "' does not exist!" };
+ }
+
+ const std::filesystem::path& get() const { return path; }
+
+ private:
+ std::filesystem::path path;
+ };
+ } // namespace
+
+ std::atomic Transcoder::_nextDebugId;
Transcoder::Transcoder(const TranscodeParameters& parameters)
- : _debugId{ globalId++ }
+ : _debugId{ _nextDebugId++ }
, _inputParams{ parameters.inputParameters }
, _outputParams{ parameters.outputParameters }
{
@@ -64,8 +76,7 @@ namespace lms::audio::ffmpeg
void Transcoder::start()
{
- if (ffmpegPath.empty())
- init();
+ static FFmpegPath ffmpegPath;
try
{
@@ -76,15 +87,16 @@ namespace lms::audio::ffmpeg
}
catch (const std::filesystem::filesystem_error& e)
{
- // TODO store/raise e.code()
- throw Exception{ "File error '" + _inputParams.filePath.string() + "': " + e.what() };
+ throw IOFileException{ _inputParams.filePath, "Failed to test file existence", e.code() };
}
LOG(INFO, "Transcoding file " << _inputParams.filePath);
std::vector args;
- args.emplace_back(ffmpegPath.string());
+ args.emplace_back(ffmpegPath.get().string());
+
+ // TODO some codecs have restrictions, take them into account (channel count, sample rate, etc.)
// Make sure:
// - we do not produce anything in the stderr output
@@ -114,7 +126,7 @@ namespace lms::audio::ffmpeg
args.emplace_back("-1");
}
- // Skip video flows (including covers)
+ // Skip video flows (including covers!)
args.emplace_back("-vn");
// Output bitrates
@@ -124,63 +136,68 @@ namespace lms::audio::ffmpeg
args.emplace_back(std::to_string(*_outputParams.bitrate));
}
- // Codecs and formats
if (_outputParams.format)
{
- switch (*_outputParams.format)
+ args.emplace_back("-f");
+
+ switch (_outputParams.format->container)
{
- case OutputFormat::MP3:
- args.emplace_back("-f");
+ case core::media::ContainerType::FLAC:
+ args.emplace_back("flac");
+ break;
+ case core::media::ContainerType::Ogg:
+ args.emplace_back("ogg");
+ break;
+ case core::media::ContainerType::MPEG:
args.emplace_back("mp3");
break;
- case OutputFormat::OGG_OPUS:
- args.emplace_back("-acodec");
+ default:
+ throw Exception{ "Unsupported container type " + std::string{ core::media::containerTypeToString(_outputParams.format->container).str() } };
+ }
+
+ args.emplace_back("-acodec");
+
+ switch (_outputParams.format->codec)
+ {
+ case core::media::CodecType::MP3:
+ args.emplace_back("libmp3lame");
+ break;
+
+ case core::media::CodecType::Opus:
args.emplace_back("libopus");
- args.emplace_back("-f");
- args.emplace_back("ogg");
break;
- case OutputFormat::MATROSKA_OPUS:
- args.emplace_back("-acodec");
- args.emplace_back("libopus");
- args.emplace_back("-f");
- args.emplace_back("matroska");
- break;
-
- case OutputFormat::OGG_VORBIS:
- args.emplace_back("-acodec");
+ case core::media::CodecType::Vorbis:
args.emplace_back("libvorbis");
- args.emplace_back("-f");
- args.emplace_back("ogg");
break;
- case OutputFormat::WEBM_VORBIS:
- args.emplace_back("-acodec");
- args.emplace_back("libvorbis");
- args.emplace_back("-f");
- args.emplace_back("webm");
+ case core::media::CodecType::FLAC:
+ args.emplace_back("flac");
break;
default:
- throw Exception{ "Unhandled format (" + std::to_string(static_cast(*_outputParams.format)) + ")" };
+ throw Exception{ "Unhandled codec type " + std::string{ codecTypeToString(_outputParams.format->codec).str() } };
}
}
args.emplace_back("pipe:1");
- LOG(DEBUG, "Dumping args (" << args.size() << ")");
- for (const std::string& arg : args)
- LOG(DEBUG, "Arg = '" << arg << "'");
+ if (core::Service::get()->isSeverityActive(core::logging::Severity::DEBUG))
+ {
+ LOG(DEBUG, "Dumping args (" << args.size() << ")");
+ for (const std::string& arg : args)
+ LOG(DEBUG, "Arg = '" << arg << "'");
+ }
// Caution: stdin must have been closed before
try
{
- _childProcess = core::Service::get()->spawnChildProcess(ffmpegPath, args);
+ _childProcess = core::Service::get()->spawnChildProcess(ffmpegPath.get(), args);
}
catch (core::ChildProcessException& exception)
{
- throw Exception{ "Cannot execute '" + ffmpegPath.string() + "': " + exception.what() };
+ throw Exception{ "Cannot execute '" + ffmpegPath.get().string() + "': " + exception.what() };
}
}
@@ -202,25 +219,10 @@ namespace lms::audio::ffmpeg
std::string_view Transcoder::getOutputMimeType() const
{
- // TODO: use input mime type
if (_outputParams.format)
- {
- switch (*_outputParams.format)
- {
- case OutputFormat::MP3:
- return "audio/mpeg";
- case OutputFormat::OGG_OPUS:
- return "audio/opus";
- case OutputFormat::MATROSKA_OPUS:
- return "audio/x-matroska";
- case OutputFormat::OGG_VORBIS:
- return "audio/ogg";
- case OutputFormat::WEBM_VORBIS:
- return "audio/webm";
- }
- }
+ return core::media::getMimeType(_outputParams.format->container, _outputParams.format->codec).str();
- return "application/octet-stream"; // default, should not happen
+ return core::media::getMimeType(_inputParams.audioProperties.container, _inputParams.audioProperties.codec).str();
}
bool Transcoder::finished() const
diff --git a/src/libs/audio/impl/ffmpeg/Transcoder.hpp b/src/libs/audio/impl/ffmpeg/Transcoder.hpp
index 715c6d4f..7204922c 100644
--- a/src/libs/audio/impl/ffmpeg/Transcoder.hpp
+++ b/src/libs/audio/impl/ffmpeg/Transcoder.hpp
@@ -19,6 +19,8 @@
#pragma once
+#include
+
#include "audio/ITranscoder.hpp"
namespace lms::core
@@ -47,7 +49,8 @@ namespace lms::audio::ffmpeg
static void init();
void start();
- const std::size_t _debugId{};
+ static std::atomic _nextDebugId;
+ const std::size_t _debugId;
const TranscodeInputParameters _inputParams;
const TranscodeOutputParameters _outputParams;
std::unique_ptr _childProcess;
diff --git a/src/libs/audio/impl/taglib/AudioFileInfo.cpp b/src/libs/audio/impl/taglib/AudioFileInfo.cpp
index 02b41ed5..1a749dd7 100644
--- a/src/libs/audio/impl/taglib/AudioFileInfo.cpp
+++ b/src/libs/audio/impl/taglib/AudioFileInfo.cpp
@@ -45,7 +45,7 @@
#include "core/ILogger.hpp"
-#include "audio/AudioTypes.hpp"
+#include "audio/AudioProperties.hpp"
#include "audio/IAudioFileInfo.hpp"
#include "audio/IAudioFileInfoParser.hpp"
@@ -104,27 +104,27 @@ namespace lms::audio::taglib
// Guess container from the file type
if (const auto* apeFile{ dynamic_cast(&file) })
{
- audioProperties.container = ContainerType::APE;
- audioProperties.codec = CodecType::APE; // TODO version?
+ audioProperties.container = core::media::ContainerType::APE;
+ audioProperties.codec = core::media::CodecType::APE; // TODO version?
audioProperties.bitsPerSample = apeFile->audioProperties()->bitsPerSample();
}
else if (const auto* asfFile{ dynamic_cast(&file) })
{
- audioProperties.container = ContainerType::ASF;
+ audioProperties.container = core::media::ContainerType::ASF;
switch (asfFile->audioProperties()->codec())
{
case ::TagLib::ASF::Properties::Codec::WMA1:
- audioProperties.codec = CodecType::WMA1;
+ audioProperties.codec = core::media::CodecType::WMA1;
break;
case ::TagLib::ASF::Properties::Codec::WMA2:
- audioProperties.codec = CodecType::WMA2;
+ audioProperties.codec = core::media::CodecType::WMA2;
break;
case ::TagLib::ASF::Properties::Codec::WMA9Lossless:
- audioProperties.codec = CodecType::WMA9Lossless;
+ audioProperties.codec = core::media::CodecType::WMA9Lossless;
break;
case ::TagLib::ASF::Properties::Codec::WMA9Pro:
- audioProperties.codec = CodecType::WMA9Pro;
+ audioProperties.codec = core::media::CodecType::WMA9Pro;
break;
case ::TagLib::ASF::Properties::Codec::Unknown:
LMS_LOG(AUDIO, DEBUG, "Unhandled ASF codec in " << filePath);
@@ -136,27 +136,27 @@ namespace lms::audio::taglib
#if LMS_TAGLIB_HAS_DSF
else if (const auto* dsfFile{ dynamic_cast(&file) })
{
- audioProperties.container = ContainerType::DSF;
- audioProperties.codec = CodecType::DSD;
+ audioProperties.container = core::media::ContainerType::DSF;
+ audioProperties.codec = core::media::CodecType::DSD;
audioProperties.bitsPerSample = dsfFile->audioProperties()->bitsPerSample();
}
#endif // LMS_TAGLIB_HAS_DSF
else if (const auto* flacFile{ dynamic_cast(&file) })
{
- audioProperties.container = ContainerType::FLAC;
- audioProperties.codec = CodecType::FLAC;
+ audioProperties.container = core::media::ContainerType::FLAC;
+ audioProperties.codec = core::media::CodecType::FLAC;
audioProperties.bitsPerSample = flacFile->audioProperties()->bitsPerSample();
}
else if (const auto* mp4File{ dynamic_cast(&file) })
{
- audioProperties.container = ContainerType::MP4;
+ audioProperties.container = core::media::ContainerType::MP4;
switch (mp4File->audioProperties()->codec())
{
case ::TagLib::MP4::Properties::Codec::AAC:
- audioProperties.codec = CodecType::AAC;
+ audioProperties.codec = core::media::CodecType::AAC;
break;
case ::TagLib::MP4::Properties::Codec::ALAC:
- audioProperties.codec = CodecType::ALAC;
+ audioProperties.codec = core::media::CodecType::ALAC;
break;
case ::TagLib::MP4::Properties::Codec::Unknown:
LMS_LOG(AUDIO, DEBUG, "Unhandled MP4 codec in " << filePath);
@@ -167,15 +167,15 @@ namespace lms::audio::taglib
}
else if (const auto* mpcFile{ dynamic_cast(&file) })
{
- audioProperties.container = ContainerType::MPC;
+ audioProperties.container = core::media::ContainerType::MPC;
switch (mpcFile->audioProperties()->mpcVersion())
{
case 7:
- audioProperties.codec = CodecType::MPC7;
+ audioProperties.codec = core::media::CodecType::MPC7;
break;
case 8:
- audioProperties.codec = CodecType::MPC8;
+ audioProperties.codec = core::media::CodecType::MPC8;
break;
default:
LMS_LOG(AUDIO, DEBUG, "Unhandled MPC codec version " << mpcFile->audioProperties()->mpcVersion() << " in " << filePath);
@@ -186,13 +186,13 @@ namespace lms::audio::taglib
{
const auto& properties{ *mpegFile->audioProperties() };
- audioProperties.container = ContainerType::MPEG;
+ audioProperties.container = core::media::ContainerType::MPEG;
if ((properties.version() == TagLib::MPEG::Header::Version::Version1 || properties.version() == TagLib::MPEG::Header::Version::Version2 || properties.version() == TagLib::MPEG::Header::Version::Version2_5)
&& mpegFile->audioProperties()->layer() == 3)
- audioProperties.codec = CodecType::MP3; // could be MPEG-1 layer 3 or MPEG-2(.5) layer 3
+ audioProperties.codec = core::media::CodecType::MP3; // could be MPEG-1 layer 3 or MPEG-2(.5) layer 3
#if LMS_TAGLIB_HAS_ADTS
else if (mpegFile->audioProperties()->isADTS()) // likely AAC
- audioProperties.codec = CodecType::AAC;
+ audioProperties.codec = core::media::CodecType::AAC;
#endif
else
{
@@ -202,44 +202,44 @@ namespace lms::audio::taglib
}
else if (dynamic_cast(&file))
{
- audioProperties.container = ContainerType::Ogg;
- audioProperties.codec = CodecType::Opus;
+ audioProperties.container = core::media::ContainerType::Ogg;
+ audioProperties.codec = core::media::CodecType::Opus;
}
else if (dynamic_cast(&file))
{
- audioProperties.container = ContainerType::Ogg;
- audioProperties.codec = CodecType::Vorbis;
+ audioProperties.container = core::media::ContainerType::Ogg;
+ audioProperties.codec = core::media::CodecType::Vorbis;
}
else if (const auto* aiffFile{ dynamic_cast(&file) })
{
- audioProperties.container = ContainerType::AIFF;
- audioProperties.codec = CodecType::PCM;
+ audioProperties.container = core::media::ContainerType::AIFF;
+ audioProperties.codec = core::media::CodecType::PCM;
audioProperties.bitsPerSample = aiffFile->audioProperties()->bitsPerSample();
}
else if (const auto* wavFile{ dynamic_cast(&file) })
{
- audioProperties.container = ContainerType::WAV;
- audioProperties.codec = CodecType::PCM;
+ audioProperties.container = core::media::ContainerType::WAV;
+ audioProperties.codec = core::media::CodecType::PCM;
audioProperties.bitsPerSample = wavFile->audioProperties()->bitsPerSample();
}
#if LMS_TAGLIB_HAS_SHORTEN
else if (const auto* shortenFile{ dynamic_cast(&file) })
{
- audioProperties.container = ContainerType::Shorten;
- audioProperties.codec = CodecType::Shorten;
+ audioProperties.container = core::media::ContainerType::Shorten;
+ audioProperties.codec = core::media::CodecType::Shorten;
audioProperties.bitsPerSample = shortenFile->audioProperties()->bitsPerSample();
}
#endif // LMS_TAGLIB_HAS_SHORTEN
else if (const auto* trueAudioFile{ dynamic_cast(&file) })
{
- audioProperties.container = ContainerType::TrueAudio;
- audioProperties.codec = CodecType::TrueAudio;
+ audioProperties.container = core::media::ContainerType::TrueAudio;
+ audioProperties.codec = core::media::CodecType::TrueAudio;
audioProperties.bitsPerSample = trueAudioFile->audioProperties()->bitsPerSample();
}
else if (const auto* wavPackFile{ dynamic_cast(&file) })
{
- audioProperties.container = ContainerType::WavPack;
- audioProperties.codec = CodecType::WavPack;
+ audioProperties.container = core::media::ContainerType::WavPack;
+ audioProperties.codec = core::media::CodecType::WavPack;
audioProperties.bitsPerSample = wavPackFile->audioProperties()->bitsPerSample();
}
else
diff --git a/src/libs/audio/impl/taglib/AudioFileInfo.hpp b/src/libs/audio/impl/taglib/AudioFileInfo.hpp
index 4dca6f08..00d734ac 100644
--- a/src/libs/audio/impl/taglib/AudioFileInfo.hpp
+++ b/src/libs/audio/impl/taglib/AudioFileInfo.hpp
@@ -22,7 +22,7 @@
#include
#include
-#include "audio/AudioTypes.hpp"
+#include "audio/AudioProperties.hpp"
#include "audio/IAudioFileInfo.hpp"
#include "audio/IAudioFileInfoParser.hpp"
#include "audio/IImageReader.hpp"
diff --git a/src/libs/audio/impl/taglib/ImageReader.cpp b/src/libs/audio/impl/taglib/ImageReader.cpp
index adad0a24..35378549 100644
--- a/src/libs/audio/impl/taglib/ImageReader.cpp
+++ b/src/libs/audio/impl/taglib/ImageReader.cpp
@@ -44,157 +44,157 @@ namespace lms::audio::taglib
{
namespace
{
- Image::Type imageTypeFromfromID3v2(TagLib::ID3v2::AttachedPictureFrame::Type type)
+ core::media::ImageType imageTypeFromfromID3v2(TagLib::ID3v2::AttachedPictureFrame::Type type)
{
switch (type)
{
case ::TagLib::ID3v2::AttachedPictureFrame::Type::Other:
- return Image::Type::Other;
+ return core::media::ImageType::Other;
case ::TagLib::ID3v2::AttachedPictureFrame::Type::FileIcon:
- return Image::Type::FileIcon;
+ return core::media::ImageType::FileIcon;
case ::TagLib::ID3v2::AttachedPictureFrame::Type::OtherFileIcon:
- return Image::Type::OtherFileIcon;
+ return core::media::ImageType::OtherFileIcon;
case ::TagLib::ID3v2::AttachedPictureFrame::Type::FrontCover:
- return Image::Type::FrontCover;
+ return core::media::ImageType::FrontCover;
case ::TagLib::ID3v2::AttachedPictureFrame::Type::BackCover:
- return Image::Type::BackCover;
+ return core::media::ImageType::BackCover;
case ::TagLib::ID3v2::AttachedPictureFrame::Type::LeafletPage:
- return Image::Type::LeafletPage;
+ return core::media::ImageType::LeafletPage;
case ::TagLib::ID3v2::AttachedPictureFrame::Type::Media:
- return Image::Type::Media;
+ return core::media::ImageType::Media;
case ::TagLib::ID3v2::AttachedPictureFrame::Type::LeadArtist:
- return Image::Type::LeadArtist;
+ return core::media::ImageType::LeadArtist;
case ::TagLib::ID3v2::AttachedPictureFrame::Type::Artist:
- return Image::Type::Artist;
+ return core::media::ImageType::Artist;
case ::TagLib::ID3v2::AttachedPictureFrame::Type::Conductor:
- return Image::Type::Conductor;
+ return core::media::ImageType::Conductor;
case ::TagLib::ID3v2::AttachedPictureFrame::Type::Band:
- return Image::Type::Band;
+ return core::media::ImageType::Band;
case ::TagLib::ID3v2::AttachedPictureFrame::Type::Composer:
- return Image::Type::Composer;
+ return core::media::ImageType::Composer;
case ::TagLib::ID3v2::AttachedPictureFrame::Type::Lyricist:
- return Image::Type::Lyricist;
+ return core::media::ImageType::Lyricist;
case ::TagLib::ID3v2::AttachedPictureFrame::Type::RecordingLocation:
- return Image::Type::RecordingLocation;
+ return core::media::ImageType::RecordingLocation;
case ::TagLib::ID3v2::AttachedPictureFrame::Type::DuringRecording:
- return Image::Type::DuringRecording;
+ return core::media::ImageType::DuringRecording;
case ::TagLib::ID3v2::AttachedPictureFrame::Type::DuringPerformance:
- return Image::Type::DuringPerformance;
+ return core::media::ImageType::DuringPerformance;
case ::TagLib::ID3v2::AttachedPictureFrame::Type::MovieScreenCapture:
- return Image::Type::MovieScreenCapture;
+ return core::media::ImageType::MovieScreenCapture;
case ::TagLib::ID3v2::AttachedPictureFrame::Type::ColouredFish:
- return Image::Type::ColouredFish;
+ return core::media::ImageType::ColouredFish;
case ::TagLib::ID3v2::AttachedPictureFrame::Type::Illustration:
- return Image::Type::Illustration;
+ return core::media::ImageType::Illustration;
case ::TagLib::ID3v2::AttachedPictureFrame::Type::BandLogo:
- return Image::Type::BandLogo;
+ return core::media::ImageType::BandLogo;
case ::TagLib::ID3v2::AttachedPictureFrame::Type::PublisherLogo:
- return Image::Type::PublisherLogo;
+ return core::media::ImageType::PublisherLogo;
}
- return Image::Type::Unknown;
+ return core::media::ImageType::Unknown;
}
- Image::Type imageTypeFromfromASF(TagLib::ASF::Picture::Type type)
+ core::media::ImageType imageTypeFromfromASF(TagLib::ASF::Picture::Type type)
{
switch (type)
{
case ::TagLib::ASF::Picture::Type::Other:
- return Image::Type::Other;
+ return core::media::ImageType::Other;
case ::TagLib::ASF::Picture::Type::FileIcon:
- return Image::Type::FileIcon;
+ return core::media::ImageType::FileIcon;
case ::TagLib::ASF::Picture::Type::OtherFileIcon:
- return Image::Type::OtherFileIcon;
+ return core::media::ImageType::OtherFileIcon;
case ::TagLib::ASF::Picture::Type::FrontCover:
- return Image::Type::FrontCover;
+ return core::media::ImageType::FrontCover;
case ::TagLib::ASF::Picture::Type::BackCover:
- return Image::Type::BackCover;
+ return core::media::ImageType::BackCover;
case ::TagLib::ASF::Picture::Type::LeafletPage:
- return Image::Type::LeafletPage;
+ return core::media::ImageType::LeafletPage;
case ::TagLib::ASF::Picture::Type::Media:
- return Image::Type::Media;
+ return core::media::ImageType::Media;
case ::TagLib::ASF::Picture::Type::LeadArtist:
- return Image::Type::LeadArtist;
+ return core::media::ImageType::LeadArtist;
case ::TagLib::ASF::Picture::Type::Artist:
- return Image::Type::Artist;
+ return core::media::ImageType::Artist;
case ::TagLib::ASF::Picture::Type::Conductor:
- return Image::Type::Conductor;
+ return core::media::ImageType::Conductor;
case ::TagLib::ASF::Picture::Type::Band:
- return Image::Type::Band;
+ return core::media::ImageType::Band;
case ::TagLib::ASF::Picture::Type::Composer:
- return Image::Type::Composer;
+ return core::media::ImageType::Composer;
case ::TagLib::ASF::Picture::Type::Lyricist:
- return Image::Type::Lyricist;
+ return core::media::ImageType::Lyricist;
case ::TagLib::ASF::Picture::Type::RecordingLocation:
- return Image::Type::RecordingLocation;
+ return core::media::ImageType::RecordingLocation;
case ::TagLib::ASF::Picture::Type::DuringRecording:
- return Image::Type::DuringRecording;
+ return core::media::ImageType::DuringRecording;
case ::TagLib::ASF::Picture::Type::DuringPerformance:
- return Image::Type::DuringPerformance;
+ return core::media::ImageType::DuringPerformance;
case ::TagLib::ASF::Picture::Type::MovieScreenCapture:
- return Image::Type::MovieScreenCapture;
+ return core::media::ImageType::MovieScreenCapture;
case ::TagLib::ASF::Picture::Type::ColouredFish:
- return Image::Type::ColouredFish;
+ return core::media::ImageType::ColouredFish;
case ::TagLib::ASF::Picture::Type::Illustration:
- return Image::Type::Illustration;
+ return core::media::ImageType::Illustration;
case ::TagLib::ASF::Picture::Type::BandLogo:
- return Image::Type::BandLogo;
+ return core::media::ImageType::BandLogo;
case ::TagLib::ASF::Picture::Type::PublisherLogo:
- return Image::Type::PublisherLogo;
+ return core::media::ImageType::PublisherLogo;
}
- return Image::Type::Unknown;
+ return core::media::ImageType::Unknown;
}
- Image::Type imageTypeFromfromFLAC(TagLib::FLAC::Picture::Type type)
+ core::media::ImageType imageTypeFromfromFLAC(TagLib::FLAC::Picture::Type type)
{
switch (type)
{
case ::TagLib::FLAC::Picture::Type::Other:
- return Image::Type::Other;
+ return core::media::ImageType::Other;
case ::TagLib::FLAC::Picture::Type::FileIcon:
- return Image::Type::FileIcon;
+ return core::media::ImageType::FileIcon;
case ::TagLib::FLAC::Picture::Type::OtherFileIcon:
- return Image::Type::OtherFileIcon;
+ return core::media::ImageType::OtherFileIcon;
case ::TagLib::FLAC::Picture::Type::FrontCover:
- return Image::Type::FrontCover;
+ return core::media::ImageType::FrontCover;
case ::TagLib::FLAC::Picture::Type::BackCover:
- return Image::Type::BackCover;
+ return core::media::ImageType::BackCover;
case ::TagLib::FLAC::Picture::Type::LeafletPage:
- return Image::Type::LeafletPage;
+ return core::media::ImageType::LeafletPage;
case ::TagLib::FLAC::Picture::Type::Media:
- return Image::Type::Media;
+ return core::media::ImageType::Media;
case ::TagLib::FLAC::Picture::Type::LeadArtist:
- return Image::Type::LeadArtist;
+ return core::media::ImageType::LeadArtist;
case ::TagLib::FLAC::Picture::Type::Artist:
- return Image::Type::Artist;
+ return core::media::ImageType::Artist;
case ::TagLib::FLAC::Picture::Type::Conductor:
- return Image::Type::Conductor;
+ return core::media::ImageType::Conductor;
case ::TagLib::FLAC::Picture::Type::Band:
- return Image::Type::Band;
+ return core::media::ImageType::Band;
case ::TagLib::FLAC::Picture::Type::Composer:
- return Image::Type::Composer;
+ return core::media::ImageType::Composer;
case ::TagLib::FLAC::Picture::Type::Lyricist:
- return Image::Type::Lyricist;
+ return core::media::ImageType::Lyricist;
case ::TagLib::FLAC::Picture::Type::RecordingLocation:
- return Image::Type::RecordingLocation;
+ return core::media::ImageType::RecordingLocation;
case ::TagLib::FLAC::Picture::Type::DuringRecording:
- return Image::Type::DuringRecording;
+ return core::media::ImageType::DuringRecording;
case ::TagLib::FLAC::Picture::Type::DuringPerformance:
- return Image::Type::DuringPerformance;
+ return core::media::ImageType::DuringPerformance;
case ::TagLib::FLAC::Picture::Type::MovieScreenCapture:
- return Image::Type::MovieScreenCapture;
+ return core::media::ImageType::MovieScreenCapture;
case ::TagLib::FLAC::Picture::Type::ColouredFish:
- return Image::Type::ColouredFish;
+ return core::media::ImageType::ColouredFish;
case ::TagLib::FLAC::Picture::Type::Illustration:
- return Image::Type::Illustration;
+ return core::media::ImageType::Illustration;
case ::TagLib::FLAC::Picture::Type::BandLogo:
- return Image::Type::BandLogo;
+ return core::media::ImageType::BandLogo;
case ::TagLib::FLAC::Picture::Type::PublisherLogo:
- return Image::Type::PublisherLogo;
+ return core::media::ImageType::PublisherLogo;
}
- return Image::Type::Unknown;
+ return core::media::ImageType::Unknown;
}
const char* mp4ImageFormatToMimeType(TagLib::MP4::CoverArt::Format format)
@@ -217,14 +217,14 @@ namespace lms::audio::taglib
}
#if LMS_TAGLIB_HAS_APE_COMPLEX_PROPERTIES
- Image::Type imageTypeFromAPEPictureType(std::string_view pictureType)
+ core::media::ImageType imageTypeFromAPEPictureType(std::string_view pictureType)
{
if (core::stringUtils::stringCaseInsensitiveContains(pictureType, "front"))
- return Image::Type::FrontCover;
+ return core::media::ImageType::FrontCover;
if (core::stringUtils::stringCaseInsensitiveContains(pictureType, "back"))
- return Image::Type::BackCover;
+ return core::media::ImageType::BackCover;
- return Image::Type::Unknown;
+ return core::media::ImageType::Unknown;
}
#endif // LMS_TAGLIB_HAS_APE_COMPLEX_PROPERTIES
@@ -294,7 +294,7 @@ namespace lms::audio::taglib
image.data = pictureData;
// By convention, consider the first cover art as the front cover
- image.type = firstCover ? Image::Type::FrontCover : Image::Type::Unknown;
+ image.type = firstCover ? core::media::ImageType::FrontCover : core::media::ImageType::Unknown;
firstCover = false;
visitor(image);
diff --git a/src/libs/audio/impl/taglib/Utils.cpp b/src/libs/audio/impl/taglib/Utils.cpp
index 121a2a6a..594a8b10 100644
--- a/src/libs/audio/impl/taglib/Utils.cpp
+++ b/src/libs/audio/impl/taglib/Utils.cpp
@@ -111,7 +111,7 @@ namespace lms::audio::taglib::utils
{
const std::error_code ec{ errno, std::generic_category() };
LMS_LOG(METADATA, DEBUG, "fopen failed for " << p << ": " << ec.message());
- throw IOFileException{ "fopen failed", ec };
+ throw IOFileException{ p, "fopen failed", ec };
}
int fd{ ::fileno(file) };
@@ -119,7 +119,7 @@ namespace lms::audio::taglib::utils
{
const std::error_code ec{ errno, std::generic_category() };
LMS_LOG(METADATA, DEBUG, "fileno failed for " << p << ": " << ec.message());
- throw IOFileException{ "fileno failed", ec };
+ throw IOFileException{ p, "fileno failed", ec };
}
return TagLib::FileStream{ fd, true };
diff --git a/src/libs/audio/include/audio/AudioProperties.hpp b/src/libs/audio/include/audio/AudioProperties.hpp
new file mode 100644
index 00000000..2b70ee7f
--- /dev/null
+++ b/src/libs/audio/include/audio/AudioProperties.hpp
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2025 Emeric Poupon
+ *
+ * This file is part of LMS.
+ *
+ * LMS is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * LMS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with LMS. If not, see .
+ */
+
+#pragma once
+
+#include
+#include
+
+#include "core/media/CodecType.hpp"
+#include "core/media/ContainerType.hpp"
+
+namespace lms::audio
+{
+ struct AudioProperties
+ {
+ core::media::ContainerType container;
+ core::media::CodecType codec;
+ std::chrono::milliseconds duration;
+ unsigned bitrate;
+ unsigned channelCount;
+ unsigned sampleRate;
+ std::optional bitsPerSample;
+ };
+} // namespace lms::audio
\ No newline at end of file
diff --git a/src/libs/audio/include/audio/Exception.hpp b/src/libs/audio/include/audio/Exception.hpp
index 6c3c9e52..feaa9560 100644
--- a/src/libs/audio/include/audio/Exception.hpp
+++ b/src/libs/audio/include/audio/Exception.hpp
@@ -19,6 +19,7 @@
#pragma once
+#include
#include
#include "core/Exception.hpp"
@@ -34,15 +35,18 @@ namespace lms::audio
class IOFileException : public Exception
{
public:
- IOFileException(std::string_view message, std::error_code err)
- : Exception{ std::string{ message } + ": " + err.message() }
+ IOFileException(const std::filesystem::path& path, std::string_view message, std::error_code err)
+ : Exception{ "File '" + path.string() + "': " + std::string{ message } + ": " + err.message() }
+ , _path{ path }
, _err{ err }
{
}
+ const std::filesystem::path& getPath() const { return _path; }
std::error_code getErrorCode() const { return _err; }
private:
+ std::filesystem::path _path;
std::error_code _err;
};
diff --git a/src/libs/audio/include/audio/IImageReader.hpp b/src/libs/audio/include/audio/IImageReader.hpp
index 0063151c..8d301b45 100644
--- a/src/libs/audio/include/audio/IImageReader.hpp
+++ b/src/libs/audio/include/audio/IImageReader.hpp
@@ -23,69 +23,18 @@
#include
#include
-#include "core/LiteralString.hpp"
+#include "core/media/ImageType.hpp"
namespace lms::audio
{
struct Image
{
- // See TagLib types (based on ID3v2 APIC types)
- enum class Type
- {
- // No information
- Unknown,
- // A type not enumerated below
- Other,
- // 32x32 PNG image that should be used as the file icon
- FileIcon,
- // File icon of a different size or format
- OtherFileIcon,
- // Front cover image of the album
- FrontCover,
- // Back cover image of the album
- BackCover,
- // Inside leaflet page of the album
- LeafletPage,
- // Image from the album itself
- Media,
- // Picture of the lead artist or soloist
- LeadArtist,
- // Picture of the artist or performer
- Artist,
- // Picture of the conductor
- Conductor,
- // Picture of the band or orchestra
- Band,
- // Picture of the composer
- Composer,
- // Picture of the lyricist or text writer
- Lyricist,
- // Picture of the recording location or studio
- RecordingLocation,
- // Picture of the artists during recording
- DuringRecording,
- // Picture of the artists during performance
- DuringPerformance,
- // Picture from a movie or video related to the track
- MovieScreenCapture,
- // Picture of a large, coloured fish
- ColouredFish,
- // Illustration related to the track
- Illustration,
- // Logo of the band or performer
- BandLogo,
- // Logo of the publisher (record company)
- PublisherLogo
- };
-
- Type type{ Type::Unknown };
+ core::media::ImageType type{ core::media::ImageType::Unknown };
std::string mimeType{ "application/octet-stream" };
std::string description;
std::span data;
};
- core::LiteralString imageTypeToString(Image::Type type);
-
class IImageReader
{
public:
diff --git a/src/libs/audio/include/audio/TranscodeTypes.hpp b/src/libs/audio/include/audio/TranscodeTypes.hpp
index 1aaf34cf..a2324646 100644
--- a/src/libs/audio/include/audio/TranscodeTypes.hpp
+++ b/src/libs/audio/include/audio/TranscodeTypes.hpp
@@ -23,28 +23,30 @@
#include
#include
+#include "core/media/CodecType.hpp"
+#include "core/media/ContainerType.hpp"
+
+#include "audio/AudioProperties.hpp"
+
namespace lms::audio
{
- // TODO deprecate?
- enum class OutputFormat
- {
- MP3,
- OGG_OPUS,
- MATROSKA_OPUS,
- OGG_VORBIS,
- WEBM_VORBIS,
- };
-
struct TranscodeInputParameters
{
std::filesystem::path filePath;
- std::chrono::milliseconds duration{}; // Duration of the audio file
- std::chrono::milliseconds offset{}; // Offset in the audio file to start transcoding from
+ AudioProperties audioProperties; // properties of the audio file
+ std::chrono::milliseconds offset{}; // Offset in the audio file to start transcoding from
+ };
+
+ struct TranscodeOutputFormat
+ {
+ core::media::ContainerType container;
+ core::media::CodecType codec;
};
struct TranscodeOutputParameters
{
- std::optional format;
+ // Not setting a value here means to use the same value as the input
+ std::optional format;
std::optional bitrate;
std::optional bitsPerSample;
std::optional channelCount;
diff --git a/src/libs/core/CMakeLists.txt b/src/libs/core/CMakeLists.txt
index d25b4264..0ddfff3a 100644
--- a/src/libs/core/CMakeLists.txt
+++ b/src/libs/core/CMakeLists.txt
@@ -13,6 +13,10 @@ configure_file(
add_library(lmscore STATIC
impl/http/Client.cpp
impl/http/SendQueue.cpp
+ impl/media/CodecType.cpp
+ impl/media/ContainerType.cpp
+ impl/media/ImageType.cpp
+ impl/media/MimeType.cpp
impl/ArchiveZipper.cpp
impl/ChildProcess.cpp
impl/ChildProcessManager.cpp
diff --git a/src/libs/audio/impl/AudioTypes.cpp b/src/libs/core/impl/media/CodecType.cpp
similarity index 66%
rename from src/libs/audio/impl/AudioTypes.cpp
rename to src/libs/core/impl/media/CodecType.cpp
index ad360bcb..b5b778f0 100644
--- a/src/libs/audio/impl/AudioTypes.cpp
+++ b/src/libs/core/impl/media/CodecType.cpp
@@ -17,45 +17,10 @@
* along with LMS. If not, see .
*/
-#include "audio/AudioTypes.hpp"
+#include "core/media/CodecType.hpp"
-namespace lms::audio
+namespace lms::core::media
{
- core::LiteralString containerTypeToString(ContainerType type)
- {
- switch (type)
- {
- case ContainerType::AIFF:
- return "AIFF";
- case ContainerType::APE:
- return "APE";
- case ContainerType::ASF:
- return "ASF";
- case ContainerType::DSF:
- return "DSF";
- case ContainerType::FLAC:
- return "FLAC";
- case ContainerType::MP4:
- return "MP4";
- case ContainerType::MPC:
- return "MPC";
- case ContainerType::MPEG:
- return "MPEG";
- case ContainerType::Ogg:
- return "Ogg";
- case ContainerType::Shorten:
- return "Shorten";
- case ContainerType::TrueAudio:
- return "TrueAudio";
- case ContainerType::WAV:
- return "WAV";
- case ContainerType::WavPack:
- return "WavPack";
- }
-
- return "";
- }
-
core::LiteralString codecTypeToString(CodecType type)
{
switch (type)
@@ -104,6 +69,6 @@ namespace lms::audio
return "WMA9Lossless";
}
- return "";
+ return "Unknown";
}
-} // namespace lms::audio
\ No newline at end of file
+} // namespace lms::core::media
\ No newline at end of file
diff --git a/src/libs/core/impl/media/ContainerType.cpp b/src/libs/core/impl/media/ContainerType.cpp
new file mode 100644
index 00000000..cf1fe447
--- /dev/null
+++ b/src/libs/core/impl/media/ContainerType.cpp
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2025 Emeric Poupon
+ *
+ * This file is part of LMS.
+ *
+ * LMS is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * LMS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with LMS. If not, see .
+ */
+
+#include "core/media/ContainerType.hpp"
+
+namespace lms::core::media
+{
+ core::LiteralString containerTypeToString(ContainerType type)
+ {
+ switch (type)
+ {
+ case ContainerType::AIFF:
+ return "AIFF";
+ case ContainerType::APE:
+ return "APE";
+ case ContainerType::ASF:
+ return "ASF";
+ case ContainerType::DSF:
+ return "DSF";
+ case ContainerType::FLAC:
+ return "FLAC";
+ case ContainerType::MP4:
+ return "MP4";
+ case ContainerType::MPC:
+ return "MPC";
+ case ContainerType::MPEG:
+ return "MPEG";
+ case ContainerType::Ogg:
+ return "Ogg";
+ case ContainerType::Shorten:
+ return "Shorten";
+ case ContainerType::TrueAudio:
+ return "TrueAudio";
+ case ContainerType::WAV:
+ return "WAV";
+ case ContainerType::WavPack:
+ return "WavPack";
+ }
+
+ return "Unknown";
+ }
+} // namespace lms::core::media
\ No newline at end of file
diff --git a/src/libs/audio/impl/ImageReader.cpp b/src/libs/core/impl/media/ImageType.cpp
similarity index 59%
rename from src/libs/audio/impl/ImageReader.cpp
rename to src/libs/core/impl/media/ImageType.cpp
index 7b314875..894f1150 100644
--- a/src/libs/audio/impl/ImageReader.cpp
+++ b/src/libs/core/impl/media/ImageType.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2015 Emeric Poupon
+ * Copyright (C) 2025 Emeric Poupon
*
* This file is part of LMS.
*
@@ -17,61 +17,60 @@
* along with LMS. If not, see .
*/
-#include "audio/IImageReader.hpp"
+#include "core/media/ImageType.hpp"
-namespace lms::audio
+namespace lms::core::media
{
- core::LiteralString imageTypeToString(Image::Type type)
+ core::LiteralString imageTypeToString(ImageType type)
{
switch (type)
{
- case Image::Type::Other:
+ case ImageType::Other:
return "Other";
- case Image::Type::FileIcon:
+ case ImageType::FileIcon:
return "FileIcon";
- case Image::Type::OtherFileIcon:
+ case ImageType::OtherFileIcon:
return "OtherFileIcon";
- case Image::Type::FrontCover:
+ case ImageType::FrontCover:
return "FrontCover";
- case Image::Type::BackCover:
+ case ImageType::BackCover:
return "BackCover";
- case Image::Type::LeafletPage:
+ case ImageType::LeafletPage:
return "LeafletPage";
- case Image::Type::Media:
+ case ImageType::Media:
return "Media";
- case Image::Type::LeadArtist:
+ case ImageType::LeadArtist:
return "LeadArtist";
- case Image::Type::Artist:
+ case ImageType::Artist:
return "Artist";
- case Image::Type::Conductor:
+ case ImageType::Conductor:
return "Conductor";
- case Image::Type::Band:
+ case ImageType::Band:
return "Band";
- case Image::Type::Composer:
+ case ImageType::Composer:
return "Composer";
- case Image::Type::Lyricist:
+ case ImageType::Lyricist:
return "Lyricist";
- case Image::Type::RecordingLocation:
+ case ImageType::RecordingLocation:
return "RecordingLocation";
- case Image::Type::DuringRecording:
+ case ImageType::DuringRecording:
return "DuringRecording";
- case Image::Type::DuringPerformance:
+ case ImageType::DuringPerformance:
return "DuringPerformance";
- case Image::Type::MovieScreenCapture:
+ case ImageType::MovieScreenCapture:
return "MovieScreenCapture";
- case Image::Type::ColouredFish:
+ case ImageType::ColouredFish:
return "ColouredFish";
- case Image::Type::Illustration:
+ case ImageType::Illustration:
return "Illustration";
- case Image::Type::BandLogo:
+ case ImageType::BandLogo:
return "BandLogo";
- case Image::Type::PublisherLogo:
+ case ImageType::PublisherLogo:
return "PublisherLogo";
- case Image::Type::Unknown:
+ case ImageType::Unknown:
break;
}
return "Unknown";
}
-
-} // namespace lms::audio
\ No newline at end of file
+} // namespace lms::core::media
\ No newline at end of file
diff --git a/src/libs/core/impl/media/MimeType.cpp b/src/libs/core/impl/media/MimeType.cpp
new file mode 100644
index 00000000..aa8d1d1f
--- /dev/null
+++ b/src/libs/core/impl/media/MimeType.cpp
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2025 Emeric Poupon
+ *
+ * This file is part of LMS.
+ *
+ * LMS is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * LMS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with LMS. If not, see .
+ */
+
+#include "core/media/MimeType.hpp"
+
+namespace lms::core::media
+{
+ core::LiteralString getMimeType(ContainerType container, CodecType codec)
+ {
+ switch (container)
+ {
+ case ContainerType::AIFF:
+ return "audio/x-aiff";
+ case ContainerType::APE:
+ return "audio/x-monkeys-audio";
+ case ContainerType::ASF:
+ return "audio/x-ms-wma";
+ case ContainerType::DSF:
+ return "audio/x-dsd-dsf";
+ case ContainerType::FLAC:
+ return "audio/flac";
+ case ContainerType::MP4:
+ switch (codec)
+ {
+ case CodecType::AAC:
+ return "audio/mp4; codecs=\"mp4a.40.2\"";
+ case CodecType::ALAC:
+ return "audio/mp4; codecs=\"alac\"";
+ case CodecType::MP4ALS:
+ return "audio/mp4; codecs=\"mp4als\"";
+ default:
+ return "audio/mp4";
+ }
+
+ case ContainerType::MPC:
+ return "audio/x-musepack";
+ case ContainerType::MPEG:
+ return "audio/mpeg";
+ case ContainerType::Ogg:
+ switch (codec)
+ {
+ case CodecType::Opus:
+ return "audio/opus";
+ case CodecType::Vorbis:
+ return "audio/ogg; codecs=\"vorbis\"";
+ case CodecType::FLAC:
+ return "audio/ogg; codecs=\"flac\"";
+ default:
+ return "audio/ogg";
+ }
+
+ case ContainerType::Shorten:
+ return "audio/x-shn";
+ case ContainerType::TrueAudio:
+ return "audio/x-tta";
+ case ContainerType::WAV:
+ return "audio/wav";
+ case ContainerType::WavPack:
+ return "audio/x-wavpack";
+ }
+
+ return "application/octet-stream";
+ }
+} // namespace lms::core::media
\ No newline at end of file
diff --git a/src/libs/audio/include/audio/AudioTypes.hpp b/src/libs/core/include/core/media/CodecType.hpp
similarity index 65%
rename from src/libs/audio/include/audio/AudioTypes.hpp
rename to src/libs/core/include/core/media/CodecType.hpp
index 952f9c14..dac67e6d 100644
--- a/src/libs/audio/include/audio/AudioTypes.hpp
+++ b/src/libs/core/include/core/media/CodecType.hpp
@@ -19,32 +19,10 @@
#pragma once
-#include
-#include
-
#include "core/LiteralString.hpp"
-namespace lms::audio
+namespace lms::core::media
{
- enum class ContainerType
- {
- AIFF,
- APE, // Monkey's Audio
- ASF, // Advanced Systems Format
- DSF,
- FLAC,
- MP4,
- MPC, // Musepack
- MPEG,
- Ogg,
- Shorten,
- TrueAudio,
- WAV,
- WavPack,
- };
-
- core::LiteralString containerTypeToString(ContainerType type);
-
enum class CodecType
{
AAC,
@@ -71,15 +49,4 @@ namespace lms::audio
};
core::LiteralString codecTypeToString(CodecType type);
-
- struct AudioProperties
- {
- ContainerType container;
- CodecType codec;
- std::chrono::milliseconds duration;
- unsigned bitrate;
- unsigned channelCount;
- unsigned sampleRate;
- std::optional bitsPerSample;
- };
-} // namespace lms::audio
\ No newline at end of file
+} // namespace lms::core::media
\ No newline at end of file
diff --git a/src/libs/core/include/core/media/ContainerType.hpp b/src/libs/core/include/core/media/ContainerType.hpp
new file mode 100644
index 00000000..709d8203
--- /dev/null
+++ b/src/libs/core/include/core/media/ContainerType.hpp
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2025 Emeric Poupon
+ *
+ * This file is part of LMS.
+ *
+ * LMS is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * LMS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with LMS. If not, see .
+ */
+
+#pragma once
+
+#include "core/LiteralString.hpp"
+
+namespace lms::core::media
+{
+ enum class ContainerType
+ {
+ AIFF,
+ APE, // Monkey's Audio
+ ASF, // Advanced Systems Format
+ DSF,
+ FLAC,
+ MP4,
+ MPC, // Musepack
+ MPEG,
+ Ogg,
+ Shorten,
+ TrueAudio,
+ WAV,
+ WavPack,
+ };
+
+ core::LiteralString containerTypeToString(ContainerType type);
+} // namespace lms::core::media
\ No newline at end of file
diff --git a/src/libs/core/include/core/media/ImageType.hpp b/src/libs/core/include/core/media/ImageType.hpp
new file mode 100644
index 00000000..de710938
--- /dev/null
+++ b/src/libs/core/include/core/media/ImageType.hpp
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2025 Emeric Poupon
+ *
+ * This file is part of LMS.
+ *
+ * LMS is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * LMS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with LMS. If not, see .
+ */
+
+#pragma once
+
+#include "core/LiteralString.hpp"
+
+namespace lms::core::media
+{
+ // Based on ID3v2 APIC types
+ enum class ImageType
+ {
+ // No information
+ Unknown,
+ // A type not enumerated below
+ Other,
+ // 32x32 PNG image that should be used as the file icon
+ FileIcon,
+ // File icon of a different size or format
+ OtherFileIcon,
+ // Front cover image of the album
+ FrontCover,
+ // Back cover image of the album
+ BackCover,
+ // Inside leaflet page of the album
+ LeafletPage,
+ // Image from the album itself
+ Media,
+ // Picture of the lead artist or soloist
+ LeadArtist,
+ // Picture of the artist or performer
+ Artist,
+ // Picture of the conductor
+ Conductor,
+ // Picture of the band or orchestra
+ Band,
+ // Picture of the composer
+ Composer,
+ // Picture of the lyricist or text writer
+ Lyricist,
+ // Picture of the recording location or studio
+ RecordingLocation,
+ // Picture of the artists during recording
+ DuringRecording,
+ // Picture of the artists during performance
+ DuringPerformance,
+ // Picture from a movie or video related to the track
+ MovieScreenCapture,
+ // Picture of a large, coloured fish
+ ColouredFish,
+ // Illustration related to the track
+ Illustration,
+ // Logo of the band or performer
+ BandLogo,
+ // Logo of the publisher (record company)
+ PublisherLogo
+ };
+
+ core::LiteralString imageTypeToString(ImageType type);
+} // namespace lms::core::media
\ No newline at end of file
diff --git a/src/libs/core/include/core/media/MimeType.hpp b/src/libs/core/include/core/media/MimeType.hpp
new file mode 100644
index 00000000..319d70de
--- /dev/null
+++ b/src/libs/core/include/core/media/MimeType.hpp
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2025 Emeric Poupon
+ *
+ * This file is part of LMS.
+ *
+ * LMS is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * LMS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with LMS. If not, see .
+ */
+
+#pragma once
+
+#include "core/LiteralString.hpp"
+#include "core/media/CodecType.hpp"
+#include "core/media/ContainerType.hpp"
+
+namespace lms::core::media
+{
+ core::LiteralString getMimeType(ContainerType container, CodecType codec);
+}
\ No newline at end of file
diff --git a/src/libs/database/CMakeLists.txt b/src/libs/database/CMakeLists.txt
index c896269e..2ba86032 100644
--- a/src/libs/database/CMakeLists.txt
+++ b/src/libs/database/CMakeLists.txt
@@ -1,4 +1,5 @@
add_library(lmsdatabase STATIC
+ impl/objects/detail/Types.cpp
impl/objects/Artist.cpp
impl/objects/ArtistInfo.cpp
impl/objects/Artwork.cpp
diff --git a/src/libs/database/impl/objects/PodcastEpisode.cpp b/src/libs/database/impl/objects/PodcastEpisode.cpp
index a0d52d91..a8aab5f2 100644
--- a/src/libs/database/impl/objects/PodcastEpisode.cpp
+++ b/src/libs/database/impl/objects/PodcastEpisode.cpp
@@ -27,6 +27,7 @@
#include "database/objects/Podcast.hpp"
#include "Utils.hpp"
+#include "detail/Types.hpp"
#include "traits/IdTypeTraits.hpp"
#include "traits/PathTraits.hpp"
@@ -98,6 +99,16 @@ namespace lms::db
utils::forEachQueryRangeResult(query, params.range, func);
}
+ std::optional PodcastEpisode::getContainer() const
+ {
+ return detail::getMediaContainerType(_container);
+ }
+
+ std::optional PodcastEpisode::getCodec() const
+ {
+ return detail::getMediaCodecType(_codec);
+ }
+
ObjectPtr PodcastEpisode::getArtwork() const
{
return _artwork;
@@ -108,6 +119,16 @@ namespace lms::db
return _artwork.id();
}
+ void PodcastEpisode::setContainer(core::media::ContainerType container)
+ {
+ _container = detail::getDbContainerType(container);
+ }
+
+ void PodcastEpisode::setCodec(core::media::CodecType codec)
+ {
+ _codec = detail::getDbCodecType(codec);
+ }
+
void PodcastEpisode::setArtwork(ObjectPtr artwork)
{
_artwork = getDboPtr(artwork);
diff --git a/src/libs/database/impl/objects/Release.cpp b/src/libs/database/impl/objects/Release.cpp
index fab11b60..6f572a2c 100644
--- a/src/libs/database/impl/objects/Release.cpp
+++ b/src/libs/database/impl/objects/Release.cpp
@@ -40,6 +40,7 @@
#include "SqlQuery.hpp"
#include "Utils.hpp"
+#include "detail/Types.hpp"
#include "traits/EnumSetTraits.hpp"
#include "traits/IdTypeTraits.hpp"
#include "traits/PartialDateTimeTraits.hpp"
@@ -679,12 +680,20 @@ namespace lms::db
return utils::fetchQuerySingleResult(session()->query("SELECT COALESCE(AVG(t.bitrate), 0) FROM track t").where("release_id = ?").bind(getId()).where("bitrate > 0"));
}
- std::vector Release::getCodecs() const
+ std::vector Release::getCodecs() const
{
assert(session());
// Get the codec ordered by frequency
- return utils::fetchQueryResults(session()->query("SELECT t.codec FROM track t").where("release_id = ?").bind(getId()).groupBy("t.codec").orderBy("COUNT(t.id) DESC"));
+ auto query{ session()->query("SELECT t.codec FROM track t").where("release_id = ?").bind(getId()).groupBy("t.codec").orderBy("COUNT(t.id) DESC") };
+
+ std::vector res;
+ utils::forEachQueryResult(query, [&](detail::CodecType codec) {
+ if (const auto mediaCodecType{ detail::getMediaCodecType(codec) })
+ res.push_back(*mediaCodecType);
+ });
+
+ return res;
}
std::vector Release::getArtists(TrackArtistLinkType linkType) const
diff --git a/src/libs/database/impl/objects/Track.cpp b/src/libs/database/impl/objects/Track.cpp
index d42dcf48..5ad089b2 100644
--- a/src/libs/database/impl/objects/Track.cpp
+++ b/src/libs/database/impl/objects/Track.cpp
@@ -23,6 +23,7 @@
#include
#include "core/ILogger.hpp"
+
#include "database/Session.hpp"
#include "database/Types.hpp"
#include "database/objects/Artist.hpp"
@@ -41,6 +42,7 @@
#include "SqlQuery.hpp"
#include "Utils.hpp"
+#include "objects/detail/Types.hpp"
#include "traits/IdTypeTraits.hpp"
#include "traits/PartialDateTimeTraits.hpp"
#include "traits/PathTraits.hpp"
@@ -523,6 +525,16 @@ namespace lms::db
_absoluteFilePath = filePath;
}
+ void Track::setContainer(core::media::ContainerType container)
+ {
+ _container = detail::getDbContainerType(container);
+ }
+
+ void Track::setCodec(core::media::CodecType codec)
+ {
+ _codec = detail::getDbCodecType(codec);
+ }
+
void Track::setName(std::string_view name)
{
_name = std::string{ name, 0, _maxNameLength };
@@ -603,6 +615,16 @@ namespace lms::db
_preferredMediaArtwork = getDboPtr(artwork);
}
+ std::optional Track::getContainer() const
+ {
+ return detail::getMediaContainerType(_container);
+ }
+
+ std::optional Track::getCodec() const
+ {
+ return detail::getMediaCodecType(_codec);
+ }
+
std::optional Track::getYear() const
{
return _date.getYear();
diff --git a/src/libs/database/impl/objects/TrackEmbeddedImage.cpp b/src/libs/database/impl/objects/TrackEmbeddedImage.cpp
index c6866f13..507ca4bb 100644
--- a/src/libs/database/impl/objects/TrackEmbeddedImage.cpp
+++ b/src/libs/database/impl/objects/TrackEmbeddedImage.cpp
@@ -28,6 +28,8 @@
#include "database/objects/TrackEmbeddedImageLink.hpp"
#include "Utils.hpp"
+#include "detail/Types.hpp"
+#include "objects/detail/Types.hpp"
#include "traits/IdTypeTraits.hpp"
#include "traits/ImageHashTypeTraits.hpp"
@@ -83,7 +85,7 @@ namespace lms::db
}
if (params.imageType.has_value())
- query.where("t_e_i_l.type = ?").bind(params.imageType.value());
+ query.where("t_e_i_l.type = ?").bind(detail::getDbImageType(params.imageType.value()));
}
switch (params.sortMethod)
diff --git a/src/libs/database/impl/objects/TrackEmbeddedImageLink.cpp b/src/libs/database/impl/objects/TrackEmbeddedImageLink.cpp
index e39b2965..4cd05a08 100644
--- a/src/libs/database/impl/objects/TrackEmbeddedImageLink.cpp
+++ b/src/libs/database/impl/objects/TrackEmbeddedImageLink.cpp
@@ -23,11 +23,11 @@
#include
#include "database/Session.hpp"
-#include "database/Types.hpp"
#include "database/objects/Track.hpp"
#include "database/objects/TrackEmbeddedImage.hpp"
#include "Utils.hpp"
+#include "detail/Types.hpp"
#include "traits/IdTypeTraits.hpp"
#include "traits/ImageHashTypeTraits.hpp"
@@ -77,4 +77,14 @@ namespace lms::db
{
return _image;
}
+
+ core::media::ImageType TrackEmbeddedImageLink::getType() const
+ {
+ return detail::getMediaImageType(_type);
+ }
+
+ void TrackEmbeddedImageLink::setType(core::media::ImageType type)
+ {
+ _type = detail::getDbImageType(type);
+ }
} // namespace lms::db
diff --git a/src/libs/database/impl/objects/Types.cpp b/src/libs/database/impl/objects/Types.cpp
index 32388860..2ae8bede 100644
--- a/src/libs/database/impl/objects/Types.cpp
+++ b/src/libs/database/impl/objects/Types.cpp
@@ -72,96 +72,4 @@ namespace lms::db
{
return allowedAudioBitrates.find(bitrate) != std::cend(allowedAudioBitrates);
}
-
- core::LiteralString containerTypeToString(ContainerType type)
- {
- switch (type)
- {
- case ContainerType::Unknown:
- break;
-
- case ContainerType::AIFF:
- return "AIFF";
- case ContainerType::APE:
- return "APE";
- case ContainerType::ASF:
- return "ASF";
- case ContainerType::DSF:
- return "DSF";
- case ContainerType::FLAC:
- return "FLAC";
- case ContainerType::MP4:
- return "MP4";
- case ContainerType::MPC:
- return "MPC";
- case ContainerType::MPEG:
- return "MPEG";
- case ContainerType::Ogg:
- return "Ogg";
- case ContainerType::Shorten:
- return "Shorten";
- case ContainerType::TrueAudio:
- return "TrueAudio";
- case ContainerType::WAV:
- return "WAV";
- case ContainerType::WavPack:
- return "WavPack";
- }
-
- return "Unknown";
- }
-
- core::LiteralString codecTypeToString(CodecType type)
- {
- switch (type)
- {
- case CodecType::Unknown:
- break;
-
- case CodecType::AAC:
- return "AAC";
- case CodecType::AC3:
- return "AC3";
- case CodecType::ALAC:
- return "ALAC";
- case CodecType::APE:
- return "APE";
- case CodecType::DSD:
- return "DSD";
- case CodecType::EAC3:
- return "EAC3";
- case CodecType::FLAC:
- return "FLAC";
- case CodecType::MP3:
- return "MP3";
- case CodecType::MP4ALS:
- return "MP4ALS";
- case CodecType::MPC7:
- return "MPC7";
- case CodecType::MPC8:
- return "MPC8";
- case CodecType::Opus:
- return "Opus";
- case CodecType::PCM:
- return "PCM";
- case CodecType::Shorten:
- return "Shorten";
- case CodecType::TrueAudio:
- return "TrueAudio";
- case CodecType::Vorbis:
- return "Vorbis";
- case CodecType::WavPack:
- return "WavPack";
- case CodecType::WMA1:
- return "WMA1";
- case CodecType::WMA2:
- return "WMA2";
- case CodecType::WMA9Pro:
- return "WMA9Pro";
- case CodecType::WMA9Lossless:
- return "WMA9Lossless";
- }
-
- return "Unknown";
- }
} // namespace lms::db
diff --git a/src/libs/database/impl/objects/detail/Types.cpp b/src/libs/database/impl/objects/detail/Types.cpp
new file mode 100644
index 00000000..aa2573ed
--- /dev/null
+++ b/src/libs/database/impl/objects/detail/Types.cpp
@@ -0,0 +1,307 @@
+/*
+ * Copyright (C) 2015 Emeric Poupon
+ *
+ * This file is part of LMS.
+ *
+ * LMS is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * LMS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with LMS. If not, see .
+ */
+
+#include "Types.hpp"
+
+namespace lms::db::detail
+{
+ std::optional getMediaContainerType(db::detail::ContainerType container)
+ {
+ switch (container)
+ {
+ case ContainerType::AIFF:
+ return core::media::ContainerType::AIFF;
+ case ContainerType::APE:
+ return core::media::ContainerType::APE;
+ case ContainerType::ASF:
+ return core::media::ContainerType::ASF;
+ case ContainerType::DSF:
+ return core::media::ContainerType::DSF;
+ case ContainerType::FLAC:
+ return core::media::ContainerType::FLAC;
+ case ContainerType::MP4:
+ return core::media::ContainerType::MP4;
+ case ContainerType::MPC:
+ return core::media::ContainerType::MPC;
+ case ContainerType::MPEG:
+ return core::media::ContainerType::MPEG;
+ case ContainerType::Ogg:
+ return core::media::ContainerType::Ogg;
+ case ContainerType::Shorten:
+ return core::media::ContainerType::Shorten;
+ case ContainerType::TrueAudio:
+ return core::media::ContainerType::TrueAudio;
+ case ContainerType::WAV:
+ return core::media::ContainerType::WAV;
+ case ContainerType::WavPack:
+ return core::media::ContainerType::WavPack;
+
+ case ContainerType::Unknown:
+ break;
+ }
+
+ return std::nullopt;
+ }
+
+ db::detail::ContainerType getDbContainerType(core::media::ContainerType container)
+ {
+ switch (container)
+ {
+ case core::media::ContainerType::AIFF:
+ return ContainerType::AIFF;
+ case core::media::ContainerType::APE:
+ return ContainerType::APE;
+ case core::media::ContainerType::ASF:
+ return ContainerType::ASF;
+ case core::media::ContainerType::DSF:
+ return ContainerType::DSF;
+ case core::media::ContainerType::FLAC:
+ return ContainerType::FLAC;
+ case core::media::ContainerType::MP4:
+ return ContainerType::MP4;
+ case core::media::ContainerType::MPC:
+ return ContainerType::MPC;
+ case core::media::ContainerType::MPEG:
+ return ContainerType::MPEG;
+ case core::media::ContainerType::Ogg:
+ return ContainerType::Ogg;
+ case core::media::ContainerType::Shorten:
+ return ContainerType::Shorten;
+ case core::media::ContainerType::TrueAudio:
+ return ContainerType::TrueAudio;
+ case core::media::ContainerType::WAV:
+ return ContainerType::WAV;
+ case core::media::ContainerType::WavPack:
+ return ContainerType::WavPack;
+ }
+
+ return ContainerType::Unknown;
+ }
+
+ std::optional getMediaCodecType(db::detail::CodecType codec)
+ {
+ switch (codec)
+ {
+ case CodecType::AAC:
+ return core::media::CodecType::AAC;
+ case CodecType::AC3:
+ return core::media::CodecType::AC3;
+ case CodecType::ALAC:
+ return core::media::CodecType::ALAC;
+ case CodecType::APE:
+ return core::media::CodecType::APE;
+ case CodecType::DSD:
+ return core::media::CodecType::DSD;
+ case CodecType::EAC3:
+ return core::media::CodecType::EAC3;
+ case CodecType::FLAC:
+ return core::media::CodecType::FLAC;
+ case CodecType::MP3:
+ return core::media::CodecType::MP3;
+ case CodecType::MP4ALS:
+ return core::media::CodecType::MP4ALS;
+ case CodecType::MPC7:
+ return core::media::CodecType::MPC7;
+ case CodecType::MPC8:
+ return core::media::CodecType::MPC8;
+ case CodecType::Opus:
+ return core::media::CodecType::Opus;
+ case CodecType::PCM:
+ return core::media::CodecType::PCM;
+ case CodecType::Shorten:
+ return core::media::CodecType::Shorten;
+ case CodecType::TrueAudio:
+ return core::media::CodecType::TrueAudio;
+ case CodecType::Vorbis:
+ return core::media::CodecType::Vorbis;
+ case CodecType::WavPack:
+ return core::media::CodecType::WavPack;
+ case CodecType::WMA1:
+ return core::media::CodecType::WMA1;
+ case CodecType::WMA2:
+ return core::media::CodecType::WMA2;
+ case CodecType::WMA9Pro:
+ return core::media::CodecType::WMA9Pro;
+ case CodecType::WMA9Lossless:
+ return core::media::CodecType::WMA9Lossless;
+
+ case CodecType::Unknown:
+ break;
+ }
+
+ return std::nullopt;
+ }
+
+ db::detail::CodecType getDbCodecType(core::media::CodecType codec)
+ {
+ switch (codec)
+ {
+ case core::media::CodecType::AAC:
+ return CodecType::AAC;
+ case core::media::CodecType::AC3:
+ return CodecType::AC3;
+ case core::media::CodecType::ALAC:
+ return CodecType::ALAC;
+ case core::media::CodecType::APE:
+ return CodecType::APE;
+ case core::media::CodecType::DSD:
+ return CodecType::DSD;
+ case core::media::CodecType::EAC3:
+ return CodecType::EAC3;
+ case core::media::CodecType::FLAC:
+ return CodecType::FLAC;
+ case core::media::CodecType::MP3:
+ return CodecType::MP3;
+ case core::media::CodecType::MP4ALS:
+ return CodecType::MP4ALS;
+ case core::media::CodecType::MPC7:
+ return CodecType::MPC7;
+ case core::media::CodecType::MPC8:
+ return CodecType::MPC8;
+ case core::media::CodecType::Opus:
+ return CodecType::Opus;
+ case core::media::CodecType::PCM:
+ return CodecType::PCM;
+ case core::media::CodecType::Shorten:
+ return CodecType::Shorten;
+ case core::media::CodecType::TrueAudio:
+ return CodecType::TrueAudio;
+ case core::media::CodecType::Vorbis:
+ return CodecType::Vorbis;
+ case core::media::CodecType::WavPack:
+ return CodecType::WavPack;
+ case core::media::CodecType::WMA1:
+ return CodecType::WMA1;
+ case core::media::CodecType::WMA2:
+ return CodecType::WMA2;
+ case core::media::CodecType::WMA9Pro:
+ return CodecType::WMA9Pro;
+ case core::media::CodecType::WMA9Lossless:
+ return CodecType::WMA9Lossless;
+ }
+
+ return CodecType::Unknown;
+ }
+
+ core::media::ImageType getMediaImageType(db::detail::ImageType type)
+ {
+ switch (type)
+ {
+ case db::detail::ImageType::Unknown:
+ return core::media::ImageType::Unknown;
+ case db::detail::ImageType::Other:
+ return core::media::ImageType::Other;
+ case db::detail::ImageType::FileIcon:
+ return core::media::ImageType::FileIcon;
+ case db::detail::ImageType::OtherFileIcon:
+ return core::media::ImageType::OtherFileIcon;
+ case db::detail::ImageType::FrontCover:
+ return core::media::ImageType::FrontCover;
+ case db::detail::ImageType::BackCover:
+ return core::media::ImageType::BackCover;
+ case db::detail::ImageType::LeafletPage:
+ return core::media::ImageType::LeafletPage;
+ case db::detail::ImageType::Media:
+ return core::media::ImageType::Media;
+ case db::detail::ImageType::LeadArtist:
+ return core::media::ImageType::LeadArtist;
+ case db::detail::ImageType::Artist:
+ return core::media::ImageType::Artist;
+ case db::detail::ImageType::Conductor:
+ return core::media::ImageType::Conductor;
+ case db::detail::ImageType::Band:
+ return core::media::ImageType::Band;
+ case db::detail::ImageType::Composer:
+ return core::media::ImageType::Composer;
+ case db::detail::ImageType::Lyricist:
+ return core::media::ImageType::Lyricist;
+ case db::detail::ImageType::RecordingLocation:
+ return core::media::ImageType::RecordingLocation;
+ case db::detail::ImageType::DuringRecording:
+ return core::media::ImageType::DuringRecording;
+ case db::detail::ImageType::DuringPerformance:
+ return core::media::ImageType::DuringPerformance;
+ case db::detail::ImageType::MovieScreenCapture:
+ return core::media::ImageType::MovieScreenCapture;
+ case db::detail::ImageType::ColouredFish:
+ return core::media::ImageType::ColouredFish;
+ case db::detail::ImageType::Illustration:
+ return core::media::ImageType::Illustration;
+ case db::detail::ImageType::BandLogo:
+ return core::media::ImageType::BandLogo;
+ case db::detail::ImageType::PublisherLogo:
+ return core::media::ImageType::PublisherLogo;
+ }
+
+ return core::media::ImageType::Unknown;
+ }
+
+ db::detail::ImageType getDbImageType(core::media::ImageType type)
+ {
+ switch (type)
+ {
+ case core::media::ImageType::Unknown:
+ return db::detail::ImageType::Unknown;
+ case core::media::ImageType::Other:
+ return db::detail::ImageType::Other;
+ case core::media::ImageType::FileIcon:
+ return db::detail::ImageType::FileIcon;
+ case core::media::ImageType::OtherFileIcon:
+ return db::detail::ImageType::OtherFileIcon;
+ case core::media::ImageType::FrontCover:
+ return db::detail::ImageType::FrontCover;
+ case core::media::ImageType::BackCover:
+ return db::detail::ImageType::BackCover;
+ case core::media::ImageType::LeafletPage:
+ return db::detail::ImageType::LeafletPage;
+ case core::media::ImageType::Media:
+ return db::detail::ImageType::Media;
+ case core::media::ImageType::LeadArtist:
+ return db::detail::ImageType::LeadArtist;
+ case core::media::ImageType::Artist:
+ return db::detail::ImageType::Artist;
+ case core::media::ImageType::Conductor:
+ return db::detail::ImageType::Conductor;
+ case core::media::ImageType::Band:
+ return db::detail::ImageType::Band;
+ case core::media::ImageType::Composer:
+ return db::detail::ImageType::Composer;
+ case core::media::ImageType::Lyricist:
+ return db::detail::ImageType::Lyricist;
+ case core::media::ImageType::RecordingLocation:
+ return db::detail::ImageType::RecordingLocation;
+ case core::media::ImageType::DuringRecording:
+ return db::detail::ImageType::DuringRecording;
+ case core::media::ImageType::DuringPerformance:
+ return db::detail::ImageType::DuringPerformance;
+ case core::media::ImageType::MovieScreenCapture:
+ return db::detail::ImageType::MovieScreenCapture;
+ case core::media::ImageType::ColouredFish:
+ return db::detail::ImageType::ColouredFish;
+ case core::media::ImageType::Illustration:
+ return db::detail::ImageType::Illustration;
+ case core::media::ImageType::BandLogo:
+ return db::detail::ImageType::BandLogo;
+ case core::media::ImageType::PublisherLogo:
+ return db::detail::ImageType::PublisherLogo;
+ }
+
+ return db::detail::ImageType::Unknown;
+ }
+} // namespace lms::db::detail
\ No newline at end of file
diff --git a/src/libs/database/impl/objects/detail/Types.hpp b/src/libs/database/impl/objects/detail/Types.hpp
new file mode 100644
index 00000000..eed0b5e4
--- /dev/null
+++ b/src/libs/database/impl/objects/detail/Types.hpp
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2015 Emeric Poupon
+ *
+ * This file is part of LMS.
+ *
+ * LMS is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * LMS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with LMS. If not, see .
+ */
+
+#pragma once
+
+#include
+
+#include "core/media/CodecType.hpp"
+#include "core/media/ContainerType.hpp"
+#include "core/media/ImageType.hpp"
+
+#include "database/objects/detail/Types.hpp"
+
+namespace lms::db::detail
+{
+ std::optional getMediaContainerType(db::detail::ContainerType container);
+ db::detail::ContainerType getDbContainerType(core::media::ContainerType container);
+
+ std::optional getMediaCodecType(db::detail::CodecType codec);
+ db::detail::CodecType getDbCodecType(core::media::CodecType codec);
+
+ core::media::ImageType getMediaImageType(db::detail::ImageType type);
+ db::detail::ImageType getDbImageType(core::media::ImageType type);
+} // namespace lms::db::detail
\ No newline at end of file
diff --git a/src/libs/database/include/database/objects/PodcastEpisode.hpp b/src/libs/database/include/database/objects/PodcastEpisode.hpp
index 0f1dc25c..7911375c 100644
--- a/src/libs/database/include/database/objects/PodcastEpisode.hpp
+++ b/src/libs/database/include/database/objects/PodcastEpisode.hpp
@@ -29,12 +29,16 @@
#include
#include
+#include "core/media/CodecType.hpp"
+#include "core/media/ContainerType.hpp"
+
#include "database/Object.hpp"
#include "database/Types.hpp"
#include "database/objects/ArtworkId.hpp"
#include "database/objects/PodcastEpisodeId.hpp"
#include "database/objects/PodcastId.hpp"
#include "database/objects/Types.hpp"
+#include "database/objects/detail/Types.hpp"
namespace lms::db
{
@@ -93,8 +97,8 @@ namespace lms::db
// Audio properties
std::chrono::milliseconds getDuration() const { return _duration; }
- ContainerType getContainer() const { return _container; }
- CodecType getCodec() const { return _codec; }
+ std::optional getContainer() const;
+ std::optional getCodec() const;
std::size_t getBitrate() const { return _bitrate; }
std::size_t getChannelCount() const { return _channelCount; }
std::size_t getSampleRate() const { return _sampleRate; }
@@ -124,8 +128,8 @@ namespace lms::db
// Audio properties
void setDuration(std::chrono::milliseconds duration) { _duration = duration; }
- void setContainer(ContainerType container) { _container = container; }
- void setCodec(CodecType codec) { _codec = codec; }
+ void setContainer(core::media::ContainerType container);
+ void setCodec(core::media::CodecType codec);
void setBitrate(std::size_t bitrate) { _bitrate = bitrate; }
void setChannelCount(std::size_t channelCount) { _channelCount = channelCount; }
void setSampleRate(std::size_t sampleRate) { _sampleRate = sampleRate; }
@@ -189,8 +193,8 @@ namespace lms::db
// Audio properties
std::chrono::duration _duration{ 0 };
- ContainerType _container{ ContainerType::Unknown };
- CodecType _codec{ CodecType::Unknown };
+ detail::ContainerType _container{ detail::ContainerType::Unknown };
+ detail::CodecType _codec{ detail::CodecType::Unknown };
int _bitrate{}; // in bps
int _channelCount{};
int _sampleRate{};
diff --git a/src/libs/database/include/database/objects/Release.hpp b/src/libs/database/include/database/objects/Release.hpp
index f8b8a3d8..b2a078e4 100644
--- a/src/libs/database/include/database/objects/Release.hpp
+++ b/src/libs/database/include/database/objects/Release.hpp
@@ -31,6 +31,7 @@
#include "core/EnumSet.hpp"
#include "core/PartialDateTime.hpp"
#include "core/UUID.hpp"
+#include "core/media/CodecType.hpp"
#include "database/IdRange.hpp"
#include "database/Object.hpp"
@@ -279,7 +280,7 @@ namespace lms::db
std::optional getCopyright() const;
std::optional getCopyrightURL() const;
std::size_t getMeanBitrate() const;
- std::vector getCodecs() const;
+ std::vector getCodecs() const;
// Accessors
std::string_view getName() const { return _name; }
diff --git a/src/libs/database/include/database/objects/Track.hpp b/src/libs/database/include/database/objects/Track.hpp
index 88f7e95f..b1d2d38a 100644
--- a/src/libs/database/include/database/objects/Track.hpp
+++ b/src/libs/database/include/database/objects/Track.hpp
@@ -34,6 +34,8 @@
#include "core/EnumSet.hpp"
#include "core/PartialDateTime.hpp"
#include "core/UUID.hpp"
+#include "core/media/CodecType.hpp"
+#include "core/media/ContainerType.hpp"
#include "database/IdRange.hpp"
#include "database/Object.hpp"
@@ -51,6 +53,7 @@
#include "database/objects/TrackListId.hpp"
#include "database/objects/Types.hpp"
#include "database/objects/UserId.hpp"
+#include "database/objects/detail/Types.hpp"
namespace lms::db
{
@@ -229,8 +232,8 @@ namespace lms::db
// Audio properties
void setDuration(std::chrono::milliseconds duration) { _duration = duration; }
- void setContainer(ContainerType container) { _container = container; }
- void setCodec(CodecType codec) { _codec = codec; }
+ void setContainer(core::media::ContainerType container);
+ void setCodec(core::media::CodecType codec);
void setBitrate(std::size_t bitrate) { _bitrate = bitrate; }
void setChannelCount(std::size_t channelCount) { _channelCount = channelCount; }
void setSampleRate(std::size_t sampleRate) { _sampleRate = sampleRate; }
@@ -275,8 +278,8 @@ namespace lms::db
// Audio properties
std::chrono::milliseconds getDuration() const { return _duration; }
- ContainerType getContainer() const { return _container; }
- CodecType getCodec() const { return _codec; }
+ std::optional getContainer() const;
+ std::optional getCodec() const;
std::size_t getBitrate() const { return _bitrate; }
std::size_t getChannelCount() const { return _channelCount; }
std::size_t getSampleRate() const { return _sampleRate; }
@@ -380,8 +383,8 @@ namespace lms::db
// Audio properties
std::chrono::duration _duration{};
- ContainerType _container{ ContainerType::Unknown };
- CodecType _codec{ CodecType::Unknown };
+ detail::ContainerType _container{ detail::ContainerType::Unknown };
+ detail::CodecType _codec{ detail::CodecType::Unknown };
int _bitrate{}; // in bps
int _channelCount{};
int _sampleRate{};
diff --git a/src/libs/database/include/database/objects/TrackEmbeddedImage.hpp b/src/libs/database/include/database/objects/TrackEmbeddedImage.hpp
index 4237ec84..2c4bf49f 100644
--- a/src/libs/database/include/database/objects/TrackEmbeddedImage.hpp
+++ b/src/libs/database/include/database/objects/TrackEmbeddedImage.hpp
@@ -26,6 +26,8 @@
#include
#include
+#include "core/media/ImageType.hpp"
+
#include "database/Object.hpp"
#include "database/Types.hpp"
#include "database/objects/MediumId.hpp"
@@ -53,7 +55,7 @@ namespace lms::db
ReleaseId release;
MediumId medium;
TrackListId trackList;
- std::optional imageType;
+ std::optional imageType;
TrackEmbeddedImageSortMethod sortMethod{ TrackEmbeddedImageSortMethod::None };
FindParameters& setRange(std::optional _range)
@@ -81,7 +83,7 @@ namespace lms::db
trackList = _trackList;
return *this;
}
- FindParameters& setImageType(std::optional _imageType)
+ FindParameters& setImageType(std::optional _imageType)
{
imageType = _imageType;
return *this;
diff --git a/src/libs/database/include/database/objects/TrackEmbeddedImageLink.hpp b/src/libs/database/include/database/objects/TrackEmbeddedImageLink.hpp
index 8334616c..c99f3e0c 100644
--- a/src/libs/database/include/database/objects/TrackEmbeddedImageLink.hpp
+++ b/src/libs/database/include/database/objects/TrackEmbeddedImageLink.hpp
@@ -24,10 +24,13 @@
#include
+#include "core/media/ImageType.hpp"
+
#include "database/Object.hpp"
#include "database/objects/TrackEmbeddedImageId.hpp"
#include "database/objects/TrackEmbeddedImageLinkId.hpp"
#include "database/objects/Types.hpp"
+#include "database/objects/detail/Types.hpp"
namespace lms::db
{
@@ -49,12 +52,12 @@ namespace lms::db
ObjectPtr