diff --git a/approot/messages.xml b/approot/messages.xml
index 1f775e67..056dddeb 100644
--- a/approot/messages.xml
+++ b/approot/messages.xml
@@ -100,9 +100,10 @@
Cannot get track duration
+Unable to read the image at index {1}
Cannot parse artist info file
Cannot parse audio file
-Cannot read file
+Cannot read file ({1})
Cannot parse image file
Cannot parse lyrics file
Cannot parse playlist file
@@ -115,6 +116,9 @@
Last scan
Not available
{1} files were scanned in {2} at {4} on {3} (UTC) - {5} errors, {6} duplicates
+Missing artist name
+Unable to find track paths
+Unable to find the path "{1}"
No audio track
Duplicated file hash
Duplicated track MBID
diff --git a/approot/messages_es.xml b/approot/messages_es.xml
index 7f47b917..325890c3 100644
--- a/approot/messages_es.xml
+++ b/approot/messages_es.xml
@@ -100,9 +100,10 @@
No ha sido posible obtener la duración de la pista
+No se puede leer la imagen en el índice {1}
No ha sido posible analizar el fichero de información sobre el artista
No ha sido posible analizar el fichero de audio
-No ha sido posible leer el fichero
+No ha sido posible leer el fichero ({1})
No ha sido posible analizar del fichero de imagen
No ha sido posible analizar el fichero de letras
No ha sido posible analizar el fichero de la lista de distribución
@@ -115,6 +116,9 @@
Último escaneo
No disponible
{1} ficheros analizados en {2} el {3} a las {4} (UTC) - {5} errores, {6} duplicados
+Falta el nombre del artista
+No se pudieron encontrar las rutas de las pistas
+No se pudo encontrar la ruta "{1}"
No es una pista de audio
Hash del fichero duplicado
MBID de la pista duplicado
diff --git a/approot/messages_fr.xml b/approot/messages_fr.xml
index de9c8039..5fea473e 100644
--- a/approot/messages_fr.xml
+++ b/approot/messages_fr.xml
@@ -100,9 +100,10 @@
Impossible de récupérer la durée de la piste
+Impossible de lire l'image à l'indice {1}
Impossible d'analyser le fichier d'informations sur l'artiste
Impossible d'analyser le fichier audio
-Impossible de lire le fichier
+Impossible de lire le fichier ({1})
Impossible d'analyser le fichier image
Impossible d'analyser le fichier de paroles
Impossible d'analyser le fichier de liste de lecture
@@ -115,6 +116,9 @@
Dernier scan
Non disponible
{1} fichiers analysés en {2} à {4} le {3} (UTC) - {5} erreurs, {6} duplicatas
+Nom de l'artiste manquant
+Impossible de trouver les chemins des pistes
+Impossible de trouver le chemin "{1}"
Pas de piste audio
Hash dupliqué
Track MBID dupliqué
diff --git a/approot/messages_it.xml b/approot/messages_it.xml
index 6545bb5d..91935ade 100644
--- a/approot/messages_it.xml
+++ b/approot/messages_it.xml
@@ -100,9 +100,10 @@
Non sono stato in grado di determinare la durata della traccia
+Impossibile leggere l'immagine all'indice {1}
Impossibile analizzare il file delle informazioni sull'artista
Impossibile analizzare il file audio
-Non in grado di leggere il file
+Non in grado di leggere il file ({1})
Impossibile analizzare il file immagine
Impossibile analizzare il file dei testi
Impossibile analizzare il file della playlist
@@ -115,6 +116,9 @@
Ultima scansione
Non disponibile
{1} file scansionati in {2} alle {3} il {4} (UTC) - {5} errori, {6} duplicati
+Nome dell'artista mancante
+Impossibile trovare i percorsi delle tracce
+Impossibile trovare il percorso "{1}"
Nessuna traccia audio
Hash doppio
Track MBID doppio
diff --git a/approot/messages_pl.xml b/approot/messages_pl.xml
index cb1af168..78c2d88b 100644
--- a/approot/messages_pl.xml
+++ b/approot/messages_pl.xml
@@ -101,9 +101,10 @@
Nie udało się ustalić długości ścieżki
+Nie można odczytać obrazu pod indeksem {1}
Nie można przetworzyć pliku z informacjami o artyście"
Nie można przeanalizować pliku audio
-Nie udało się odczytać pliku
+Nie udało się odczytać pliku ({1})
Nie można przeanalizować pliku obrazu
Nie można przetworzyć pliku z tekstem
Nie można przeanalizować pliku playlisty
@@ -124,6 +125,9 @@
Ostatnie skanowanie
Niedostępne
Przeskanowano {1} plików w {2} o {4} dnia {3} (UTC) - {5} błędów, {6} duplikatów
+Brakuje nazwy artysty
+Nie można znaleźć ścieżek utworów
+Nie można znaleźć ścieżki „{1}”
Brak ścieżki dźwiękowej
Zduplikowny hash pliku
Zduplikowany MBID pliku
diff --git a/approot/messages_zh.xml b/approot/messages_zh.xml
index 7b81cbe3..860bb5d2 100644
--- a/approot/messages_zh.xml
+++ b/approot/messages_zh.xml
@@ -100,9 +100,10 @@
无法获得音轨时间
+
无法解析文件
-无法读取文件
+无法读取文件 ({1})
@@ -114,6 +115,9 @@
最后扫描
不可用
已扫描 {1} 个文件,用时 {2},在 {3} 的 {4} (UTC) - {5} 个错误,{6} 个重复项
+
+
+
没有音轨
相同文件哈希值
相同 MBID
diff --git a/src/libs/core/impl/ArchiveZipper.cpp b/src/libs/core/impl/ArchiveZipper.cpp
index 15042e87..9cdfb52a 100644
--- a/src/libs/core/impl/ArchiveZipper.cpp
+++ b/src/libs/core/impl/ArchiveZipper.cpp
@@ -22,12 +22,12 @@
#include
#include
#include
+#include
#include
#include
#include "core/ILogger.hpp"
-#include "core/String.hpp"
namespace lms::zip
{
@@ -43,9 +43,13 @@ namespace lms::zip
: Exception{ "File '" + p.string() + "': " + std::string{ message } }
{
}
+ };
- FileException(const std::filesystem::path& p, std::string_view message, int err)
- : Exception{ "File '" + p.string() + "': " + std::string{ message } + ": " + core::stringUtils::systemErrorToString(err) }
+ class FileStdException : public FileException
+ {
+ public:
+ FileStdException(const std::filesystem::path& p, std::string_view message, int err)
+ : FileException{ p, std::string{ message } + "': " + std::error_code{ err, std::generic_category() }.message() }
{
}
};
@@ -240,7 +244,7 @@ namespace lms::zip
std::ifstream ifs{ _currentEntry->filePath, std::ios_base::binary };
if (!ifs)
- throw FileException{ _currentEntry->filePath, "cannot open file", errno };
+ throw FileStdException{ _currentEntry->filePath, "cannot open file", errno };
ifs.seekg(0, std::ios::end);
const std::uint64_t fileSize{ static_cast(ifs.tellg()) };
@@ -254,10 +258,10 @@ namespace lms::zip
// read from file
if (!ifs.seekg(_currentEntryOffset, std::ios::beg))
- throw FileException{ _currentEntry->filePath, "seek failed", errno };
+ throw FileStdException{ _currentEntry->filePath, "seek failed", errno };
if (!ifs.read(reinterpret_cast(_readBuffer.data()), bytesToRead))
- throw FileException{ _currentEntry->filePath, "read failed", errno };
+ throw FileStdException{ _currentEntry->filePath, "read failed", errno };
const std::uint64_t actualBytesRead{ static_cast(ifs.gcount()) };
diff --git a/src/libs/core/impl/ChildProcess.cpp b/src/libs/core/impl/ChildProcess.cpp
index 0f7b2ef9..2dc57207 100644
--- a/src/libs/core/impl/ChildProcess.cpp
+++ b/src/libs/core/impl/ChildProcess.cpp
@@ -25,6 +25,7 @@
#include
#include
#include
+#include
#include
#include
@@ -35,7 +36,6 @@
#include
#include "core/ILogger.hpp"
-#include "core/String.hpp"
namespace lms::core
{
@@ -44,8 +44,8 @@ namespace lms::core
class SystemException : public ChildProcessException
{
public:
- SystemException(int err, const std::string& errMsg)
- : ChildProcessException{ errMsg + ": " + stringUtils::systemErrorToString(err) }
+ SystemException(std::error_code err, const std::string& errMsg)
+ : ChildProcessException{ errMsg + ": " + err.message() }
{
}
@@ -69,20 +69,20 @@ namespace lms::core
// Use 'pipe' instead of 'pipe2', more portable
if (pipe(pipefd) < 0)
- throw SystemException{ errno, "pipe failed!" };
+ throw SystemException{ std::error_code{ errno, std::generic_category() }, "pipe failed!" };
// Manually set the O_NONBLOCK and O_CLOEXEC flags for both ends of the pipe
if (fcntl(pipefd[0], F_SETFL, O_NONBLOCK) == -1)
- throw SystemException{ errno, "fcntl failed to set O_NONBLOCK!" };
+ throw SystemException{ std::error_code{ errno, std::generic_category() }, "fcntl failed to set O_NONBLOCK!" };
if (fcntl(pipefd[1], F_SETFL, O_NONBLOCK) == -1)
- throw SystemException{ errno, "fcntl failed to set O_NONBLOCK!" };
+ throw SystemException{ std::error_code{ errno, std::generic_category() }, "fcntl failed to set O_NONBLOCK!" };
if (fcntl(pipefd[0], F_SETFD, FD_CLOEXEC) == -1)
- throw SystemException{ errno, "fcntl failed to set FD_CLOEXEC!" };
+ throw SystemException{ std::error_code{ errno, std::generic_category() }, "fcntl failed to set FD_CLOEXEC!" };
if (fcntl(pipefd[1], F_SETFD, FD_CLOEXEC) == -1)
- throw SystemException{ errno, "fcntl failed to set FD_CLOEXEC!" };
+ throw SystemException{ std::error_code{ errno, std::generic_category() }, "fcntl failed to set FD_CLOEXEC!" };
#if defined(__linux__) && defined(F_SETPIPE_SZ)
for (const int fd : { pipefd[0], pipefd[1] })
@@ -94,7 +94,7 @@ namespace lms::core
if (pipeSizeRes == -1)
{
const int err{ errno };
- LMS_LOG(CHILDPROCESS, DEBUG, "F_GETPIPE_SZ failed: " << stringUtils::systemErrorToString(err));
+ LMS_LOG(CHILDPROCESS, DEBUG, "F_GETPIPE_SZ failed: " << (std::error_code{ err, std::generic_category() }.message()));
}
else
{
@@ -103,10 +103,10 @@ namespace lms::core
#endif
if (currentPipeSize < targetPipeSize)
{
- if (fcntl(fd, F_SETPIPE_SZ, targetPipeSize) == -1)
+ if (::fcntl(fd, F_SETPIPE_SZ, targetPipeSize) == -1)
{
const int err{ errno };
- LMS_LOG(CHILDPROCESS, DEBUG, "F_SETPIPE_SZ failed: " << stringUtils::systemErrorToString(err));
+ LMS_LOG(CHILDPROCESS, DEBUG, "F_SETPIPE_SZ failed: " << (std::error_code{ err, std::generic_category() }.message()));
}
}
}
@@ -114,7 +114,7 @@ namespace lms::core
int res{ fork() };
if (res == -1)
- throw SystemException{ errno, "fork failed!" };
+ throw SystemException{ std::error_code{ errno, std::generic_category() }, "fork failed!" };
if (res == 0) // CHILD
{
@@ -168,7 +168,10 @@ namespace lms::core
// process may already have finished
LMS_LOG(CHILDPROCESS, DEBUG, "Killing child process...");
if (::kill(_childPID, SIGKILL) == -1)
- LMS_LOG(CHILDPROCESS, DEBUG, "Kill failed: " << stringUtils::systemErrorToString(errno));
+ {
+ const int err{ errno };
+ LMS_LOG(CHILDPROCESS, DEBUG, "Kill failed: " << (std::error_code{ err, std::generic_category() }.message()));
+ }
}
bool ChildProcess::wait(bool block)
@@ -179,7 +182,7 @@ namespace lms::core
const pid_t pid{ waitpid(_childPID, &wstatus, block ? 0 : WNOHANG) };
if (pid == -1)
- throw SystemException{ errno, "waitpid failed!" };
+ throw SystemException{ std::error_code{ errno, std::generic_category() }, "waitpid failed!" };
if (pid == 0)
return false;
diff --git a/src/libs/core/impl/Path.cpp b/src/libs/core/impl/Path.cpp
index d0f983e7..248042c7 100644
--- a/src/libs/core/impl/Path.cpp
+++ b/src/libs/core/impl/Path.cpp
@@ -23,6 +23,7 @@
#include
#include
#include
+#include
#include
#include
@@ -66,16 +67,24 @@ namespace lms::core::pathUtils
return std::filesystem::create_directory(dir);
}
- Wt::WDateTime getLastWriteTime(const std::filesystem::path& file)
+ Wt::WDateTime getLastWriteTime(const std::filesystem::path& file, std::error_code& ec)
{
+ Wt::WDateTime res;
+
struct stat sb
{
};
-
if (stat(file.c_str(), &sb) == -1)
- throw LmsException("Failed to get stats on file '" + file.string() + "'");
+ {
+ ec = std::error_code{ errno, std::generic_category() };
+ }
+ else
+ {
+ ec = std::error_code{};
+ res = Wt::WDateTime::fromTime_t(sb.st_mtime);
+ }
- return Wt::WDateTime::fromTime_t(sb.st_mtime);
+ return res;
}
bool exploreFilesRecursive(const std::filesystem::path& directory, std::function cb, const std::filesystem::path* excludeDirFileName)
diff --git a/src/libs/core/impl/String.cpp b/src/libs/core/impl/String.cpp
index 8258348a..d976d26d 100644
--- a/src/libs/core/impl/String.cpp
+++ b/src/libs/core/impl/String.cpp
@@ -20,7 +20,6 @@
#include "core/String.hpp"
#include
-#include
#include
#include
#include
@@ -509,11 +508,4 @@ namespace lms::core::stringUtils
return "[" + std::to_string(mins) + ":" + (secs < 10 ? "0" : "") + std::to_string(secs) + "." + (millis < 100 ? (millis < 10 ? "00" : "0") : "") + std::to_string(millis) + "]";
}
-
- std::string systemErrorToString(int err)
- {
- std::array buffer{};
- ::strerror_r(err, buffer.data(), buffer.size());
- return std::string{ buffer.data() };
- }
} // namespace lms::core::stringUtils
diff --git a/src/libs/core/include/core/Path.hpp b/src/libs/core/include/core/Path.hpp
index 500c9af3..1d9688bd 100644
--- a/src/libs/core/include/core/Path.hpp
+++ b/src/libs/core/include/core/Path.hpp
@@ -22,7 +22,7 @@
#include
#include
#include
-#include
+#include
#include
@@ -35,7 +35,7 @@ namespace lms::core::pathUtils
bool ensureDirectory(const std::filesystem::path& dir);
// Get the last write time since Epoch
- Wt::WDateTime getLastWriteTime(const std::filesystem::path& dir);
+ Wt::WDateTime getLastWriteTime(const std::filesystem::path& file, std::error_code& ec);
// returns false if aborted by user
bool exploreFilesRecursive(const std::filesystem::path& directory, std::function cb, const std::filesystem::path* excludeDirFileName = {});
diff --git a/src/libs/core/include/core/String.hpp b/src/libs/core/include/core/String.hpp
index 7c99a7cc..b65df63a 100644
--- a/src/libs/core/include/core/String.hpp
+++ b/src/libs/core/include/core/String.hpp
@@ -119,6 +119,4 @@ namespace lms::core::stringUtils
// to "[minutes:seconds.milliseconds]"
std::string formatTimestamp(std::chrono::milliseconds timestamp);
-
- std::string systemErrorToString(int err);
} // namespace lms::core::stringUtils
\ No newline at end of file
diff --git a/src/libs/metadata/CMakeLists.txt b/src/libs/metadata/CMakeLists.txt
index d5dfc9fd..ea401ef1 100644
--- a/src/libs/metadata/CMakeLists.txt
+++ b/src/libs/metadata/CMakeLists.txt
@@ -11,12 +11,14 @@ endif()
add_library(lmsmetadata STATIC
impl/ArtistInfo.cpp
impl/AudioFileParser.cpp
- impl/AvFormatImageReader.cpp
- impl/AvFormatTagReader.cpp
+ impl/avformat/AvFormatImageReader.cpp
+ impl/avformat/AvFormatTagReader.cpp
+ impl/avformat/Utils.cpp
impl/Lyrics.cpp
impl/PlayList.cpp
- impl/TagLibImageReader.cpp
- impl/TagLibTagReader.cpp
+ impl/taglib/TagLibImageReader.cpp
+ impl/taglib/TagLibTagReader.cpp
+ impl/taglib/Utils.cpp
impl/Utils.cpp
)
@@ -26,6 +28,7 @@ target_include_directories(lmsmetadata INTERFACE
target_include_directories(lmsmetadata PRIVATE
include
+ impl
)
target_link_libraries(lmsmetadata PRIVATE
diff --git a/src/libs/metadata/impl/ArtistInfo.cpp b/src/libs/metadata/impl/ArtistInfo.cpp
index 639bbd42..85b4e96b 100644
--- a/src/libs/metadata/impl/ArtistInfo.cpp
+++ b/src/libs/metadata/impl/ArtistInfo.cpp
@@ -27,10 +27,10 @@
namespace lms::metadata
{
- std::span getSupportedInfoFileExtensions()
+ std::span getSupportedArtistInfoFiles()
{
- static const std::array fileExtensions{ ".nfo" };
- return fileExtensions;
+ static const std::array files{ "artist.nfo" };
+ return files;
}
ArtistInfo parseArtistInfo(std::istream& is)
@@ -56,7 +56,7 @@ namespace lms::metadata
}
catch (boost::property_tree::ptree_error& error)
{
- LMS_LOG(RECOMMENDATION, ERROR, "Cannot read artist xml info: " << error.what());
+ LMS_LOG(METADATA, ERROR, "Cannot read artist xml info: " << error.what());
throw ArtistInfoParseException{ error.what() };
}
}
diff --git a/src/libs/metadata/impl/AudioFileParser.cpp b/src/libs/metadata/impl/AudioFileParser.cpp
index a75d7c03..29cfa356 100644
--- a/src/libs/metadata/impl/AudioFileParser.cpp
+++ b/src/libs/metadata/impl/AudioFileParser.cpp
@@ -28,11 +28,13 @@
#include "core/String.hpp"
#include "metadata/Exception.hpp"
-#include "AvFormatImageReader.hpp"
-#include "AvFormatTagReader.hpp"
-#include "TagLibImageReader.hpp"
-#include "TagLibTagReader.hpp"
#include "Utils.hpp"
+#include "avformat/AvFormatImageReader.hpp"
+#include "avformat/AvFormatTagReader.hpp"
+#include "avformat/Utils.hpp"
+#include "taglib/TagLibImageReader.hpp"
+#include "taglib/TagLibTagReader.hpp"
+#include "taglib/Utils.hpp"
namespace lms::metadata
{
@@ -338,82 +340,56 @@ namespace lms::metadata
std::span AudioFileParser::getSupportedExtensions() const
{
- // TODO: use backend capability to retrieve supported formats
- static const std::array fileExtensions{
- ".aac",
- ".alac",
- ".aif",
- ".aiff",
- ".ape",
- ".dsf",
- ".flac",
- ".m4a",
- ".m4b",
- ".mp3",
- ".mpc",
- ".oga",
- ".ogg",
- ".opus",
- ".shn",
- ".wav",
- ".wma",
- ".wv",
- };
- return fileExtensions;
+ switch (_params.backend)
+ {
+ case ParserBackend::TagLib:
+ return taglib::utils::getSupportedExtensions();
+ break;
+
+ case ParserBackend::AvFormat:
+ return avformat::utils::getSupportedExtensions();
+ break;
+ }
+
+ return {};
}
std::unique_ptr