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.
Lidarr/src/NzbDrone.Core/Parser/ParsingService.cs

240 lines
7.7 KiB

using System.Collections.Generic;
using System.Linq;
using NLog;
using NzbDrone.Common.Extensions;
using NzbDrone.Core.IndexerSearch.Definitions;
using NzbDrone.Core.MediaFiles;
using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Music;
using System;
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
using System.IO;
namespace NzbDrone.Core.Parser
{
public interface IParsingService
{
Artist GetArtist(string title);
Artist GetArtistFromTag(string file);
RemoteAlbum Map(ParsedAlbumInfo parsedAlbumInfo, SearchCriteriaBase searchCriteria = null);
RemoteAlbum Map(ParsedAlbumInfo parsedAlbumInfo, int artistId, IEnumerable<int> albumIds);
List<Album> GetAlbums(ParsedAlbumInfo parsedAlbumInfo, Artist artist, SearchCriteriaBase searchCriteria = null);
// Music stuff here
Album GetLocalAlbum(string filename, Artist artist);
}
public class ParsingService : IParsingService
{
private readonly IArtistService _artistService;
private readonly IAlbumService _albumService;
private readonly ITrackService _trackService;
private readonly IMediaFileService _mediaFileService;
private readonly Logger _logger;
public ParsingService(ITrackService trackService,
IArtistService artistService,
IAlbumService albumService,
IMediaFileService mediaFileService,
Logger logger)
{
_albumService = albumService;
_artistService = artistService;
_trackService = trackService;
_mediaFileService = mediaFileService;
_logger = logger;
}
public Artist GetArtist(string title)
{
var parsedAlbumInfo = Parser.ParseAlbumTitle(title);
if (parsedAlbumInfo != null && !parsedAlbumInfo.ArtistName.IsNullOrWhiteSpace())
{
title = parsedAlbumInfo.ArtistName;
}
var artistInfo = _artistService.FindByName(title);
if (artistInfo == null)
{
_logger.Debug("Trying inexact artist match for {0}", title);
artistInfo = _artistService.FindByNameInexact(title);
}
return artistInfo;
}
public Artist GetArtistFromTag(string file)
{
var parsedTrackInfo = Parser.ParseMusicPath(file);
var artist = new Artist();
if (parsedTrackInfo.ArtistMBId.IsNotNullOrWhiteSpace())
{
artist = _artistService.FindById(parsedTrackInfo.ArtistMBId);
if (artist != null)
{
return artist;
}
}
if (parsedTrackInfo == null || parsedTrackInfo.ArtistTitle.IsNullOrWhiteSpace())
{
return null;
}
artist = _artistService.FindByName(parsedTrackInfo.ArtistTitle);
if (artist == null)
{
_logger.Debug("Trying inexact artist match for {0}", parsedTrackInfo.ArtistTitle);
artist = _artistService.FindByNameInexact(parsedTrackInfo.ArtistTitle);
}
return artist;
}
public RemoteAlbum Map(ParsedAlbumInfo parsedAlbumInfo, SearchCriteriaBase searchCriteria = null)
{
var remoteAlbum = new RemoteAlbum
{
ParsedAlbumInfo = parsedAlbumInfo,
};
var artist = GetArtist(parsedAlbumInfo, searchCriteria);
if (artist == null)
{
return remoteAlbum;
}
remoteAlbum.Artist = artist;
remoteAlbum.Albums = GetAlbums(parsedAlbumInfo, artist, searchCriteria);
return remoteAlbum;
}
public List<Album> GetAlbums(ParsedAlbumInfo parsedAlbumInfo, Artist artist, SearchCriteriaBase searchCriteria = null)
{
var albumTitle = parsedAlbumInfo.AlbumTitle;
var result = new List<Album>();
if (parsedAlbumInfo.AlbumTitle == null)
{
return new List<Album>();
}
Album albumInfo = null;
if (parsedAlbumInfo.Discography)
{
if (parsedAlbumInfo.DiscographyStart > 0)
{
return _albumService.ArtistAlbumsBetweenDates(artist,
new DateTime(parsedAlbumInfo.DiscographyStart, 1, 1),
new DateTime(parsedAlbumInfo.DiscographyEnd, 12, 31), false);
}
if (parsedAlbumInfo.DiscographyEnd > 0)
{
return _albumService.ArtistAlbumsBetweenDates(artist,
new DateTime(1800, 1, 1),
new DateTime(parsedAlbumInfo.DiscographyEnd, 12, 31), false);
}
return _albumService.GetAlbumsByArtist(artist.Id);
}
if (searchCriteria != null)
{
albumInfo = searchCriteria.Albums.ExclusiveOrDefault(e => e.Title == albumTitle);
}
if (albumInfo == null)
{
// TODO: Search by Title and Year instead of just Title when matching
albumInfo = _albumService.FindByTitle(artist.ArtistMetadataId, parsedAlbumInfo.AlbumTitle);
}
if (albumInfo == null)
{
_logger.Debug("Trying inexact album match for {0}", parsedAlbumInfo.AlbumTitle);
albumInfo = _albumService.FindByTitleInexact(artist.Id, parsedAlbumInfo.AlbumTitle);
}
if (albumInfo != null)
{
result.Add(albumInfo);
}
else
{
_logger.Debug("Unable to find {0}", parsedAlbumInfo);
}
return result;
}
public RemoteAlbum Map(ParsedAlbumInfo parsedAlbumInfo, int artistId, IEnumerable<int> albumIds)
{
return new RemoteAlbum
{
ParsedAlbumInfo = parsedAlbumInfo,
Artist = _artistService.GetArtist(artistId),
Albums = _albumService.GetAlbums(albumIds)
};
}
private Artist GetArtist(ParsedAlbumInfo parsedAlbumInfo, SearchCriteriaBase searchCriteria)
{
Artist artist = null;
if (searchCriteria != null)
{
if (searchCriteria.Artist.CleanName == parsedAlbumInfo.ArtistName.CleanArtistName())
{
return searchCriteria.Artist;
}
}
artist = _artistService.FindByName(parsedAlbumInfo.ArtistName);
if (artist == null)
{
_logger.Debug("Trying inexact artist match for {0}", parsedAlbumInfo.ArtistName);
artist = _artistService.FindByNameInexact(parsedAlbumInfo.ArtistName);
}
if (artist == null)
{
_logger.Debug("No matching artist {0}", parsedAlbumInfo.ArtistName);
return null;
}
return artist;
}
public Album GetLocalAlbum(string filename, Artist artist)
{
if (Path.HasExtension(filename))
{
filename = Path.GetDirectoryName(filename);
}
filename = artist.Path.GetRelativePath(filename);
var tracksInAlbum = _mediaFileService.GetFilesByArtist(artist.Id)
.FindAll(s => Path.GetDirectoryName(s.RelativePath) == filename)
.DistinctBy(s => s.AlbumId)
.ToList();
return tracksInAlbum.Count == 1 ? _albumService.GetAlbum(tracksInAlbum.First().AlbumId) : null;
}
}
}