You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Readarr/src/NzbDrone.Core/MediaFiles/MediaFileService.cs

245 lines
8.3 KiB

using System;
using System.Collections.Generic;
using System.IO.Abstractions;
using System.Linq;
using NLog;
using NzbDrone.Common;
using NzbDrone.Core.Books.Events;
using NzbDrone.Core.Datastore.Events;
using NzbDrone.Core.MediaFiles.Events;
using NzbDrone.Core.Messaging.Events;
using NzbDrone.Core.RootFolders;
namespace NzbDrone.Core.MediaFiles
{
public interface IMediaFileService
{
BookFile Add(BookFile bookFile);
void AddMany(List<BookFile> bookFiles);
void Update(BookFile bookFile);
void Update(List<BookFile> bookFiles);
void Delete(BookFile bookFile, DeleteMediaFileReason reason);
void DeleteMany(List<BookFile> bookFiles, DeleteMediaFileReason reason);
List<BookFile> GetFilesByAuthor(int authorId);
List<BookFile> GetFilesByAuthorMetadataId(int authorMetadataId);
List<BookFile> GetFilesByBook(int bookId);
List<BookFile> GetFilesByEdition(int editionId);
4 years ago
List<BookFile> GetUnmappedFiles();
List<IFileInfo> FilterUnchangedFiles(List<IFileInfo> files, FilterFilesType filter);
4 years ago
BookFile Get(int id);
List<BookFile> Get(IEnumerable<int> ids);
List<BookFile> GetFilesWithBasePath(string path);
List<BookFile> GetFileWithPath(List<string> path);
BookFile GetFileWithPath(string path);
void UpdateMediaInfo(List<BookFile> bookFiles);
}
public class MediaFileService : IMediaFileService,
IHandle<AuthorMovedEvent>,
IHandleAsync<BookDeletedEvent>,
IHandleAsync<ModelEvent<RootFolder>>
{
private readonly IEventAggregator _eventAggregator;
private readonly IMediaFileRepository _mediaFileRepository;
private readonly Logger _logger;
public MediaFileService(IMediaFileRepository mediaFileRepository, IEventAggregator eventAggregator, Logger logger)
{
_mediaFileRepository = mediaFileRepository;
_eventAggregator = eventAggregator;
_logger = logger;
}
public BookFile Add(BookFile bookFile)
{
var addedFile = _mediaFileRepository.Insert(bookFile);
_eventAggregator.PublishEvent(new BookFileAddedEvent(addedFile));
return addedFile;
}
public void AddMany(List<BookFile> bookFiles)
Whole album matching and fingerprinting (#592) * Cache result of GetAllArtists * Fixed: Manual import not respecting album import notifications * Fixed: partial album imports stay in queue, prompting manual import * Fixed: Allow release if tracks are missing * Fixed: Be tolerant of missing/extra "The" at start of artist name * Improve manual import UI * Omit video tracks from DB entirely * Revert "faster test packaging in build.sh" This reverts commit 2723e2a7b86bcbff9051fd2aced07dd807b4bcb7. -u and -T are not supported on macOS * Fix tests on linux and macOS * Actually lint on linux On linux yarn runs scripts with sh not bash so ** doesn't recursively glob * Match whole albums * Option to disable fingerprinting * Rip out MediaInfo * Don't split up things that have the same album selected in manual import * Try to speed up IndentificationService * More speedups * Some fixes and increase power of recording id * Fix NRE when no tags * Fix NRE when some (but not all) files in a directory have missing tags * Bump taglib, tidy up tag parsing * Add a health check * Remove media info setting * Tags -> audioTags * Add some tests where tags are null * Rename history events * Add missing method to interface * Reinstate MediaInfo tags and update info with artist scan Also adds migration to remove old format media info * This file no longer exists * Don't penalise year if missing from tags * Formatting improvements * Use correct system newline * Switch to the netstandard2.0 library to support net 461 * TagLib.File is IDisposable so should be in a using * Improve filename matching and add tests * Neater logging of parsed tags * Fix disk scan tests for new media info update * Fix quality detection source * Fix Inexact Artist/Album match * Add button to clear track mapping * Fix warning * Pacify eslint * Use \ not / * Fix UI updates * Fix media covers Prevent localizing URL propaging back to the metadata object * Reduce database overhead broadcasting UI updates * Relax timings a bit to make test pass * Remove irrelevant tests * Test framework for identification service * Fix PreferMissingToBadMatch test case * Make fingerprinting more robust * More logging * Penalize unknown media format and country * Prefer USA to UK * Allow Data CD * Fix exception if fingerprinting fails for all files * Fix tests * Fix NRE * Allow apostrophes and remove accents in filename aggregation * Address codacy issues * Cope with old versions of fpcalc and suggest upgrade * fpcalc health check passes if fingerprinting disabled * Get the Artist meta with the artist * Fix the mapper so that lazy loaded lists will be populated on Join And therefore we can join TrackFiles on Tracks by default and avoid an extra query * Rename subtitle -> lyric * Tidy up MediaInfoFormatter
6 years ago
{
_mediaFileRepository.InsertMany(bookFiles);
foreach (var addedFile in bookFiles)
Whole album matching and fingerprinting (#592) * Cache result of GetAllArtists * Fixed: Manual import not respecting album import notifications * Fixed: partial album imports stay in queue, prompting manual import * Fixed: Allow release if tracks are missing * Fixed: Be tolerant of missing/extra "The" at start of artist name * Improve manual import UI * Omit video tracks from DB entirely * Revert "faster test packaging in build.sh" This reverts commit 2723e2a7b86bcbff9051fd2aced07dd807b4bcb7. -u and -T are not supported on macOS * Fix tests on linux and macOS * Actually lint on linux On linux yarn runs scripts with sh not bash so ** doesn't recursively glob * Match whole albums * Option to disable fingerprinting * Rip out MediaInfo * Don't split up things that have the same album selected in manual import * Try to speed up IndentificationService * More speedups * Some fixes and increase power of recording id * Fix NRE when no tags * Fix NRE when some (but not all) files in a directory have missing tags * Bump taglib, tidy up tag parsing * Add a health check * Remove media info setting * Tags -> audioTags * Add some tests where tags are null * Rename history events * Add missing method to interface * Reinstate MediaInfo tags and update info with artist scan Also adds migration to remove old format media info * This file no longer exists * Don't penalise year if missing from tags * Formatting improvements * Use correct system newline * Switch to the netstandard2.0 library to support net 461 * TagLib.File is IDisposable so should be in a using * Improve filename matching and add tests * Neater logging of parsed tags * Fix disk scan tests for new media info update * Fix quality detection source * Fix Inexact Artist/Album match * Add button to clear track mapping * Fix warning * Pacify eslint * Use \ not / * Fix UI updates * Fix media covers Prevent localizing URL propaging back to the metadata object * Reduce database overhead broadcasting UI updates * Relax timings a bit to make test pass * Remove irrelevant tests * Test framework for identification service * Fix PreferMissingToBadMatch test case * Make fingerprinting more robust * More logging * Penalize unknown media format and country * Prefer USA to UK * Allow Data CD * Fix exception if fingerprinting fails for all files * Fix tests * Fix NRE * Allow apostrophes and remove accents in filename aggregation * Address codacy issues * Cope with old versions of fpcalc and suggest upgrade * fpcalc health check passes if fingerprinting disabled * Get the Artist meta with the artist * Fix the mapper so that lazy loaded lists will be populated on Join And therefore we can join TrackFiles on Tracks by default and avoid an extra query * Rename subtitle -> lyric * Tidy up MediaInfoFormatter
6 years ago
{
_eventAggregator.PublishEvent(new BookFileAddedEvent(addedFile));
Whole album matching and fingerprinting (#592) * Cache result of GetAllArtists * Fixed: Manual import not respecting album import notifications * Fixed: partial album imports stay in queue, prompting manual import * Fixed: Allow release if tracks are missing * Fixed: Be tolerant of missing/extra "The" at start of artist name * Improve manual import UI * Omit video tracks from DB entirely * Revert "faster test packaging in build.sh" This reverts commit 2723e2a7b86bcbff9051fd2aced07dd807b4bcb7. -u and -T are not supported on macOS * Fix tests on linux and macOS * Actually lint on linux On linux yarn runs scripts with sh not bash so ** doesn't recursively glob * Match whole albums * Option to disable fingerprinting * Rip out MediaInfo * Don't split up things that have the same album selected in manual import * Try to speed up IndentificationService * More speedups * Some fixes and increase power of recording id * Fix NRE when no tags * Fix NRE when some (but not all) files in a directory have missing tags * Bump taglib, tidy up tag parsing * Add a health check * Remove media info setting * Tags -> audioTags * Add some tests where tags are null * Rename history events * Add missing method to interface * Reinstate MediaInfo tags and update info with artist scan Also adds migration to remove old format media info * This file no longer exists * Don't penalise year if missing from tags * Formatting improvements * Use correct system newline * Switch to the netstandard2.0 library to support net 461 * TagLib.File is IDisposable so should be in a using * Improve filename matching and add tests * Neater logging of parsed tags * Fix disk scan tests for new media info update * Fix quality detection source * Fix Inexact Artist/Album match * Add button to clear track mapping * Fix warning * Pacify eslint * Use \ not / * Fix UI updates * Fix media covers Prevent localizing URL propaging back to the metadata object * Reduce database overhead broadcasting UI updates * Relax timings a bit to make test pass * Remove irrelevant tests * Test framework for identification service * Fix PreferMissingToBadMatch test case * Make fingerprinting more robust * More logging * Penalize unknown media format and country * Prefer USA to UK * Allow Data CD * Fix exception if fingerprinting fails for all files * Fix tests * Fix NRE * Allow apostrophes and remove accents in filename aggregation * Address codacy issues * Cope with old versions of fpcalc and suggest upgrade * fpcalc health check passes if fingerprinting disabled * Get the Artist meta with the artist * Fix the mapper so that lazy loaded lists will be populated on Join And therefore we can join TrackFiles on Tracks by default and avoid an extra query * Rename subtitle -> lyric * Tidy up MediaInfoFormatter
6 years ago
}
}
public void Update(BookFile bookFile)
{
_mediaFileRepository.Update(bookFile);
}
public void Update(List<BookFile> bookFiles)
{
_mediaFileRepository.UpdateMany(bookFiles);
}
public void Delete(BookFile bookFile, DeleteMediaFileReason reason)
{
_mediaFileRepository.Delete(bookFile);
// If the trackfile wasn't mapped to a track, don't publish an event
if (bookFile.EditionId > 0)
{
_eventAggregator.PublishEvent(new BookFileDeletedEvent(bookFile, reason));
}
}
public void DeleteMany(List<BookFile> bookFiles, DeleteMediaFileReason reason)
{
_mediaFileRepository.DeleteMany(bookFiles);
// publish events where trackfile was mapped to a track
foreach (var bookFile in bookFiles.Where(x => x.EditionId > 0))
{
_eventAggregator.PublishEvent(new BookFileDeletedEvent(bookFile, reason));
}
}
public List<IFileInfo> FilterUnchangedFiles(List<IFileInfo> files, FilterFilesType filter)
{
if (filter == FilterFilesType.None)
{
return files;
}
_logger.Debug($"Filtering {files.Count} files for unchanged files");
var knownFiles = GetFileWithPath(files.Select(x => x.FullName).ToList());
_logger.Trace($"Got {knownFiles.Count} existing files");
if (!knownFiles.Any())
{
return files;
}
var combined = files
.Join(knownFiles,
f => f.FullName,
af => af.Path,
(f, af) => new { DiskFile = f, DbFile = af },
PathEqualityComparer.Instance)
.ToList();
_logger.Trace($"Matched paths for {combined.Count} files");
List<IFileInfo> unwanted = null;
if (filter == FilterFilesType.Known)
{
unwanted = combined
.Where(x => x.DiskFile.Length == x.DbFile.Size &&
Math.Abs((x.DiskFile.LastWriteTimeUtc - x.DbFile.Modified.ToUniversalTime()).TotalSeconds) <= 1)
.Select(x => x.DiskFile)
.ToList();
_logger.Trace($"{unwanted.Count} unchanged existing files");
}
else if (filter == FilterFilesType.Matched)
{
unwanted = combined
.Where(x => x.DiskFile.Length == x.DbFile.Size &&
Math.Abs((x.DiskFile.LastWriteTimeUtc - x.DbFile.Modified.ToUniversalTime()).TotalSeconds) <= 1 &&
(x.DbFile.Edition == null || (x.DbFile.Edition.IsLoaded && x.DbFile.Edition.Value != null)))
.Select(x => x.DiskFile)
.ToList();
_logger.Trace($"{unwanted.Count} unchanged and matched files");
}
else
{
throw new ArgumentException("Unrecognised value of FilterFilesType filter");
}
return files.Except(unwanted).ToList();
}
4 years ago
public BookFile Get(int id)
{
return _mediaFileRepository.Get(id);
}
4 years ago
public List<BookFile> Get(IEnumerable<int> ids)
{
return _mediaFileRepository.Get(ids).ToList();
}
4 years ago
public List<BookFile> GetFilesWithBasePath(string path)
{
return _mediaFileRepository.GetFilesWithBasePath(path);
}
4 years ago
public List<BookFile> GetFileWithPath(List<string> path)
{
return _mediaFileRepository.GetFileWithPath(path);
}
4 years ago
public BookFile GetFileWithPath(string path)
{
return _mediaFileRepository.GetFileWithPath(path);
}
public List<BookFile> GetFilesByAuthor(int authorId)
{
return _mediaFileRepository.GetFilesByAuthor(authorId);
}
public List<BookFile> GetFilesByAuthorMetadataId(int authorMetadataId)
{
return _mediaFileRepository.GetFilesByAuthorMetadataId(authorMetadataId);
}
public List<BookFile> GetFilesByBook(int bookId)
{
return _mediaFileRepository.GetFilesByBook(bookId);
}
Whole album matching and fingerprinting (#592) * Cache result of GetAllArtists * Fixed: Manual import not respecting album import notifications * Fixed: partial album imports stay in queue, prompting manual import * Fixed: Allow release if tracks are missing * Fixed: Be tolerant of missing/extra "The" at start of artist name * Improve manual import UI * Omit video tracks from DB entirely * Revert "faster test packaging in build.sh" This reverts commit 2723e2a7b86bcbff9051fd2aced07dd807b4bcb7. -u and -T are not supported on macOS * Fix tests on linux and macOS * Actually lint on linux On linux yarn runs scripts with sh not bash so ** doesn't recursively glob * Match whole albums * Option to disable fingerprinting * Rip out MediaInfo * Don't split up things that have the same album selected in manual import * Try to speed up IndentificationService * More speedups * Some fixes and increase power of recording id * Fix NRE when no tags * Fix NRE when some (but not all) files in a directory have missing tags * Bump taglib, tidy up tag parsing * Add a health check * Remove media info setting * Tags -> audioTags * Add some tests where tags are null * Rename history events * Add missing method to interface * Reinstate MediaInfo tags and update info with artist scan Also adds migration to remove old format media info * This file no longer exists * Don't penalise year if missing from tags * Formatting improvements * Use correct system newline * Switch to the netstandard2.0 library to support net 461 * TagLib.File is IDisposable so should be in a using * Improve filename matching and add tests * Neater logging of parsed tags * Fix disk scan tests for new media info update * Fix quality detection source * Fix Inexact Artist/Album match * Add button to clear track mapping * Fix warning * Pacify eslint * Use \ not / * Fix UI updates * Fix media covers Prevent localizing URL propaging back to the metadata object * Reduce database overhead broadcasting UI updates * Relax timings a bit to make test pass * Remove irrelevant tests * Test framework for identification service * Fix PreferMissingToBadMatch test case * Make fingerprinting more robust * More logging * Penalize unknown media format and country * Prefer USA to UK * Allow Data CD * Fix exception if fingerprinting fails for all files * Fix tests * Fix NRE * Allow apostrophes and remove accents in filename aggregation * Address codacy issues * Cope with old versions of fpcalc and suggest upgrade * fpcalc health check passes if fingerprinting disabled * Get the Artist meta with the artist * Fix the mapper so that lazy loaded lists will be populated on Join And therefore we can join TrackFiles on Tracks by default and avoid an extra query * Rename subtitle -> lyric * Tidy up MediaInfoFormatter
6 years ago
public List<BookFile> GetFilesByEdition(int editionId)
{
return _mediaFileRepository.GetFilesByEdition(editionId);
}
4 years ago
public List<BookFile> GetUnmappedFiles()
{
return _mediaFileRepository.GetUnmappedFiles();
}
public void UpdateMediaInfo(List<BookFile> bookFiles)
Whole album matching and fingerprinting (#592) * Cache result of GetAllArtists * Fixed: Manual import not respecting album import notifications * Fixed: partial album imports stay in queue, prompting manual import * Fixed: Allow release if tracks are missing * Fixed: Be tolerant of missing/extra "The" at start of artist name * Improve manual import UI * Omit video tracks from DB entirely * Revert "faster test packaging in build.sh" This reverts commit 2723e2a7b86bcbff9051fd2aced07dd807b4bcb7. -u and -T are not supported on macOS * Fix tests on linux and macOS * Actually lint on linux On linux yarn runs scripts with sh not bash so ** doesn't recursively glob * Match whole albums * Option to disable fingerprinting * Rip out MediaInfo * Don't split up things that have the same album selected in manual import * Try to speed up IndentificationService * More speedups * Some fixes and increase power of recording id * Fix NRE when no tags * Fix NRE when some (but not all) files in a directory have missing tags * Bump taglib, tidy up tag parsing * Add a health check * Remove media info setting * Tags -> audioTags * Add some tests where tags are null * Rename history events * Add missing method to interface * Reinstate MediaInfo tags and update info with artist scan Also adds migration to remove old format media info * This file no longer exists * Don't penalise year if missing from tags * Formatting improvements * Use correct system newline * Switch to the netstandard2.0 library to support net 461 * TagLib.File is IDisposable so should be in a using * Improve filename matching and add tests * Neater logging of parsed tags * Fix disk scan tests for new media info update * Fix quality detection source * Fix Inexact Artist/Album match * Add button to clear track mapping * Fix warning * Pacify eslint * Use \ not / * Fix UI updates * Fix media covers Prevent localizing URL propaging back to the metadata object * Reduce database overhead broadcasting UI updates * Relax timings a bit to make test pass * Remove irrelevant tests * Test framework for identification service * Fix PreferMissingToBadMatch test case * Make fingerprinting more robust * More logging * Penalize unknown media format and country * Prefer USA to UK * Allow Data CD * Fix exception if fingerprinting fails for all files * Fix tests * Fix NRE * Allow apostrophes and remove accents in filename aggregation * Address codacy issues * Cope with old versions of fpcalc and suggest upgrade * fpcalc health check passes if fingerprinting disabled * Get the Artist meta with the artist * Fix the mapper so that lazy loaded lists will be populated on Join And therefore we can join TrackFiles on Tracks by default and avoid an extra query * Rename subtitle -> lyric * Tidy up MediaInfoFormatter
6 years ago
{
_mediaFileRepository.SetFields(bookFiles, t => t.MediaInfo);
Whole album matching and fingerprinting (#592) * Cache result of GetAllArtists * Fixed: Manual import not respecting album import notifications * Fixed: partial album imports stay in queue, prompting manual import * Fixed: Allow release if tracks are missing * Fixed: Be tolerant of missing/extra "The" at start of artist name * Improve manual import UI * Omit video tracks from DB entirely * Revert "faster test packaging in build.sh" This reverts commit 2723e2a7b86bcbff9051fd2aced07dd807b4bcb7. -u and -T are not supported on macOS * Fix tests on linux and macOS * Actually lint on linux On linux yarn runs scripts with sh not bash so ** doesn't recursively glob * Match whole albums * Option to disable fingerprinting * Rip out MediaInfo * Don't split up things that have the same album selected in manual import * Try to speed up IndentificationService * More speedups * Some fixes and increase power of recording id * Fix NRE when no tags * Fix NRE when some (but not all) files in a directory have missing tags * Bump taglib, tidy up tag parsing * Add a health check * Remove media info setting * Tags -> audioTags * Add some tests where tags are null * Rename history events * Add missing method to interface * Reinstate MediaInfo tags and update info with artist scan Also adds migration to remove old format media info * This file no longer exists * Don't penalise year if missing from tags * Formatting improvements * Use correct system newline * Switch to the netstandard2.0 library to support net 461 * TagLib.File is IDisposable so should be in a using * Improve filename matching and add tests * Neater logging of parsed tags * Fix disk scan tests for new media info update * Fix quality detection source * Fix Inexact Artist/Album match * Add button to clear track mapping * Fix warning * Pacify eslint * Use \ not / * Fix UI updates * Fix media covers Prevent localizing URL propaging back to the metadata object * Reduce database overhead broadcasting UI updates * Relax timings a bit to make test pass * Remove irrelevant tests * Test framework for identification service * Fix PreferMissingToBadMatch test case * Make fingerprinting more robust * More logging * Penalize unknown media format and country * Prefer USA to UK * Allow Data CD * Fix exception if fingerprinting fails for all files * Fix tests * Fix NRE * Allow apostrophes and remove accents in filename aggregation * Address codacy issues * Cope with old versions of fpcalc and suggest upgrade * fpcalc health check passes if fingerprinting disabled * Get the Artist meta with the artist * Fix the mapper so that lazy loaded lists will be populated on Join And therefore we can join TrackFiles on Tracks by default and avoid an extra query * Rename subtitle -> lyric * Tidy up MediaInfoFormatter
6 years ago
}
public void Handle(AuthorMovedEvent message)
{
var files = _mediaFileRepository.GetFilesWithBasePath(message.SourcePath);
foreach (var file in files)
{
var newPath = message.DestinationPath + file.Path.Substring(message.SourcePath.Length);
file.Path = newPath;
}
Update(files);
}
public void HandleAsync(BookDeletedEvent message)
{
if (message.DeleteFiles)
{
_mediaFileRepository.DeleteFilesByBook(message.Book.Id);
}
else
{
_mediaFileRepository.UnlinkFilesByBook(message.Book.Id);
}
}
public void HandleAsync(ModelEvent<RootFolder> message)
{
if (message.Action == ModelAction.Deleted)
{
var files = GetFilesWithBasePath(message.Model.Path);
DeleteMany(files, DeleteMediaFileReason.Manual);
}
}
}
}