Moved scanner specific code from core

This commit is contained in:
emeric
2025-07-19 11:39:57 +02:00
parent 1236969516
commit 97866d6143
4 changed files with 61 additions and 81 deletions
-57
View File
@@ -35,63 +35,6 @@ namespace lms::core::pathUtils
return std::filesystem::create_directory(dir); return std::filesystem::create_directory(dir);
} }
bool exploreFilesRecursive(const std::filesystem::path& directory, ExploreFileCallback cb, const std::filesystem::path* excludeDirFileName)
{
std::error_code ec;
std::filesystem::directory_iterator itPath{ directory, std::filesystem::directory_options::follow_directory_symlink, ec };
if (ec)
{
cb(ec, directory, nullptr);
return true; // try to continue exploring anyway
}
if (excludeDirFileName && !excludeDirFileName->empty())
{
const std::filesystem::path excludePath{ directory / *excludeDirFileName };
if (std::filesystem::exists(excludePath, ec))
{
// TODO: handle exclude another way + remove this log
LMS_LOG(DBUPDATER, DEBUG, "Found " << excludePath << ": skipping directory");
return true;
}
}
std::filesystem::directory_iterator itEnd;
while (itPath != itEnd)
{
bool continueExploring{ true };
if (ec)
{
continueExploring = cb(ec, *itPath, nullptr);
}
else
{
const std::filesystem::directory_entry& entry{ *itPath };
if (entry.is_regular_file())
{
FileInfo fileInfo;
fileInfo.fileSize = entry.file_size();
fileInfo.lastWriteTime = Wt::WDateTime{ std::chrono::file_clock::to_sys(entry.last_write_time()) };
continueExploring = cb(ec, *itPath, &fileInfo);
}
else if (entry.is_directory())
continueExploring = exploreFilesRecursive(*itPath, cb, excludeDirFileName);
}
if (!continueExploring)
return false;
itPath.increment(ec);
}
return true;
}
bool hasFileAnyExtension(const std::filesystem::path& file, std::span<const std::filesystem::path> supportedExtensions) bool hasFileAnyExtension(const std::filesystem::path& file, std::span<const std::filesystem::path> supportedExtensions)
{ {
const std::filesystem::path extension{ stringUtils::stringToLower(file.extension().c_str()) }; const std::filesystem::path extension{ stringUtils::stringToLower(file.extension().c_str()) };
-11
View File
@@ -20,9 +20,7 @@
#pragma once #pragma once
#include <filesystem> #include <filesystem>
#include <functional>
#include <span> #include <span>
#include <system_error>
#include <Wt/WDateTime.h> #include <Wt/WDateTime.h>
@@ -32,15 +30,6 @@ namespace lms::core::pathUtils
// Create it if needed // Create it if needed
bool ensureDirectory(const std::filesystem::path& dir); bool ensureDirectory(const std::filesystem::path& dir);
struct FileInfo
{
Wt::WDateTime lastWriteTime; // Last write time of the file since Epoch
std::uint64_t fileSize{}; // Size of the file in bytes
};
using ExploreFileCallback = std::function<bool(std::error_code, const std::filesystem::path&, const FileInfo* fileInfo)>;
// returns false if aborted by user
bool exploreFilesRecursive(const std::filesystem::path& directory, ExploreFileCallback cb, const std::filesystem::path* excludeDirFileName = {});
// Check if file's extension is one of provided extensions // Check if file's extension is one of provided extensions
bool hasFileAnyExtension(const std::filesystem::path& file, std::span<const std::filesystem::path> extensions); bool hasFileAnyExtension(const std::filesystem::path& file, std::span<const std::filesystem::path> extensions);
+5 -6
View File
@@ -154,10 +154,7 @@ namespace lms::metadata::taglib::utils
#endif #endif
if (file && !file->isValid()) if (file && !file->isValid())
{
LMS_LOG(METADATA, DEBUG, "File " << file << ": failed to parse by extension");
file.reset(); file.reset();
}
return file; return file;
} }
@@ -208,10 +205,7 @@ namespace lms::metadata::taglib::utils
#endif #endif
if (file && !file->isValid()) if (file && !file->isValid())
{
LMS_LOG(METADATA, DEBUG, "File " << file << ": failed to parse by content");
file.reset(); file.reset();
}
return file; return file;
} }
@@ -223,7 +217,12 @@ namespace lms::metadata::taglib::utils
TagLib::FileStream fileStream{ createFileStream(p) }; TagLib::FileStream fileStream{ createFileStream(p) };
std::unique_ptr<TagLib::File> file{ parseFileByExtension(&fileStream, p.extension(), readStyle, readAudioProperties.value()) }; std::unique_ptr<TagLib::File> file{ parseFileByExtension(&fileStream, p.extension(), readStyle, readAudioProperties.value()) };
if (!file) if (!file)
{
LMS_LOG(METADATA, DEBUG, "File " << p << ": failed to parse by extension");
file = parseFileByContent(&fileStream, readStyle, readAudioProperties.value()); file = parseFileByContent(&fileStream, readStyle, readAudioProperties.value());
if (!file)
LMS_LOG(METADATA, DEBUG, "File " << p << ": failed to parse by content");
}
return file; return file;
} }
@@ -37,10 +37,59 @@
namespace lms::scanner namespace lms::scanner
{ {
using namespace db;
namespace namespace
{ {
using ExploreFileCallback = std::function<bool(std::error_code, const std::filesystem::path& path, const std::filesystem::directory_entry*)>;
bool exploreFilesRecursive(const std::filesystem::path& directory, ExploreFileCallback cb, const std::filesystem::path* excludeDirFileName)
{
std::error_code ec;
std::filesystem::directory_iterator itPath{ directory, std::filesystem::directory_options::follow_directory_symlink, ec };
if (ec)
{
cb(ec, directory, nullptr);
return true; // try to continue exploring anyway
}
if (excludeDirFileName && !excludeDirFileName->empty())
{
const std::filesystem::path excludePath{ directory / *excludeDirFileName };
if (std::filesystem::exists(excludePath, ec))
{
LMS_LOG(DBUPDATER, DEBUG, "Found " << excludePath << ": skipping directory");
return true;
}
}
std::filesystem::directory_iterator itEnd;
while (itPath != itEnd)
{
bool continueExploring{ true };
const std::filesystem::directory_entry& entry{ *itPath };
const std::filesystem::path& path{ entry.path() };
if (ec)
{
continueExploring = cb(ec, path, nullptr);
}
else
{
if (entry.is_regular_file())
continueExploring = cb(ec, path, &entry);
else if (entry.is_directory())
continueExploring = exploreFilesRecursive(path, cb, excludeDirFileName);
}
if (!continueExploring)
return false;
itPath.increment(ec);
}
return true;
}
class FileScanJob : public core::IJob class FileScanJob : public core::IJob
{ {
public: public:
@@ -97,11 +146,11 @@ namespace lms::scanner
std::vector<std::unique_ptr<core::IJob>> jobsDone; std::vector<std::unique_ptr<core::IJob>> jobsDone;
std::vector<std::unique_ptr<IFileScanOperation>> scanOperations; std::vector<std::unique_ptr<IFileScanOperation>> scanOperations;
core::pathUtils::exploreFilesRecursive( exploreFilesRecursive(
mediaLibrary.rootDirectory, [&](std::error_code ec, const std::filesystem::path& path, const core::pathUtils::FileInfo* fileInfo) { mediaLibrary.rootDirectory, [&](std::error_code ec, const std::filesystem::path& path, const std::filesystem::directory_entry* fileEntry) {
LMS_SCOPED_TRACE_DETAILED("Scanner", "OnExploreFile"); LMS_SCOPED_TRACE_DETAILED("Scanner", "OnExploreFile");
assert((ec && !fileInfo) || (!ec && fileInfo)); assert((ec && !fileEntry) || (!ec && fileEntry));
if (_abortScan) if (_abortScan)
return false; // stop iterating return false; // stop iterating
@@ -117,8 +166,8 @@ namespace lms::scanner
fileToScan.filePath = path; fileToScan.filePath = path;
fileToScan.mediaLibrary = mediaLibrary; fileToScan.mediaLibrary = mediaLibrary;
fileToScan.lastWriteTime.setTime_t(fileInfo->lastWriteTime.toTime_t()); // sec resolution, as stored in the database fileToScan.lastWriteTime.setTime_t(Wt::WDateTime{ std::chrono::file_clock::to_sys(fileEntry->last_write_time()) }.toTime_t()); // sec resolution, as stored in the database
fileToScan.fileSize = fileInfo->fileSize; fileToScan.fileSize = fileEntry->file_size();
if (context.scanOptions.fullScan || scanner->needsScan(fileToScan)) if (context.scanOptions.fullScan || scanner->needsScan(fileToScan))
{ {