Added an option to skip duplicated recording MBID. Fixes #180

This commit is contained in:
emeric
2022-02-02 13:31:23 +01:00
parent 71d6d4825f
commit 483cb1bdda
11 changed files with 46 additions and 19 deletions
+1 -1
View File
@@ -68,7 +68,7 @@
<message id="Lms.Admin.ScannerController.last-scan-status">Scanned {1} files in {2} on {3} ({4} errors, {5} duplicates)</message> <message id="Lms.Admin.ScannerController.last-scan-status">Scanned {1} files in {2} on {3} ({4} errors, {5} duplicates)</message>
<message id="Lms.Admin.ScannerController.no-audio-track">No audio track</message> <message id="Lms.Admin.ScannerController.no-audio-track">No audio track</message>
<message id="Lms.Admin.ScannerController.same-hash">Duplicated file hash</message> <message id="Lms.Admin.ScannerController.same-hash">Duplicated file hash</message>
<message id="Lms.Admin.ScannerController.same-mbid">Duplicated MBID</message> <message id="Lms.Admin.ScannerController.same-mbid">Duplicated recording MBID</message>
<message id="Lms.Admin.ScannerController.scan-now">Scan now</message> <message id="Lms.Admin.ScannerController.scan-now">Scan now</message>
<message id="Lms.Admin.ScannerController.scanner">Scanner</message> <message id="Lms.Admin.ScannerController.scanner">Scanner</message>
<message id="Lms.Admin.ScannerController.status">Status</message> <message id="Lms.Admin.ScannerController.status">Status</message>
+1 -1
View File
@@ -68,7 +68,7 @@
<message id="Lms.Admin.ScannerController.last-scan-status">{1} fichiers scannés en {2} le {3} ({4} erreurs, {5} duplicatas)</message> <message id="Lms.Admin.ScannerController.last-scan-status">{1} fichiers scannés en {2} le {3} ({4} erreurs, {5} duplicatas)</message>
<message id="Lms.Admin.ScannerController.no-audio-track">Pas de piste audio</message> <message id="Lms.Admin.ScannerController.no-audio-track">Pas de piste audio</message>
<message id="Lms.Admin.ScannerController.same-hash">Hash dupliqué</message> <message id="Lms.Admin.ScannerController.same-hash">Hash dupliqué</message>
<message id="Lms.Admin.ScannerController.same-mbid">MBID dupliqué</message> <message id="Lms.Admin.ScannerController.same-mbid">Recording MBID dupliqué</message>
<message id="Lms.Admin.ScannerController.scan-now">Lancer un scan</message> <message id="Lms.Admin.ScannerController.scan-now">Lancer un scan</message>
<message id="Lms.Admin.ScannerController.scanner">Scanner</message> <message id="Lms.Admin.ScannerController.scanner">Scanner</message>
<message id="Lms.Admin.ScannerController.status">Statut</message> <message id="Lms.Admin.ScannerController.status">Statut</message>
+1 -1
View File
@@ -67,7 +67,7 @@
<message id="Lms.Admin.ScannerController.last-scan-status">Scansionati {1} files in {2} su {3} ({4} errori, {5} duplicati)</message> <message id="Lms.Admin.ScannerController.last-scan-status">Scansionati {1} files in {2} su {3} ({4} errori, {5} duplicati)</message>
<message id="Lms.Admin.ScannerController.no-audio-track">Nessuna traccia audio</message> <message id="Lms.Admin.ScannerController.no-audio-track">Nessuna traccia audio</message>
<message id="Lms.Admin.ScannerController.same-hash">Hash doppio</message> <message id="Lms.Admin.ScannerController.same-hash">Hash doppio</message>
<message id="Lms.Admin.ScannerController.same-mbid">MBID doppio</message> <message id="Lms.Admin.ScannerController.same-mbid">Recording MBID doppio</message>
<message id="Lms.Admin.ScannerController.scan-now">Scansiona ora</message> <message id="Lms.Admin.ScannerController.scan-now">Scansiona ora</message>
<message id="Lms.Admin.ScannerController.scanner">Scanner</message> <message id="Lms.Admin.ScannerController.scanner">Scanner</message>
<message id="Lms.Admin.ScannerController.status">Stato</message> <message id="Lms.Admin.ScannerController.status">Stato</message>
+1 -1
View File
@@ -68,7 +68,7 @@
<message id="Lms.Admin.ScannerController.last-scan-status">已扫描 {1} 文件 在 {2} 和 {3} ({4} 错误, {5} 副本)</message> <message id="Lms.Admin.ScannerController.last-scan-status">已扫描 {1} 文件 在 {2} 和 {3} ({4} 错误, {5} 副本)</message>
<message id="Lms.Admin.ScannerController.no-audio-track">没有音轨</message> <message id="Lms.Admin.ScannerController.no-audio-track">没有音轨</message>
<message id="Lms.Admin.ScannerController.same-hash">复制文件哈希值</message> <message id="Lms.Admin.ScannerController.same-hash">复制文件哈希值</message>
<message id="Lms.Admin.ScannerController.same-mbid">复制 MBID</message> <message id="Lms.Admin.ScannerController.same-mbid">复制 Recording MBID</message>
<message id="Lms.Admin.ScannerController.scan-now">立即扫描</message> <message id="Lms.Admin.ScannerController.scan-now">立即扫描</message>
<message id="Lms.Admin.ScannerController.scanner">扫描器</message> <message id="Lms.Admin.ScannerController.scanner">扫描器</message>
<message id="Lms.Admin.ScannerController.status">状态</message> <message id="Lms.Admin.ScannerController.status">状态</message>
+3
View File
@@ -70,3 +70,6 @@ cover-max-cache-size = 30;
# JPEG quality for covers (range is 1-100) # JPEG quality for covers (range is 1-100)
cover-jpeg-quality = 75; cover-jpeg-quality = 75;
# Set to true if you want to hide duplicate tracks
scanner-skip-duplicate-recording-mbid = false;
+3 -3
View File
@@ -186,12 +186,12 @@ Track::findPaths(Session& session, Range range)
} }
RangeResults<TrackId> RangeResults<TrackId>
Track::findMBIDDuplicates(Session& session, Range range) Track::findRecordingMBIDDuplicates(Session& session, Range range)
{ {
session.checkSharedLocked(); session.checkSharedLocked();
auto query {session.getDboSession().query<TrackId>( "SELECT track.id FROM track WHERE mbid in (SELECT mbid FROM track WHERE mbid <> '' GROUP BY mbid HAVING COUNT (*) > 1)") auto query {session.getDboSession().query<TrackId>( "SELECT track.id FROM track WHERE recording_mbid in (SELECT recording_mbid FROM track WHERE recording_mbid <> '' GROUP BY recording_mbid HAVING COUNT (*) > 1)")
.orderBy("track.release_id,track.disc_number,track.track_number,track.mbid")}; .orderBy("track.release_id,track.disc_number,track.track_number,track.recording_mbid")};
return execQuery(query, range); return execQuery(query, range);
} }
@@ -92,7 +92,7 @@ class Track : public Object<Track, TrackId>
static RangeResults<TrackId> find(Session& session, const FindParameters& parameters); static RangeResults<TrackId> find(Session& session, const FindParameters& parameters);
static RangeResults<TrackId> findByNameAndReleaseName(Session& session, std::string_view trackName, std::string_view releaseName); static RangeResults<TrackId> findByNameAndReleaseName(Session& session, std::string_view trackName, std::string_view releaseName);
static RangeResults<PathResult> findPaths(Session& session, Range range); static RangeResults<PathResult> findPaths(Session& session, Range range);
static RangeResults<TrackId> findMBIDDuplicates(Session& session, Range range); static RangeResults<TrackId> findRecordingMBIDDuplicates(Session& session, Range range);
static RangeResults<TrackId> findWithRecordingMBIDAndMissingFeatures(Session& session, Range range); static RangeResults<TrackId> findWithRecordingMBIDAndMissingFeatures(Session& session, Range range);
// Create utility // Create utility
@@ -34,6 +34,7 @@
#include "metadata/TagLibParser.hpp" #include "metadata/TagLibParser.hpp"
#include "services/recommendation/IRecommendationService.hpp" #include "services/recommendation/IRecommendationService.hpp"
#include "utils/Exception.hpp" #include "utils/Exception.hpp"
#include "utils/IConfig.hpp"
#include "utils/Logger.hpp" #include "utils/Logger.hpp"
#include "utils/Path.hpp" #include "utils/Path.hpp"
#include "utils/UUID.hpp" #include "utils/UUID.hpp"
@@ -256,8 +257,11 @@ createScannerService(Db& db, Recommendation::IRecommendationService& recommendat
ScannerService::ScannerService(Db& db, Recommendation::IRecommendationService& recommendationService) ScannerService::ScannerService(Db& db, Recommendation::IRecommendationService& recommendationService)
: _recommendationService {recommendationService} : _recommendationService {recommendationService}
, _skipDuplicateRecordingMBID {Service<IConfig>::get()->getBool("scanner-skip-duplicate-recording-mbid", false)}
, _dbSession {db} , _dbSession {db}
{ {
LMS_LOG(DBUPDATER, INFO) << "skipDuplicateRecordingMBID = " << _skipDuplicateRecordingMBID;
// For now, always use TagLib // For now, always use TagLib
_metadataParser = std::make_unique<MetaData::TagLibParser>(); _metadataParser = std::make_unique<MetaData::TagLibParser>();
@@ -719,6 +723,25 @@ ScannerService::scanAudioFile(const std::filesystem::path& file, bool forceScan,
Track::pointer track {Track::findByPath(_dbSession, file) }; Track::pointer track {Track::findByPath(_dbSession, file) };
// Skip duplicate recording MBID
if (trackInfo->recordingMBID && _skipDuplicateRecordingMBID)
{
for (Track::pointer otherTrack : Track::findByRecordingMBID(_dbSession, *trackInfo->recordingMBID))
{
if (track && track->getId() == otherTrack->getId())
continue;
LMS_LOG(DBUPDATER, DEBUG) << "Skipped '" << file.string() << "' (similar recording MBID in '" << otherTrack->getPath().string() << "')";
// This recording MBID already exists, just remove what we just scanned
if (track)
{
track.remove();
stats.deletions++;
}
return;
}
}
// We estimate this is an audio file if: // We estimate this is an audio file if:
// - we found a least one audio stream // - we found a least one audio stream
// - the duration is not null // - the duration is not null
@@ -1026,14 +1049,14 @@ ScannerService::checkDuplicatedAudioFiles(ScanStats& stats)
auto transaction {_dbSession.createSharedTransaction()}; auto transaction {_dbSession.createSharedTransaction()};
const RangeResults<TrackId> tracks = Track::findMBIDDuplicates(_dbSession, Range {}); const RangeResults<TrackId> tracks = Track::findRecordingMBIDDuplicates(_dbSession, Range {});
for (const TrackId trackId : tracks.results) for (const TrackId trackId : tracks.results)
{ {
const Track::pointer track {Track::find(_dbSession, trackId)}; const Track::pointer track {Track::find(_dbSession, trackId)};
if (auto trackMBID {track->getTrackMBID()}) if (auto recordingMBID {track->getRecordingMBID()})
{ {
LMS_LOG(DBUPDATER, INFO) << "Found duplicated Track MBID [" << trackMBID->getAsString() << "], file: " << track->getPath().string() << " - " << track->getName(); LMS_LOG(DBUPDATER, INFO) << "Found duplicated recording MBID [" << recordingMBID->getAsString() << "], file: " << track->getPath().string() << " - " << track->getName();
stats.duplicates.emplace_back(ScanDuplicate {track->getId(), DuplicateReason::SameMBID}); stats.duplicates.emplace_back(ScanDuplicate {track->getId(), DuplicateReason::SameRecordingMBID});
} }
} }
@@ -98,6 +98,7 @@ namespace Scanner
std::atomic<bool> _abortScan {}; std::atomic<bool> _abortScan {};
Wt::WIOService _ioService; Wt::WIOService _ioService;
boost::asio::system_timer _scheduleTimer {_ioService}; boost::asio::system_timer _scheduleTimer {_ioService};
const bool _skipDuplicateRecordingMBID {};
Events _events; Events _events;
std::chrono::system_clock::time_point _lastScanInProgressEmit {}; std::chrono::system_clock::time_point _lastScanInProgressEmit {};
Database::Session _dbSession; Database::Session _dbSession;
@@ -39,7 +39,7 @@ namespace Scanner
enum class DuplicateReason enum class DuplicateReason
{ {
SameHash, SameHash,
SameMBID, SameRecordingMBID,
}; };
struct ScanError struct ScanError
+2 -2
View File
@@ -96,7 +96,7 @@ class ReportResource : public Wt::WResource
response.out() << track->getPath().string(); response.out() << track->getPath().string();
if (auto mbid {track->getTrackMBID()}) if (auto mbid {track->getTrackMBID()})
response.out() << " (Track MBID " << mbid->getAsString() << ")"; response.out() << " (Recording MBID " << mbid->getAsString() << ")";
response.out() << " - " << duplicateReasonToWString(duplicate.reason).toUTF8() << '\n'; response.out() << " - " << duplicateReasonToWString(duplicate.reason).toUTF8() << '\n';
} }
@@ -122,7 +122,7 @@ class ReportResource : public Wt::WResource
switch (reason) switch (reason)
{ {
case Scanner::DuplicateReason::SameHash: return Wt::WString::tr("Lms.Admin.ScannerController.same-hash"); case Scanner::DuplicateReason::SameHash: return Wt::WString::tr("Lms.Admin.ScannerController.same-hash");
case Scanner::DuplicateReason::SameMBID: return Wt::WString::tr("Lms.Admin.ScannerController.same-mbid"); case Scanner::DuplicateReason::SameRecordingMBID: return Wt::WString::tr("Lms.Admin.ScannerController.same-mbid");
} }
return "?"; return "?";
} }