From 75cbbde598d2949f0523aef885751a4884986c23 Mon Sep 17 00:00:00 2001 From: emeric Date: Mon, 7 Apr 2025 22:48:10 +0200 Subject: [PATCH] No need to full rescan when changing some settings --- src/libs/database/impl/Migration.cpp | 9 +- src/libs/database/impl/ScanSettings.cpp | 35 ++-- src/libs/database/impl/Session.cpp | 4 +- .../include/database/ScanSettings.hpp | 21 ++- src/libs/services/scanner/CMakeLists.txt | 1 + .../services/scanner/impl/ScannerService.cpp | 167 +++++++++++------- .../services/scanner/impl/ScannerService.hpp | 3 +- .../services/scanner/impl/ScannerSettings.hpp | 2 +- .../impl/scanners/AudioFileScanOperation.cpp | 2 +- .../impl/scanners/AudioFileScanner.cpp | 2 +- .../services/scanner/impl/steps/IScanStep.hpp | 1 + .../steps/ScanStepArtistReconciliation.cpp | 14 +- .../steps/ScanStepArtistReconciliation.hpp | 1 + .../steps/ScanStepAssociateArtistImages.cpp | 14 +- .../steps/ScanStepAssociateArtistImages.hpp | 1 + .../steps/ScanStepAssociateExternalLyrics.cpp | 14 +- .../steps/ScanStepAssociateExternalLyrics.hpp | 1 + .../steps/ScanStepAssociatePlayListTracks.cpp | 17 +- .../steps/ScanStepAssociatePlayListTracks.hpp | 1 + .../steps/ScanStepAssociateReleaseImages.cpp | 14 +- .../steps/ScanStepAssociateReleaseImages.hpp | 1 + .../scanner/impl/steps/ScanStepBase.cpp | 35 ++++ .../scanner/impl/steps/ScanStepBase.hpp | 17 +- .../steps/ScanStepCheckForDuplicatedFiles.cpp | 9 +- .../steps/ScanStepCheckForDuplicatedFiles.hpp | 1 + .../steps/ScanStepCheckForRemovedFiles.cpp | 9 +- .../steps/ScanStepCheckForRemovedFiles.hpp | 1 + .../scanner/impl/steps/ScanStepCompact.cpp | 10 +- .../scanner/impl/steps/ScanStepCompact.hpp | 1 + .../steps/ScanStepComputeClusterStats.cpp | 11 +- .../steps/ScanStepComputeClusterStats.hpp | 1 + .../impl/steps/ScanStepDiscoverFiles.cpp | 6 + .../impl/steps/ScanStepDiscoverFiles.hpp | 1 + .../scanner/impl/steps/ScanStepOptimize.cpp | 46 ++--- .../scanner/impl/steps/ScanStepOptimize.hpp | 1 + .../steps/ScanStepRemoveOrphanedDbEntries.cpp | 6 + .../steps/ScanStepRemoveOrphanedDbEntries.hpp | 1 + .../scanner/impl/steps/ScanStepScanFiles.cpp | 6 + .../scanner/impl/steps/ScanStepScanFiles.hpp | 1 + .../steps/ScanStepUpdateLibraryFields.cpp | 5 + .../steps/ScanStepUpdateLibraryFields.hpp | 1 + 41 files changed, 331 insertions(+), 163 deletions(-) create mode 100644 src/libs/services/scanner/impl/steps/ScanStepBase.cpp diff --git a/src/libs/database/impl/Migration.cpp b/src/libs/database/impl/Migration.cpp index f20bf21d..57859eb0 100644 --- a/src/libs/database/impl/Migration.cpp +++ b/src/libs/database/impl/Migration.cpp @@ -35,7 +35,7 @@ namespace lms::db { namespace { - static constexpr Version LMS_DATABASE_VERSION{ 86 }; + static constexpr Version LMS_DATABASE_VERSION{ 87 }; } VersionInfo::VersionInfo() @@ -1178,6 +1178,12 @@ FROM tracklist)"); utils::executeCommand(*session.getDboSession(), "UPDATE scan_settings SET scan_version = scan_version + 1"); } + void migrateFromV86(Session& session) + { + utils::executeCommand(*session.getDboSession(), "ALTER TABLE scan_settings ADD COLUMN name TEXT NON NULL DEFAULT('')"); + utils::executeCommand(*session.getDboSession(), "ALTER TABLE scan_settings RENAME COLUMN scan_version TO audio_scan_version"); + } + bool doDbMigration(Session& session) { constexpr std::string_view outdatedMsg{ "Outdated database, please rebuild it (delete the .db file and restart)" }; @@ -1240,6 +1246,7 @@ FROM tracklist)"); { 83, migrateFromV83 }, { 84, migrateFromV84 }, { 85, migrateFromV85 }, + { 86, migrateFromV86 }, }; bool migrationPerformed{}; diff --git a/src/libs/database/impl/ScanSettings.cpp b/src/libs/database/impl/ScanSettings.cpp index 5059eb12..828e61b2 100644 --- a/src/libs/database/impl/ScanSettings.cpp +++ b/src/libs/database/impl/ScanSettings.cpp @@ -26,24 +26,25 @@ #include "database/Session.hpp" #include "Utils.hpp" +#include "traits/StringViewTraits.hpp" namespace lms::db { - void ScanSettings::init(Session& session) + ScanSettings::ScanSettings(std::string_view name) + : _name{ name } { - session.checkWriteTransaction(); - - if (pointer settings{ get(session) }) - return; - - session.getDboSession()->add(std::make_unique()); } - ScanSettings::pointer ScanSettings::get(Session& session) + ScanSettings::pointer ScanSettings::create(Session& session, std::string_view name) + { + return session.getDboSession()->add(std::unique_ptr(new ScanSettings{ name })); + } + + ScanSettings::pointer ScanSettings::get(Session& session, std::string_view name) { session.checkReadTransaction(); - return utils::fetchQuerySingleResult(session.getDboSession()->find()); + return utils::fetchQuerySingleResult(session.getDboSession()->find().where("name = ?").bind(name)); } std::vector ScanSettings::getExtraTagsToScan() const @@ -69,7 +70,7 @@ namespace lms::db { std::string newTagsToScan{ core::stringUtils::joinStrings(extraTags, ";") }; if (newTagsToScan != _extraTagsToScan) - incScanVersion(); + incAudioScanVersion(); _extraTagsToScan = std::move(newTagsToScan); } @@ -80,7 +81,7 @@ namespace lms::db if (tagDelimiters != _artistTagDelimiters) { _artistTagDelimiters.swap(tagDelimiters); - incScanVersion(); + incAudioScanVersion(); } } @@ -90,30 +91,24 @@ namespace lms::db if (tagDelimiters != _defaultTagDelimiters) { _defaultTagDelimiters.swap(tagDelimiters); - incScanVersion(); + incAudioScanVersion(); } } void ScanSettings::setSkipSingleReleasePlayLists(bool value) { if (_skipSingleReleasePlayLists != value) - { _skipSingleReleasePlayLists = value; - incScanVersion(); - } } void ScanSettings::setAllowMBIDArtistMerge(bool value) { if (_allowMBIDArtistMerge != value) - { _allowMBIDArtistMerge = value; - incScanVersion(); - } } - void ScanSettings::incScanVersion() + void ScanSettings::incAudioScanVersion() { - _scanVersion += 1; + _audioScanVersion += 1; } } // namespace lms::db diff --git a/src/libs/database/impl/Session.cpp b/src/libs/database/impl/Session.cpp index d417f44a..9f3a2c0d 100644 --- a/src/libs/database/impl/Session.cpp +++ b/src/libs/database/impl/Session.cpp @@ -180,7 +180,9 @@ namespace lms::db // TODO: move this elsewhere { auto uniqueTransaction{ createWriteTransaction() }; - ScanSettings::init(*this); + + if (!ScanSettings::get(*this)) + create(); } return migrationPerformed; diff --git a/src/libs/database/include/database/ScanSettings.hpp b/src/libs/database/include/database/ScanSettings.hpp index b1fe8c97..a43ae04d 100644 --- a/src/libs/database/include/database/ScanSettings.hpp +++ b/src/libs/database/include/database/ScanSettings.hpp @@ -19,7 +19,6 @@ #pragma once -#include #include #include #include @@ -58,12 +57,12 @@ namespace lms::db None, }; - static void init(Session& session); + ScanSettings() = default; - static pointer get(Session& session); + static pointer get(Session& session, std::string_view name = ""); // Getters - std::size_t getScanVersion() const { return _scanVersion; } + std::size_t getAudioScanVersion() const { return _audioScanVersion; } Wt::WTime getUpdateStartTime() const { return _startTime; } UpdatePeriod getUpdatePeriod() const { return _updatePeriod; } std::vector getExtraTagsToScan() const; @@ -82,12 +81,12 @@ namespace lms::db void setDefaultTagDelimiters(std::span delimiters); void setSkipSingleReleasePlayLists(bool value); void setAllowMBIDArtistMerge(bool value); - void incScanVersion(); template void persist(Action& a) { - Wt::Dbo::field(a, _scanVersion, "scan_version"); + Wt::Dbo::field(a, _name, "name"); + Wt::Dbo::field(a, _audioScanVersion, "audio_scan_version"); Wt::Dbo::field(a, _startTime, "start_time"); Wt::Dbo::field(a, _updatePeriod, "update_period"); Wt::Dbo::field(a, _similarityEngineType, "similarity_engine_type"); @@ -99,7 +98,15 @@ namespace lms::db } private: - int _scanVersion{}; + friend class Session; + + ScanSettings(std::string_view name); + static pointer create(Session& session, std::string_view name = ""); + + void incAudioScanVersion(); + + std::string _name; + int _audioScanVersion{}; Wt::WTime _startTime = Wt::WTime{ 0, 0, 0 }; UpdatePeriod _updatePeriod{ UpdatePeriod::Never }; SimilarityEngineType _similarityEngineType{ SimilarityEngineType::Clusters }; diff --git a/src/libs/services/scanner/CMakeLists.txt b/src/libs/services/scanner/CMakeLists.txt index c92f0abd..7966d1f5 100644 --- a/src/libs/services/scanner/CMakeLists.txt +++ b/src/libs/services/scanner/CMakeLists.txt @@ -13,6 +13,7 @@ add_library(lmsscanner STATIC impl/steps/ScanStepAssociateExternalLyrics.cpp impl/steps/ScanStepAssociatePlayListTracks.cpp impl/steps/ScanStepAssociateReleaseImages.cpp + impl/steps/ScanStepBase.cpp impl/steps/ScanStepCheckForDuplicatedFiles.cpp impl/steps/ScanStepCheckForRemovedFiles.cpp impl/steps/ScanStepCompact.cpp diff --git a/src/libs/services/scanner/impl/ScannerService.cpp b/src/libs/services/scanner/impl/ScannerService.cpp index 99fed0f9..2f3acf8c 100644 --- a/src/libs/services/scanner/impl/ScannerService.cpp +++ b/src/libs/services/scanner/impl/ScannerService.cpp @@ -28,6 +28,7 @@ #include "core/ITraceLogger.hpp" #include "database/MediaLibrary.hpp" #include "database/ScanSettings.hpp" +#include "database/Session.hpp" #include "scanners/ArtistInfoFileScanner.hpp" #include "scanners/AudioFileScanner.hpp" @@ -56,6 +57,9 @@ namespace lms::scanner namespace { + static constexpr std::string_view currentSettingsName{ "" }; + static constexpr std::string_view lastScanSettingsName{ "last_scan" }; + Wt::WDate getNextMonday(Wt::WDate current) { do @@ -75,6 +79,60 @@ namespace lms::scanner return current; } + + std::optional readScannerSettings(db::Session& session, std::string_view name) + { + std::optional settings; + + auto transaction{ session.createReadTransaction() }; + + const ScanSettings::pointer scanSettings{ ScanSettings::get(session, name) }; + if (!scanSettings) + return settings; + + settings.emplace(); + settings->audioScanVersion = scanSettings->getAudioScanVersion(); + settings->startTime = scanSettings->getUpdateStartTime(); + settings->updatePeriod = scanSettings->getUpdatePeriod(); + + MediaLibrary::find(session, [&](const MediaLibrary::pointer& mediaLibrary) { + MediaLibraryInfo info; + info.firstScan = mediaLibrary->isEmpty(); + info.id = mediaLibrary->getId(); + info.rootDirectory = mediaLibrary->getPath().lexically_normal(); + + settings->mediaLibraries.push_back(info); + }); + + { + const auto& tags{ scanSettings->getExtraTagsToScan() }; + std::transform(std::cbegin(tags), std::cend(tags), std::back_inserter(settings->extraTags), [](std::string_view tag) { return std::string{ tag }; }); + } + + settings->artistTagDelimiters = scanSettings->getArtistTagDelimiters(); + settings->defaultTagDelimiters = scanSettings->getDefaultTagDelimiters(); + + settings->skipSingleReleasePlayLists = scanSettings->getSkipSingleReleasePlayLists(); + settings->allowArtistMBIDFallback = scanSettings->getAllowMBIDArtistMerge(); + + // TODO, store this in DB + expose in UI + settings->skipDuplicateTrackMBID = core::Service::get()->getBool("scanner-skip-duplicate-mbid", false); + + return settings; + } + + void writeScannerSettings(db::Session& session, std::string_view name, const ScannerSettings& settings) + { + auto transaction{ session.createWriteTransaction() }; + + ScanSettings::pointer scanSettings{ ScanSettings::get(session, name) }; + if (!scanSettings) + scanSettings = session.create(name); + + scanSettings.modify()->setAllowMBIDArtistMerge(settings.allowArtistMBIDFallback); + scanSettings.modify()->setSkipSingleReleasePlayLists(settings.skipSingleReleasePlayLists); + // TODO add more fields + } } // namespace std::unique_ptr createScannerService(Db& db) @@ -283,26 +341,7 @@ namespace lms::scanner ScanStats& stats{ scanContext.stats }; stats.startTime = Wt::WDateTime::currentDateTime(); - std::size_t stepIndex{}; - for (auto& scanStep : _scanSteps) - { - LMS_SCOPED_TRACE_OVERVIEW("Scanner", scanStep->getStepName()); - - LMS_LOG(DBUPDATER, DEBUG, "Starting scan step '" << scanStep->getStepName() << "'"); - scanContext.currentStepStats = ScanStepStats{ - .startTime = Wt::WDateTime::currentDateTime(), - .stepCount = _scanSteps.size(), - .stepIndex = stepIndex++, - .currentStep = scanStep->getStep(), - .totalElems = 0, - .processedElems = 0 - }; - - notifyInProgress(scanContext.currentStepStats); - scanStep->process(scanContext); - notifyInProgress(scanContext.currentStepStats); - LMS_LOG(DBUPDATER, DEBUG, "Completed scan step '" << scanStep->getStepName() << "'"); - } + processScanSteps(scanContext); { std::unique_lock lock{ _statusMutex }; @@ -322,6 +361,10 @@ namespace lms::scanner _lastCompleteScanStats = stats; } + // save current settings as last scan settings to compare during next scans if something changed + writeScannerSettings(_db.getTLSSession(), lastScanSettingsName, _settings); + _lastScanSettings = _settings; + LMS_LOG(DBUPDATER, DEBUG, "Scan not aborted, scheduling next scan!"); scheduleNextScan(); @@ -333,16 +376,54 @@ namespace lms::scanner } } + void ScannerService::processScanSteps(ScanContext& context) + { + std::size_t stepIndex{}; + for (auto& scanStep : _scanSteps) + { + context.currentStepStats = ScanStepStats{ + .startTime = Wt::WDateTime::currentDateTime(), + .stepCount = _scanSteps.size(), + .stepIndex = stepIndex++, + .currentStep = scanStep->getStep(), + .totalElems = 0, + .processedElems = 0 + }; + + if (_abortScan) + break; + + if (!scanStep->needProcess(context)) + { + LMS_LOG(DBUPDATER, DEBUG, "Skipping scan step '" << scanStep->getStepName() << "'"); + continue; + } + + { + LMS_SCOPED_TRACE_OVERVIEW("Scanner", scanStep->getStepName()); + + LMS_LOG(DBUPDATER, DEBUG, "Starting scan step '" << scanStep->getStepName() << "'"); + notifyInProgress(context.currentStepStats); + scanStep->process(context); + notifyInProgress(context.currentStepStats); + LMS_LOG(DBUPDATER, DEBUG, "Completed scan step '" << scanStep->getStepName() << "'"); + } + } + } + void ScannerService::refreshScanSettings() { - ScannerSettings newSettings{ readSettings() }; - if (_settings == newSettings) + std::optional newSettings{ readScannerSettings(_db.getTLSSession(), currentSettingsName) }; + assert(newSettings.has_value()); + if (_settings == *newSettings) return; LMS_LOG(DBUPDATER, DEBUG, "Scanner settings updated"); - LMS_LOG(DBUPDATER, DEBUG, "Using scan settings version " << newSettings.scanVersion); + LMS_LOG(DBUPDATER, DEBUG, "Using audio scan settings version " << newSettings->audioScanVersion); - _settings = std::move(newSettings); + _settings = std::move(*newSettings); + if (!_lastScanSettings) + _lastScanSettings = readScannerSettings(_db.getTLSSession(), lastScanSettingsName); auto cbFunc{ [this](const ScanStepStats& stats) { notifyInProgressIfNeeded(stats); @@ -360,6 +441,7 @@ namespace lms::scanner ScanStepBase::InitParams params{ .settings = _settings, + .lastScanSettings = _lastScanSettings.has_value() ? &(_lastScanSettings.value()) : nullptr, .progressCallback = cbFunc, .abortScan = _abortScan, .db = _db, @@ -384,43 +466,6 @@ namespace lms::scanner _scanSteps.emplace_back(std::make_unique(params)); } - ScannerSettings ScannerService::readSettings() - { - ScannerSettings newSettings; - - newSettings.skipDuplicateTrackMBID = core::Service::get()->getBool("scanner-skip-duplicate-mbid", false); - { - auto transaction{ _db.getTLSSession().createReadTransaction() }; - - const ScanSettings::pointer scanSettings{ ScanSettings::get(_db.getTLSSession()) }; - - newSettings.scanVersion = scanSettings->getScanVersion(); - newSettings.startTime = scanSettings->getUpdateStartTime(); - newSettings.updatePeriod = scanSettings->getUpdatePeriod(); - - MediaLibrary::find(_db.getTLSSession(), [&](const MediaLibrary::pointer& mediaLibrary) { - MediaLibraryInfo info; - info.firstScan = mediaLibrary->isEmpty(); - info.id = mediaLibrary->getId(); - info.rootDirectory = mediaLibrary->getPath().lexically_normal(); - - newSettings.mediaLibraries.push_back(info); - }); - - { - const auto& tags{ scanSettings->getExtraTagsToScan() }; - std::transform(std::cbegin(tags), std::cend(tags), std::back_inserter(newSettings.extraTags), [](std::string_view tag) { return std::string{ tag }; }); - } - - newSettings.artistTagDelimiters = scanSettings->getArtistTagDelimiters(); - newSettings.defaultTagDelimiters = scanSettings->getDefaultTagDelimiters(); - - newSettings.skipSingleReleasePlayLists = scanSettings->getSkipSingleReleasePlayLists(); - } - - return newSettings; - } - void ScannerService::notifyInProgress(const ScanStepStats& stepStats) { { diff --git a/src/libs/services/scanner/impl/ScannerService.hpp b/src/libs/services/scanner/impl/ScannerService.hpp index 1a819a33..4f26ce8f 100644 --- a/src/libs/services/scanner/impl/ScannerService.hpp +++ b/src/libs/services/scanner/impl/ScannerService.hpp @@ -68,12 +68,12 @@ namespace lms::scanner // Update database (scheduled callback) void scan(const ScanOptions& scanOptions); + void processScanSteps(ScanContext& context); void scanMediaDirectory(const std::filesystem::path& mediaDirectory, bool forceScan, ScanStats& stats); // Helpers void refreshScanSettings(); - ScannerSettings readSettings(); void notifyInProgressIfNeeded(const ScanStepStats& stats); void notifyInProgress(const ScanStepStats& stats); @@ -96,5 +96,6 @@ namespace lms::scanner Wt::WDateTime _nextScheduledScan; ScannerSettings _settings; + std::optional _lastScanSettings; }; } // namespace lms::scanner diff --git a/src/libs/services/scanner/impl/ScannerSettings.hpp b/src/libs/services/scanner/impl/ScannerSettings.hpp index df0aa2fd..cace22e7 100644 --- a/src/libs/services/scanner/impl/ScannerSettings.hpp +++ b/src/libs/services/scanner/impl/ScannerSettings.hpp @@ -35,7 +35,7 @@ namespace lms::scanner struct ScannerSettings { - std::size_t scanVersion{}; + std::size_t audioScanVersion{}; Wt::WTime startTime; db::ScanSettings::UpdatePeriod updatePeriod{ db::ScanSettings::UpdatePeriod::Never }; bool skipDuplicateTrackMBID{}; diff --git a/src/libs/services/scanner/impl/scanners/AudioFileScanOperation.cpp b/src/libs/services/scanner/impl/scanners/AudioFileScanOperation.cpp index b035f7fa..8911e780 100644 --- a/src/libs/services/scanner/impl/scanners/AudioFileScanOperation.cpp +++ b/src/libs/services/scanner/impl/scanners/AudioFileScanOperation.cpp @@ -645,6 +645,7 @@ namespace lms::scanner // Track related data assert(track); + track.modify()->setScanVersion(_settings.audioScanVersion); // Audio properties track.modify()->setBitrate(_parsedTrack->audioProperties.bitrate); @@ -692,7 +693,6 @@ namespace lms::scanner for (const auto& [role, performers] : _parsedTrack->performerArtists) createTrackArtistLinks(dbSession, track, db::TrackArtistLinkType::Performer, role, performers, allowFallback); - track.modify()->setScanVersion(_settings.scanVersion); if (_parsedTrack->medium && _parsedTrack->medium->release) track.modify()->setRelease(getOrCreateRelease(dbSession, *_parsedTrack->medium->release, directory)); else diff --git a/src/libs/services/scanner/impl/scanners/AudioFileScanner.cpp b/src/libs/services/scanner/impl/scanners/AudioFileScanner.cpp index 38f422d4..9b708dfe 100644 --- a/src/libs/services/scanner/impl/scanners/AudioFileScanner.cpp +++ b/src/libs/services/scanner/impl/scanners/AudioFileScanner.cpp @@ -106,7 +106,7 @@ namespace lms::scanner const db::Track::pointer track{ db::Track::findByPath(dbSession, file.file) }; if (track && track->getLastWriteTime() == lastWriteTime - && track->getScanVersion() == _settings.scanVersion) + && track->getScanVersion() == _settings.audioScanVersion) { // this file may have been moved from one library to another, then we just need to update the media library id instead of a full rescan const auto trackMediaLibrary{ track->getMediaLibrary() }; diff --git a/src/libs/services/scanner/impl/steps/IScanStep.hpp b/src/libs/services/scanner/impl/steps/IScanStep.hpp index af6c4071..44adb1f7 100644 --- a/src/libs/services/scanner/impl/steps/IScanStep.hpp +++ b/src/libs/services/scanner/impl/steps/IScanStep.hpp @@ -32,6 +32,7 @@ namespace lms::scanner virtual ScanStep getStep() const = 0; virtual core::LiteralString getStepName() const = 0; + virtual bool needProcess(const ScanContext& context) const = 0; virtual void process(ScanContext& context) = 0; }; } // namespace lms::scanner diff --git a/src/libs/services/scanner/impl/steps/ScanStepArtistReconciliation.cpp b/src/libs/services/scanner/impl/steps/ScanStepArtistReconciliation.cpp index 404923ec..29177e36 100644 --- a/src/libs/services/scanner/impl/steps/ScanStepArtistReconciliation.cpp +++ b/src/libs/services/scanner/impl/steps/ScanStepArtistReconciliation.cpp @@ -74,6 +74,12 @@ namespace lms::scanner } } // namespace + bool ScanStepArtistReconciliation::needProcess([[maybe_unused]] const ScanContext& context) const + { + // Since this step is very fast in case there is nothing to do, no need to skip if nothing has changed + return true; + } + void ScanStepArtistReconciliation::process(ScanContext& context) { // Reconcile artist links @@ -99,7 +105,7 @@ namespace lms::scanner db::Session& session{ _db.getTLSSession() }; std::vector artistInfo; - while (true) + while (!_abortScan) { artistInfo.clear(); { @@ -133,7 +139,7 @@ namespace lms::scanner db::Session& session{ _db.getTLSSession() }; std::vector artistInfo; - while (true) + while (!_abortScan) { artistInfo.clear(); { @@ -166,7 +172,7 @@ namespace lms::scanner db::Session& session{ _db.getTLSSession() }; std::vector links; - while (true) + while (!_abortScan) { links.clear(); { @@ -200,7 +206,7 @@ namespace lms::scanner db::Session& session{ _db.getTLSSession() }; std::vector links; - while (true) + while (!_abortScan) { links.clear(); { diff --git a/src/libs/services/scanner/impl/steps/ScanStepArtistReconciliation.hpp b/src/libs/services/scanner/impl/steps/ScanStepArtistReconciliation.hpp index 33c55aec..6121dcb4 100644 --- a/src/libs/services/scanner/impl/steps/ScanStepArtistReconciliation.hpp +++ b/src/libs/services/scanner/impl/steps/ScanStepArtistReconciliation.hpp @@ -31,6 +31,7 @@ namespace lms::scanner private: ScanStep getStep() const override { return ScanStep::ReconciliateArtists; } core::LiteralString getStepName() const override { return "Artist reconciliation"; } + bool needProcess(const ScanContext& context) const override; void process(ScanContext& context) override; void updateLinksForArtistNameNoLongerMatch(ScanContext& context); diff --git a/src/libs/services/scanner/impl/steps/ScanStepAssociateArtistImages.cpp b/src/libs/services/scanner/impl/steps/ScanStepAssociateArtistImages.cpp index 91d06948..aa92af77 100644 --- a/src/libs/services/scanner/impl/steps/ScanStepAssociateArtistImages.cpp +++ b/src/libs/services/scanner/impl/steps/ScanStepAssociateArtistImages.cpp @@ -254,14 +254,16 @@ namespace lms::scanner { } + bool ScanStepAssociateArtistImages::needProcess(const ScanContext& context) const + { + if (context.stats.nbChanges() > 0) + return true; + + return false; + } + void ScanStepAssociateArtistImages::process(ScanContext& context) { - if (_abortScan) - return; - - if (context.stats.nbChanges() == 0) - return; - auto& session{ _db.getTLSSession() }; { diff --git a/src/libs/services/scanner/impl/steps/ScanStepAssociateArtistImages.hpp b/src/libs/services/scanner/impl/steps/ScanStepAssociateArtistImages.hpp index b041f65a..f57bcee2 100644 --- a/src/libs/services/scanner/impl/steps/ScanStepAssociateArtistImages.hpp +++ b/src/libs/services/scanner/impl/steps/ScanStepAssociateArtistImages.hpp @@ -37,6 +37,7 @@ namespace lms::scanner private: ScanStep getStep() const override { return ScanStep::AssociateArtistImages; } core::LiteralString getStepName() const override { return "Associate artist images"; } + bool needProcess(const ScanContext& context) const override; void process(ScanContext& context) override; const std::vector _artistFileNames; diff --git a/src/libs/services/scanner/impl/steps/ScanStepAssociateExternalLyrics.cpp b/src/libs/services/scanner/impl/steps/ScanStepAssociateExternalLyrics.cpp index 434342ca..d065e8f7 100644 --- a/src/libs/services/scanner/impl/steps/ScanStepAssociateExternalLyrics.cpp +++ b/src/libs/services/scanner/impl/steps/ScanStepAssociateExternalLyrics.cpp @@ -138,14 +138,16 @@ namespace lms::scanner } } // namespace + bool ScanStepAssociateExternalLyrics::needProcess(const ScanContext& context) const + { + if (context.stats.nbChanges() > 0) + return true; + + return false; + } + void ScanStepAssociateExternalLyrics::process(ScanContext& context) { - if (_abortScan) - return; - - if (context.stats.nbChanges() == 0) - return; - auto& session{ _db.getTLSSession() }; { diff --git a/src/libs/services/scanner/impl/steps/ScanStepAssociateExternalLyrics.hpp b/src/libs/services/scanner/impl/steps/ScanStepAssociateExternalLyrics.hpp index 0a5c6951..79349f3c 100644 --- a/src/libs/services/scanner/impl/steps/ScanStepAssociateExternalLyrics.hpp +++ b/src/libs/services/scanner/impl/steps/ScanStepAssociateExternalLyrics.hpp @@ -31,6 +31,7 @@ namespace lms::scanner private: ScanStep getStep() const override { return ScanStep::AssociateExternalLyrics; } core::LiteralString getStepName() const override { return "Associate external lyrics"; } + bool needProcess(const ScanContext& context) const override; void process(ScanContext& context) override; }; } // namespace lms::scanner diff --git a/src/libs/services/scanner/impl/steps/ScanStepAssociatePlayListTracks.cpp b/src/libs/services/scanner/impl/steps/ScanStepAssociatePlayListTracks.cpp index b3852f9f..4b1e410e 100644 --- a/src/libs/services/scanner/impl/steps/ScanStepAssociatePlayListTracks.cpp +++ b/src/libs/services/scanner/impl/steps/ScanStepAssociatePlayListTracks.cpp @@ -212,14 +212,19 @@ namespace lms::scanner } } // namespace + bool ScanStepAssociatePlayListTracks::needProcess(const ScanContext& context) const + { + if (context.stats.nbChanges() > 0) + return true; + + if (getLastScanSettings() && getLastScanSettings()->skipSingleReleasePlayLists != _settings.skipSingleReleasePlayLists) + return true; + + return false; + } + void ScanStepAssociatePlayListTracks::process(ScanContext& context) { - if (_abortScan) - return; - - if (context.stats.nbChanges() == 0) - return; - auto& session{ _db.getTLSSession() }; { diff --git a/src/libs/services/scanner/impl/steps/ScanStepAssociatePlayListTracks.hpp b/src/libs/services/scanner/impl/steps/ScanStepAssociatePlayListTracks.hpp index 86f05674..a7f9392e 100644 --- a/src/libs/services/scanner/impl/steps/ScanStepAssociatePlayListTracks.hpp +++ b/src/libs/services/scanner/impl/steps/ScanStepAssociatePlayListTracks.hpp @@ -31,6 +31,7 @@ namespace lms::scanner private: ScanStep getStep() const override { return ScanStep::AssociatePlayListTracks; } core::LiteralString getStepName() const override { return "Associate playlist tracks"; } + bool needProcess(const ScanContext& context) const override; void process(ScanContext& context) override; }; } // namespace lms::scanner diff --git a/src/libs/services/scanner/impl/steps/ScanStepAssociateReleaseImages.cpp b/src/libs/services/scanner/impl/steps/ScanStepAssociateReleaseImages.cpp index cefb76ec..c384fab8 100644 --- a/src/libs/services/scanner/impl/steps/ScanStepAssociateReleaseImages.cpp +++ b/src/libs/services/scanner/impl/steps/ScanStepAssociateReleaseImages.cpp @@ -199,14 +199,16 @@ namespace lms::scanner { } + bool ScanStepAssociateReleaseImages::needProcess(const ScanContext& context) const + { + if (context.stats.nbChanges() > 0) + return true; + + return false; + } + void ScanStepAssociateReleaseImages::process(ScanContext& context) { - if (_abortScan) - return; - - if (context.stats.nbChanges() == 0) - return; - auto& session{ _db.getTLSSession() }; { diff --git a/src/libs/services/scanner/impl/steps/ScanStepAssociateReleaseImages.hpp b/src/libs/services/scanner/impl/steps/ScanStepAssociateReleaseImages.hpp index abf8a62f..70376a09 100644 --- a/src/libs/services/scanner/impl/steps/ScanStepAssociateReleaseImages.hpp +++ b/src/libs/services/scanner/impl/steps/ScanStepAssociateReleaseImages.hpp @@ -37,6 +37,7 @@ namespace lms::scanner private: ScanStep getStep() const override { return ScanStep::AssociateReleaseImages; } core::LiteralString getStepName() const override { return "Associate release images"; } + bool needProcess(const ScanContext& context) const override; void process(ScanContext& context) override; const std::vector _releaseFileNames; diff --git a/src/libs/services/scanner/impl/steps/ScanStepBase.cpp b/src/libs/services/scanner/impl/steps/ScanStepBase.cpp new file mode 100644 index 00000000..fa09f4ac --- /dev/null +++ b/src/libs/services/scanner/impl/steps/ScanStepBase.cpp @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2023 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 "ScanStepBase.hpp" + +namespace lms::scanner +{ + ScanStepBase::ScanStepBase(InitParams& initParams) + : _settings{ initParams.settings } + , _progressCallback{ initParams.progressCallback } + , _abortScan{ initParams.abortScan } + , _db{ initParams.db } + , _fileScanners(std::cbegin(initParams.fileScanners), std::cend(initParams.fileScanners)) + , _lastScanSettings{ initParams.lastScanSettings } + { + } + + ScanStepBase::~ScanStepBase() = default; +} // namespace lms::scanner diff --git a/src/libs/services/scanner/impl/steps/ScanStepBase.hpp b/src/libs/services/scanner/impl/steps/ScanStepBase.hpp index bd78977b..0b209415 100644 --- a/src/libs/services/scanner/impl/steps/ScanStepBase.hpp +++ b/src/libs/services/scanner/impl/steps/ScanStepBase.hpp @@ -44,28 +44,27 @@ namespace lms::scanner struct InitParams { const ScannerSettings& settings; + const ScannerSettings* lastScanSettings{}; ProgressCallback progressCallback; bool& abortScan; db::Db& db; std::span fileScanners; }; - ScanStepBase(InitParams& initParams) - : _settings{ initParams.settings } - , _progressCallback{ initParams.progressCallback } - , _abortScan{ initParams.abortScan } - , _db{ initParams.db } - , _fileScanners(std::cbegin(initParams.fileScanners), std::cend(initParams.fileScanners)) - { - } - ~ScanStepBase() override = default; + ScanStepBase(InitParams& initParams); + ~ScanStepBase() override; ScanStepBase(const ScanStepBase&) = delete; ScanStepBase& operator=(const ScanStepBase&) = delete; protected: + const ScannerSettings* getLastScanSettings() const { return _lastScanSettings; } + const ScannerSettings& _settings; ProgressCallback _progressCallback; bool& _abortScan; db::Db& _db; std::vector _fileScanners; + + private: + const ScannerSettings* _lastScanSettings{}; }; } // namespace lms::scanner diff --git a/src/libs/services/scanner/impl/steps/ScanStepCheckForDuplicatedFiles.cpp b/src/libs/services/scanner/impl/steps/ScanStepCheckForDuplicatedFiles.cpp index 9b92321b..0fc8deaa 100644 --- a/src/libs/services/scanner/impl/steps/ScanStepCheckForDuplicatedFiles.cpp +++ b/src/libs/services/scanner/impl/steps/ScanStepCheckForDuplicatedFiles.cpp @@ -26,13 +26,16 @@ namespace lms::scanner { + bool ScanStepCheckForDuplicatedFiles::needProcess([[maybe_unused]] const ScanContext& context) const + { + // Always check for everything + return true; + } + void ScanStepCheckForDuplicatedFiles::process(ScanContext& context) { using namespace db; - if (_abortScan) - return; - Session& session{ _db.getTLSSession() }; auto transaction{ session.createReadTransaction() }; diff --git a/src/libs/services/scanner/impl/steps/ScanStepCheckForDuplicatedFiles.hpp b/src/libs/services/scanner/impl/steps/ScanStepCheckForDuplicatedFiles.hpp index ca16031f..2af2d6bc 100644 --- a/src/libs/services/scanner/impl/steps/ScanStepCheckForDuplicatedFiles.hpp +++ b/src/libs/services/scanner/impl/steps/ScanStepCheckForDuplicatedFiles.hpp @@ -31,6 +31,7 @@ namespace lms::scanner private: core::LiteralString getStepName() const override { return "Check for duplicated files"; } ScanStep getStep() const override { return ScanStep::CheckForDuplicatedFiles; } + bool needProcess(const ScanContext& context) const override; void process(ScanContext& context) override; }; } // namespace lms::scanner diff --git a/src/libs/services/scanner/impl/steps/ScanStepCheckForRemovedFiles.cpp b/src/libs/services/scanner/impl/steps/ScanStepCheckForRemovedFiles.cpp index 817261f3..6f04948b 100644 --- a/src/libs/services/scanner/impl/steps/ScanStepCheckForRemovedFiles.cpp +++ b/src/libs/services/scanner/impl/steps/ScanStepCheckForRemovedFiles.cpp @@ -41,11 +41,14 @@ namespace lms::scanner constexpr std::size_t batchSize = 100; } + bool ScanStepCheckForRemovedFiles::needProcess([[maybe_unused]] const ScanContext& context) const + { + // always check for removed files + return true; + } + void ScanStepCheckForRemovedFiles::process(ScanContext& context) { - if (_abortScan) - return; - db::Session& session{ _db.getTLSSession() }; { diff --git a/src/libs/services/scanner/impl/steps/ScanStepCheckForRemovedFiles.hpp b/src/libs/services/scanner/impl/steps/ScanStepCheckForRemovedFiles.hpp index 18db8896..d33bec8c 100644 --- a/src/libs/services/scanner/impl/steps/ScanStepCheckForRemovedFiles.hpp +++ b/src/libs/services/scanner/impl/steps/ScanStepCheckForRemovedFiles.hpp @@ -34,6 +34,7 @@ namespace lms::scanner private: core::LiteralString getStepName() const override { return "Check for removed files"; } ScanStep getStep() const override { return ScanStep::CheckForRemovedFiles; } + bool needProcess(const ScanContext& context) const override; void process(ScanContext& context) override; template diff --git a/src/libs/services/scanner/impl/steps/ScanStepCompact.cpp b/src/libs/services/scanner/impl/steps/ScanStepCompact.cpp index 482065bd..bc740555 100644 --- a/src/libs/services/scanner/impl/steps/ScanStepCompact.cpp +++ b/src/libs/services/scanner/impl/steps/ScanStepCompact.cpp @@ -24,10 +24,14 @@ namespace lms::scanner { - void ScanStepCompact::process(ScanContext& context) + bool ScanStepCompact::needProcess(const ScanContext& context) const { // Don't auto compact as it may be too annoying to block the whole application for very large databases - if (context.scanOptions.compact) - _db.getTLSSession().vacuum(); + return context.scanOptions.compact; + } + + void ScanStepCompact::process([[maybe_unused]] ScanContext& context) + { + _db.getTLSSession().vacuum(); } } // namespace lms::scanner diff --git a/src/libs/services/scanner/impl/steps/ScanStepCompact.hpp b/src/libs/services/scanner/impl/steps/ScanStepCompact.hpp index d1c4e195..bb18477c 100644 --- a/src/libs/services/scanner/impl/steps/ScanStepCompact.hpp +++ b/src/libs/services/scanner/impl/steps/ScanStepCompact.hpp @@ -31,6 +31,7 @@ namespace lms::scanner private: ScanStep getStep() const override { return ScanStep::Compact; } core::LiteralString getStepName() const override { return "Compact"; } + bool needProcess(const ScanContext& context) const override; void process(ScanContext& context) override; }; } // namespace lms::scanner diff --git a/src/libs/services/scanner/impl/steps/ScanStepComputeClusterStats.cpp b/src/libs/services/scanner/impl/steps/ScanStepComputeClusterStats.cpp index f776c6eb..e4344d95 100644 --- a/src/libs/services/scanner/impl/steps/ScanStepComputeClusterStats.cpp +++ b/src/libs/services/scanner/impl/steps/ScanStepComputeClusterStats.cpp @@ -25,13 +25,18 @@ namespace lms::scanner { + bool ScanStepComputeClusterStats::needProcess(const ScanContext& context) const + { + if (context.stats.nbChanges() > 0) + return true; + + return false; + } + void ScanStepComputeClusterStats::process(ScanContext& context) { using namespace db; - if (context.stats.nbChanges() == 0) - return; - Session& dbSession{ _db.getTLSSession() }; const std::size_t clusterCount{ [&] { diff --git a/src/libs/services/scanner/impl/steps/ScanStepComputeClusterStats.hpp b/src/libs/services/scanner/impl/steps/ScanStepComputeClusterStats.hpp index 1139c7fc..56e0788c 100644 --- a/src/libs/services/scanner/impl/steps/ScanStepComputeClusterStats.hpp +++ b/src/libs/services/scanner/impl/steps/ScanStepComputeClusterStats.hpp @@ -31,6 +31,7 @@ namespace lms::scanner private: ScanStep getStep() const override { return ScanStep::ComputeClusterStats; } core::LiteralString getStepName() const override { return "Compute cluster stats"; } + bool needProcess(const ScanContext& context) const override; void process(ScanContext& context) override; }; } // namespace lms::scanner diff --git a/src/libs/services/scanner/impl/steps/ScanStepDiscoverFiles.cpp b/src/libs/services/scanner/impl/steps/ScanStepDiscoverFiles.cpp index 974c6f13..8babbd5b 100644 --- a/src/libs/services/scanner/impl/steps/ScanStepDiscoverFiles.cpp +++ b/src/libs/services/scanner/impl/steps/ScanStepDiscoverFiles.cpp @@ -28,6 +28,12 @@ namespace lms::scanner { + bool ScanStepDiscoverFiles::needProcess([[maybe_unused]] const ScanContext& context) const + { + // always discover files + return true; + } + void ScanStepDiscoverFiles::process(ScanContext& context) { context.stats.totalFileCount = 0; diff --git a/src/libs/services/scanner/impl/steps/ScanStepDiscoverFiles.hpp b/src/libs/services/scanner/impl/steps/ScanStepDiscoverFiles.hpp index 29d6d3af..ab8baeff 100644 --- a/src/libs/services/scanner/impl/steps/ScanStepDiscoverFiles.hpp +++ b/src/libs/services/scanner/impl/steps/ScanStepDiscoverFiles.hpp @@ -31,6 +31,7 @@ namespace lms::scanner private: ScanStep getStep() const override { return ScanStep::DiscoverFiles; } core::LiteralString getStepName() const override { return "Discover files"; } + bool needProcess(const ScanContext& context) const override; void process(ScanContext& context) override; }; } // namespace lms::scanner diff --git a/src/libs/services/scanner/impl/steps/ScanStepOptimize.cpp b/src/libs/services/scanner/impl/steps/ScanStepOptimize.cpp index 4c65a7b0..97550d22 100644 --- a/src/libs/services/scanner/impl/steps/ScanStepOptimize.cpp +++ b/src/libs/services/scanner/impl/steps/ScanStepOptimize.cpp @@ -25,32 +25,38 @@ namespace lms::scanner { + bool ScanStepOptimize::needProcess(const ScanContext& context) const + { + if (context.scanOptions.forceOptimize) + return true; + + if (context.stats.nbChanges() > (context.stats.nbFiles() / 10)) + return true; + + return false; + } + void ScanStepOptimize::process(ScanContext& context) { - ScanStats& stats{ context.stats }; + LMS_LOG(DBUPDATER, INFO, "Database analyze started"); - if (context.scanOptions.forceOptimize || (stats.nbChanges() > (stats.nbFiles() / 10))) + auto& session{ _db.getTLSSession() }; + + std::vector entries; + session.retrieveEntriesToAnalyze(entries); + context.currentStepStats.totalElems = entries.size(); + _progressCallback(context.currentStepStats); + + for (const std::string& entry : entries) { - LMS_LOG(DBUPDATER, INFO, "Database analyze started"); + if (_abortScan) + break; - auto& session{ _db.getTLSSession() }; - - std::vector entries; - session.retrieveEntriesToAnalyze(entries); - context.currentStepStats.totalElems = entries.size(); + _db.getTLSSession().analyzeEntry(entry); + context.currentStepStats.processedElems++; _progressCallback(context.currentStepStats); - - for (const std::string& entry : entries) - { - if (_abortScan) - break; - - _db.getTLSSession().analyzeEntry(entry); - context.currentStepStats.processedElems++; - _progressCallback(context.currentStepStats); - } - - LMS_LOG(DBUPDATER, INFO, "Database analyze complete"); } + + LMS_LOG(DBUPDATER, INFO, "Database analyze complete"); } } // namespace lms::scanner diff --git a/src/libs/services/scanner/impl/steps/ScanStepOptimize.hpp b/src/libs/services/scanner/impl/steps/ScanStepOptimize.hpp index 117cda3a..c6984c9e 100644 --- a/src/libs/services/scanner/impl/steps/ScanStepOptimize.hpp +++ b/src/libs/services/scanner/impl/steps/ScanStepOptimize.hpp @@ -31,6 +31,7 @@ namespace lms::scanner private: ScanStep getStep() const override { return ScanStep::Optimize; } core::LiteralString getStepName() const override { return "Optimize"; } + bool needProcess(const ScanContext& context) const override; void process(ScanContext& context) override; }; } // namespace lms::scanner diff --git a/src/libs/services/scanner/impl/steps/ScanStepRemoveOrphanedDbEntries.cpp b/src/libs/services/scanner/impl/steps/ScanStepRemoveOrphanedDbEntries.cpp index 131f5c65..4a5e78ea 100644 --- a/src/libs/services/scanner/impl/steps/ScanStepRemoveOrphanedDbEntries.cpp +++ b/src/libs/services/scanner/impl/steps/ScanStepRemoveOrphanedDbEntries.cpp @@ -31,6 +31,12 @@ namespace lms::scanner { + bool ScanStepRemoveOrphanedDbEntries::needProcess([[maybe_unused]] const ScanContext& context) const + { + // fast enough when there is nothing to do + return true; + } + void ScanStepRemoveOrphanedDbEntries::process(ScanContext& context) { removeOrphanedClusters(context); diff --git a/src/libs/services/scanner/impl/steps/ScanStepRemoveOrphanedDbEntries.hpp b/src/libs/services/scanner/impl/steps/ScanStepRemoveOrphanedDbEntries.hpp index 72ca0315..c7af0d06 100644 --- a/src/libs/services/scanner/impl/steps/ScanStepRemoveOrphanedDbEntries.hpp +++ b/src/libs/services/scanner/impl/steps/ScanStepRemoveOrphanedDbEntries.hpp @@ -31,6 +31,7 @@ namespace lms::scanner private: core::LiteralString getStepName() const override { return "Remove orphaned DB entries"; } ScanStep getStep() const override { return ScanStep::RemoveOrphanedDbEntries; } + bool needProcess(const ScanContext& context) const override; void process(ScanContext& context) override; void removeOrphanedClusters(ScanContext& context); diff --git a/src/libs/services/scanner/impl/steps/ScanStepScanFiles.cpp b/src/libs/services/scanner/impl/steps/ScanStepScanFiles.cpp index cd4f3b97..7434c8b3 100644 --- a/src/libs/services/scanner/impl/steps/ScanStepScanFiles.cpp +++ b/src/libs/services/scanner/impl/steps/ScanStepScanFiles.cpp @@ -64,6 +64,12 @@ namespace lms::scanner LMS_LOG(DBUPDATER, INFO, "Using " << _fileScanQueue.getThreadCount() << " thread(s) for scanning file metadata"); } + bool ScanStepScanFiles::needProcess([[maybe_unused]] const ScanContext& context) const + { + // Always need to scan files + return true; + } + void ScanStepScanFiles::process(ScanContext& context) { context.currentStepStats.totalElems = context.stats.totalFileCount; diff --git a/src/libs/services/scanner/impl/steps/ScanStepScanFiles.hpp b/src/libs/services/scanner/impl/steps/ScanStepScanFiles.hpp index e15c54a2..8dc9bd70 100644 --- a/src/libs/services/scanner/impl/steps/ScanStepScanFiles.hpp +++ b/src/libs/services/scanner/impl/steps/ScanStepScanFiles.hpp @@ -38,6 +38,7 @@ namespace lms::scanner private: ScanStep getStep() const override { return ScanStep::ScanFiles; } core::LiteralString getStepName() const override { return "Scan files"; } + bool needProcess(const ScanContext& context) const override; void process(ScanContext& context) override; void process(ScanContext& context, const MediaLibraryInfo& mediaLibrary); void processFileScanResults(ScanContext& context, std::span> scanOperations); diff --git a/src/libs/services/scanner/impl/steps/ScanStepUpdateLibraryFields.cpp b/src/libs/services/scanner/impl/steps/ScanStepUpdateLibraryFields.cpp index d90a028e..35dcda97 100644 --- a/src/libs/services/scanner/impl/steps/ScanStepUpdateLibraryFields.cpp +++ b/src/libs/services/scanner/impl/steps/ScanStepUpdateLibraryFields.cpp @@ -29,6 +29,11 @@ namespace lms::scanner { + bool ScanStepUpdateLibraryFields::needProcess([[maybe_unused]] const ScanContext& context) const + { + // Fast enough when nothing to do + return true; + } void ScanStepUpdateLibraryFields::process(ScanContext& context) { diff --git a/src/libs/services/scanner/impl/steps/ScanStepUpdateLibraryFields.hpp b/src/libs/services/scanner/impl/steps/ScanStepUpdateLibraryFields.hpp index 5acb0f10..3740d539 100644 --- a/src/libs/services/scanner/impl/steps/ScanStepUpdateLibraryFields.hpp +++ b/src/libs/services/scanner/impl/steps/ScanStepUpdateLibraryFields.hpp @@ -33,6 +33,7 @@ namespace lms::scanner private: core::LiteralString getStepName() const override { return "Update Library fields"; } ScanStep getStep() const override { return ScanStep::UpdateLibraryFields; } + bool needProcess(const ScanContext& context) const override; void process(ScanContext& context) override; void processDirectories(ScanContext& context);