2018-12-15 22:35:20 +00:00
using Microsoft.EntityFrameworkCore ;
using Microsoft.Extensions.Logging ;
using Roadie.Library.Caching ;
using Roadie.Library.Configuration ;
using Roadie.Library.Data ;
using Roadie.Library.Encoding ;
using Roadie.Library.Enums ;
using Roadie.Library.Extensions ;
using Roadie.Library.Imaging ;
using Roadie.Library.MetaData.Audio ;
2019-06-03 13:37:13 +00:00
using Roadie.Library.MetaData.ID3Tags ;
2018-12-15 22:35:20 +00:00
using Roadie.Library.SearchEngines.Imaging ;
using Roadie.Library.SearchEngines.MetaData ;
using Roadie.Library.Utility ;
using System ;
using System.Collections.Concurrent ;
using System.Collections.Generic ;
using System.Diagnostics ;
using System.IO ;
using System.Linq ;
using System.Threading.Tasks ;
using discogs = Roadie . Library . SearchEngines . MetaData . Discogs ;
using lastfm = Roadie . Library . MetaData . LastFm ;
using musicbrainz = Roadie . Library . MetaData . MusicBrainz ;
using spotify = Roadie . Library . SearchEngines . MetaData . Spotify ;
using wikipedia = Roadie . Library . SearchEngines . MetaData . Wikipedia ;
namespace Roadie.Library.Engines
{
public class ReleaseLookupEngine : LookupEngineBase , IReleaseLookupEngine
{
2018-12-15 23:22:02 +00:00
public List < int > _addedReleaseIds = new List < int > ( ) ;
public List < int > _addedTrackIds = new List < int > ( ) ;
2019-07-03 16:21:29 +00:00
public IEnumerable < int > AddedReleaseIds = > _addedReleaseIds ;
2018-12-15 23:22:02 +00:00
2019-07-03 16:21:29 +00:00
public IEnumerable < int > AddedTrackIds = > _addedTrackIds ;
2018-12-15 22:35:20 +00:00
public IReleaseSearchEngine DiscogsReleaseSearchEngine { get ; }
2019-07-03 16:21:29 +00:00
2018-12-15 22:35:20 +00:00
public IReleaseSearchEngine ITunesReleaseSearchEngine { get ; }
2019-07-03 16:21:29 +00:00
2018-12-15 22:35:20 +00:00
public IReleaseSearchEngine LastFmReleaseSearchEngine { get ; }
2019-07-03 16:21:29 +00:00
public IReleaseSearchEngine MusicBrainzReleaseSearchEngine { get ; }
2018-12-15 22:35:20 +00:00
2019-07-03 16:21:29 +00:00
public IReleaseSearchEngine SpotifyReleaseSearchEngine { get ; }
2019-02-25 02:26:54 +00:00
2019-07-03 16:21:29 +00:00
public IReleaseSearchEngine WikipediaReleaseSearchEngine { get ; }
2019-02-25 02:26:54 +00:00
2019-07-03 16:21:29 +00:00
private IArtistLookupEngine ArtistLookupEngine { get ; }
2019-01-27 22:49:55 +00:00
2019-07-03 16:21:29 +00:00
private ILabelLookupEngine LabelLookupEngine { get ; }
public ReleaseLookupEngine ( IRoadieSettings configuration , IHttpEncoder httpEncoder , IRoadieDbContext context ,
ICacheManager cacheManager , ILogger logger , IArtistLookupEngine artistLookupEngine ,
ILabelLookupEngine labelLookupEngine )
: base ( configuration , httpEncoder , context , cacheManager , logger )
{
ArtistLookupEngine = ArtistLookupEngine ;
LabelLookupEngine = labelLookupEngine ;
ITunesReleaseSearchEngine = new ITunesSearchEngine ( Configuration , CacheManager , Logger ) ;
MusicBrainzReleaseSearchEngine = new musicbrainz . MusicBrainzProvider ( Configuration , CacheManager , Logger ) ;
LastFmReleaseSearchEngine =
new lastfm . LastFmHelper ( Configuration , CacheManager , Logger , context , httpEncoder ) ;
DiscogsReleaseSearchEngine = new discogs . DiscogsHelper ( Configuration , CacheManager , Logger ) ;
SpotifyReleaseSearchEngine = new spotify . SpotifyHelper ( Configuration , CacheManager , Logger ) ;
WikipediaReleaseSearchEngine =
new wikipedia . WikipediaHelper ( Configuration , CacheManager , Logger , HttpEncoder ) ;
2018-12-15 22:35:20 +00:00
}
2019-07-03 16:21:29 +00:00
public async Task < OperationResult < Release > > Add ( Release release , bool doAddTracksInDatabase = false )
2018-12-15 22:35:20 +00:00
{
SimpleContract . Requires < ArgumentNullException > ( release ! = null , "Invalid Release" ) ;
try
{
var releaseGenreTables = release . Genres ;
var releaseImages = release . Images ;
var releaseMedias = release . Medias ;
var releaseLabels = release . Labels ;
var now = DateTime . UtcNow ;
2019-07-03 16:21:29 +00:00
release . AlternateNames =
release . AlternateNames . AddToDelimitedList ( new [ ] { release . Title . ToAlphanumericName ( ) } ) ;
2018-12-15 22:35:20 +00:00
release . Images = null ;
release . Labels = null ;
release . Medias = null ;
release . Genres = null ;
release . LibraryStatus = LibraryStatus . Incomplete ;
release . Status = Statuses . New ;
if ( ! release . IsValid )
2019-07-03 16:21:29 +00:00
return new OperationResult < Release >
2018-12-15 22:35:20 +00:00
{
Errors = new Exception [ 1 ] { new Exception ( "Release is Invalid" ) }
} ;
2019-07-03 16:21:29 +00:00
DbContext . Releases . Add ( release ) ;
var inserted = 0 ;
2018-12-15 22:35:20 +00:00
try
{
2019-07-03 16:21:29 +00:00
inserted = await DbContext . SaveChangesAsync ( ) ;
2018-12-15 22:35:20 +00:00
}
catch ( Exception ex )
{
2019-07-03 16:21:29 +00:00
Logger . LogError ( ex , ex . Serialize ( ) ) ;
2018-12-15 22:35:20 +00:00
}
2019-07-03 16:21:29 +00:00
2018-12-15 22:35:20 +00:00
if ( inserted > 0 & & release . Id > 0 )
{
2019-07-03 16:21:29 +00:00
_addedReleaseIds . Add ( release . Id ) ;
2018-12-15 22:35:20 +00:00
if ( releaseGenreTables ! = null & & releaseGenreTables . Any ( x = > x . GenreId = = null ) )
foreach ( var releaseGenreTable in releaseGenreTables )
{
2019-07-04 16:00:55 +00:00
var genreName = releaseGenreTable . Genre ? . Name ? . ToAlphanumericName ( ) ;
2019-07-03 16:21:29 +00:00
if ( string . IsNullOrEmpty ( genreName ) ) continue ;
2019-07-04 16:00:55 +00:00
if ( releaseGenreTable . Genre . Name . Length > 100 )
2019-06-03 13:37:13 +00:00
{
2019-07-04 16:00:55 +00:00
var originalName = releaseGenreTable . Genre . Name ;
releaseGenreTable . Genre . Name = releaseGenreTable . Genre . Name . Substring ( 0 , 99 ) ;
2019-06-03 13:37:13 +00:00
genreName = genreName . Substring ( 0 , 99 ) ;
2019-07-04 16:00:55 +00:00
Logger . LogWarning ( $"Genre Name Too long was [{originalName}] truncated to [{releaseGenreTable.Genre.Name}]" ) ;
2019-06-03 13:37:13 +00:00
}
2019-07-03 16:21:29 +00:00
2019-07-04 16:00:55 +00:00
var genre = DbContext . Genres . FirstOrDefault ( x = > x . NormalizedName = = genreName ) ;
2018-12-15 22:35:20 +00:00
if ( genre = = null )
{
genre = new Genre
{
2019-07-04 16:00:55 +00:00
Name = releaseGenreTable . Genre . Name ,
NormalizedName = genreName
2018-12-15 22:35:20 +00:00
} ;
2019-07-03 16:21:29 +00:00
DbContext . Genres . Add ( genre ) ;
await DbContext . SaveChangesAsync ( ) ;
2018-12-15 22:35:20 +00:00
}
2019-07-03 16:21:29 +00:00
2018-12-15 22:35:20 +00:00
if ( genre ! = null & & genre . Id > 0 )
{
2019-07-04 15:50:31 +00:00
DbContext . ReleaseGenres . Add ( new ReleaseGenre
2018-12-15 22:35:20 +00:00
{
2019-07-04 15:50:31 +00:00
ReleaseId = release . Id ,
GenreId = genre . Id
} ) ;
2018-12-15 22:35:20 +00:00
}
}
2019-07-03 16:21:29 +00:00
2018-12-15 22:35:20 +00:00
if ( releaseImages ! = null & & releaseImages . Any ( x = > x . Status = = Statuses . New ) )
{
foreach ( var releaseImage in releaseImages )
2019-07-04 15:50:31 +00:00
{
2019-07-03 16:21:29 +00:00
DbContext . Images . Add ( new Image
2018-12-15 22:35:20 +00:00
{
ReleaseId = release . Id ,
Url = releaseImage . Url ,
Signature = releaseImage . Signature ,
Bytes = releaseImage . Bytes
} ) ;
2019-07-04 15:50:31 +00:00
}
2018-12-15 22:35:20 +00:00
try
{
2019-07-03 16:21:29 +00:00
await DbContext . SaveChangesAsync ( ) ;
2018-12-15 22:35:20 +00:00
}
catch ( Exception ex )
{
2019-07-03 16:21:29 +00:00
Logger . LogError ( ex ) ;
2018-12-15 22:35:20 +00:00
}
}
if ( releaseLabels ! = null & & releaseLabels . Any ( x = > x . Status = = Statuses . New ) )
{
foreach ( var neweleaseLabel in releaseLabels . Where ( x = > x . Status = = Statuses . New ) )
{
2019-07-03 16:21:29 +00:00
var labelFetch = await LabelLookupEngine . GetByName ( neweleaseLabel . Label . Name , true ) ;
2018-12-15 22:35:20 +00:00
if ( labelFetch . IsSuccess )
2019-07-03 16:21:29 +00:00
DbContext . ReleaseLabels . Add ( new ReleaseLabel
2018-12-15 22:35:20 +00:00
{
CatalogNumber = neweleaseLabel . CatalogNumber ,
BeginDate = neweleaseLabel . BeginDate ,
EndDate = neweleaseLabel . EndDate ,
ReleaseId = release . Id ,
LabelId = labelFetch . Data . Id
} ) ;
}
2019-07-03 16:21:29 +00:00
2018-12-15 22:35:20 +00:00
try
{
2019-07-03 16:21:29 +00:00
await DbContext . SaveChangesAsync ( ) ;
2018-12-15 22:35:20 +00:00
}
catch ( Exception ex )
{
2019-07-03 16:21:29 +00:00
Logger . LogError ( ex ) ;
2018-12-15 22:35:20 +00:00
}
}
2019-07-03 16:21:29 +00:00
2018-12-15 22:35:20 +00:00
if ( doAddTracksInDatabase )
if ( releaseMedias ! = null & & releaseMedias . Any ( x = > x . Status = = Statuses . New ) )
{
foreach ( var newReleaseMedia in releaseMedias . Where ( x = > x . Status = = Statuses . New ) )
{
2019-07-03 16:21:29 +00:00
var releasemedia = new ReleaseMedia
2018-12-15 22:35:20 +00:00
{
Status = Statuses . Incomplete ,
MediaNumber = newReleaseMedia . MediaNumber ,
SubTitle = newReleaseMedia . SubTitle ,
TrackCount = newReleaseMedia . TrackCount ,
ReleaseId = release . Id
} ;
2019-07-03 16:21:29 +00:00
var releasemediatracks = new List < Track > ( ) ;
2018-12-15 22:35:20 +00:00
foreach ( var newTrack in newReleaseMedia . Tracks )
{
int? trackArtistId = null ;
string partTitles = null ;
if ( newTrack . TrackArtist ! = null )
{
if ( ! release . IsCastRecording )
{
2019-07-03 16:21:29 +00:00
var trackArtistData =
await ArtistLookupEngine . GetByName (
new AudioMetaData { Artist = newTrack . TrackArtist . Name } , true ) ;
if ( trackArtistData . IsSuccess ) trackArtistId = trackArtistData . Data . Id ;
2018-12-15 22:35:20 +00:00
}
else if ( newTrack . TrackArtists ! = null & & newTrack . TrackArtists . Any ( ) )
{
partTitles = string . Join ( "/" , newTrack . TrackArtists ) ;
}
else
{
partTitles = newTrack . TrackArtist . Name ;
}
}
2019-07-03 16:21:29 +00:00
releasemediatracks . Add ( new Track
2018-12-15 22:35:20 +00:00
{
ArtistId = trackArtistId ,
PartTitles = partTitles ,
Status = Statuses . Incomplete ,
TrackNumber = newTrack . TrackNumber ,
MusicBrainzId = newTrack . MusicBrainzId ,
SpotifyId = newTrack . SpotifyId ,
AmgId = newTrack . AmgId ,
Title = newTrack . Title ,
AlternateNames = newTrack . AlternateNames ,
Duration = newTrack . Duration ,
Tags = newTrack . Tags ,
ISRC = newTrack . ISRC ,
LastFMId = newTrack . LastFMId
} ) ;
}
2019-07-03 16:21:29 +00:00
2018-12-15 22:35:20 +00:00
releasemedia . Tracks = releasemediatracks ;
2019-07-03 16:21:29 +00:00
DbContext . ReleaseMedias . Add ( releasemedia ) ;
_addedTrackIds . AddRange ( releasemedia . Tracks . Select ( x = > x . Id ) ) ;
2018-12-15 22:35:20 +00:00
}
2019-07-03 16:21:29 +00:00
2018-12-15 22:35:20 +00:00
try
{
2019-07-03 16:21:29 +00:00
await DbContext . SaveChangesAsync ( ) ;
2018-12-15 22:35:20 +00:00
}
catch ( Exception ex )
{
2019-07-03 16:21:29 +00:00
Logger . LogError ( ex ) ;
2018-12-15 22:35:20 +00:00
}
}
2019-07-03 16:21:29 +00:00
Logger . LogInformation ( "Added New Release: `{0}`" , release . ToString ( ) ) ;
2018-12-15 22:35:20 +00:00
}
}
catch ( Exception ex )
{
2019-07-03 16:21:29 +00:00
Logger . LogError ( ex , ex . Serialize ( ) ) ;
2018-12-15 22:35:20 +00:00
}
2019-07-03 16:21:29 +00:00
return new OperationResult < Release >
2018-12-15 22:35:20 +00:00
{
IsSuccess = release . Id > 0 ,
Data = release
} ;
}
2019-07-03 16:21:29 +00:00
public async Task < OperationResult < Release > > GetByName ( Artist artist , AudioMetaData metaData ,
bool doFindIfNotInDatabase = false , bool doAddTracksInDatabase = false , int? submissionId = null )
{
SimpleContract . Requires < ArgumentNullException > ( artist ! = null , "Invalid Artist" ) ;
SimpleContract . Requires < ArgumentOutOfRangeException > ( artist . Id > 0 , "Invalid Artist Id" ) ;
try
{
var sw = new Stopwatch ( ) ;
sw . Start ( ) ;
var cacheRegion = new Release { Artist = artist , Title = metaData . Release } . CacheRegion ;
var cacheKey = string . Format ( "urn:release_by_artist_id_and_name:{0}:{1}" , artist . Id , metaData . Release ) ;
var resultInCache = CacheManager . Get < Release > ( cacheKey , cacheRegion ) ;
if ( resultInCache ! = null )
{
sw . Stop ( ) ;
return new OperationResult < Release >
{
IsSuccess = true ,
OperationTime = sw . ElapsedMilliseconds ,
Data = resultInCache
} ;
}
var searchName = metaData . Release . NormalizeName ( ) . ToLower ( ) ;
var specialSearchName = metaData . Release . ToAlphanumericName ( ) ;
var altStart = $"{searchName}|" ;
var altIn = $"|{searchName}|" ;
var altEnds = $"|{searchName}" ;
var altStartSpecial = $"{specialSearchName}|" ;
var altInSpecial = $"|{specialSearchName}|" ;
var altEndsSpecial = $"|{specialSearchName}" ;
var release = ( from r in DbContext . Releases
where r . ArtistId = = artist . Id
where r . Title = = searchName | |
r . Title = = specialSearchName | |
r . AlternateNames = = searchName | |
r . AlternateNames = = specialSearchName | |
r . AlternateNames . Contains ( altStart ) | |
r . AlternateNames . Contains ( altIn ) | |
r . AlternateNames . Contains ( altEnds ) | |
r . AlternateNames . Contains ( altStartSpecial ) | |
r . AlternateNames . Contains ( altInSpecial ) | |
r . AlternateNames . Contains ( altEndsSpecial )
select r
) . FirstOrDefault ( ) ;
sw . Stop ( ) ;
if ( release = = null | | ! release . IsValid )
{
Logger . LogInformation ( "ReleaseFactory: Release Not Found For Artist `{0}` MetaData [{1}]" ,
artist . ToString ( ) , metaData . ToString ( ) ) ;
if ( doFindIfNotInDatabase )
{
var releaseSearch = new OperationResult < Release > ( ) ;
try
{
releaseSearch = await PerformMetaDataProvidersReleaseSearch ( metaData ,
artist . ArtistFileFolder ( Configuration , Configuration . LibraryFolder ) , submissionId ) ;
}
catch ( Exception ex )
{
sw . Stop ( ) ;
Logger . LogError ( ex ) ;
return new OperationResult < Release >
{
OperationTime = sw . ElapsedMilliseconds ,
Errors = new Exception [ 1 ] { ex }
} ;
}
if ( releaseSearch . IsSuccess )
{
release = releaseSearch . Data ;
release . ArtistId = artist . Id ;
var addResult = await Add ( release , doAddTracksInDatabase ) ;
if ( ! addResult . IsSuccess )
{
sw . Stop ( ) ;
return new OperationResult < Release >
{
OperationTime = sw . ElapsedMilliseconds ,
Errors = addResult . Errors
} ;
}
}
}
}
if ( release ! = null ) CacheManager . Add ( cacheKey , release ) ;
return new OperationResult < Release >
{
IsSuccess = release ! = null ,
OperationTime = sw . ElapsedMilliseconds ,
Data = release
} ;
}
catch ( Exception ex )
{
Logger . LogError ( ex ) ;
}
return new OperationResult < Release > ( ) ;
}
public async Task < OperationResult < Release > > PerformMetaDataProvidersReleaseSearch ( AudioMetaData metaData ,
string artistFolder = null , int? submissionId = null )
2018-12-15 22:35:20 +00:00
{
SimpleContract . Requires < ArgumentNullException > ( metaData ! = null , "Invalid MetaData" ) ;
var sw = new Stopwatch ( ) ;
sw . Start ( ) ;
2019-07-03 16:21:29 +00:00
var result = new Release
2018-12-15 22:35:20 +00:00
{
Title = metaData . Release . ToTitleCase ( false ) ,
TrackCount = ( short ) ( metaData . TotalTrackNumbers ? ? 0 ) ,
ReleaseDate = SafeParser . ToDateTime ( metaData . Year ) ,
SubmissionId = submissionId
} ;
var resultsExceptions = new List < Exception > ( ) ;
var releaseGenres = new List < string > ( ) ;
// Add any Genre found in the given MetaData
2019-07-03 16:21:29 +00:00
if ( metaData . Genres ! = null ) releaseGenres . AddRange ( metaData . Genres ) ;
2018-12-15 22:35:20 +00:00
var releaseLabels = new List < ReleaseLabelSearchResult > ( ) ;
var releaseMedias = new List < ReleaseMediaSearchResult > ( ) ;
var releaseImageUrls = new List < string > ( ) ;
2019-07-03 16:21:29 +00:00
var dontDoMetaDataProvidersSearchArtists = Configuration . DontDoMetaDataProvidersSearchArtists ;
if ( ! dontDoMetaDataProvidersSearchArtists . Any ( x = >
x . Equals ( metaData . Artist , StringComparison . OrdinalIgnoreCase ) ) )
2018-12-15 22:35:20 +00:00
{
try
{
#region ITunes
2019-07-03 16:21:29 +00:00
if ( ITunesReleaseSearchEngine . IsEnabled )
2018-12-15 22:35:20 +00:00
{
2019-07-03 16:21:29 +00:00
Logger . LogTrace (
"ITunesReleaseSearchEngine Release Search for ArtistName [{0}], ReleaseTitle [{1}]" ,
metaData . Artist , result . Title ) ;
var iTunesResult =
await ITunesReleaseSearchEngine . PerformReleaseSearch ( metaData . Artist , result . Title , 1 ) ;
2018-12-15 22:35:20 +00:00
if ( iTunesResult . IsSuccess )
{
var i = iTunesResult . Data . First ( ) ;
if ( i . AlternateNames ! = null )
result . AlternateNames = result . AlternateNames . AddToDelimitedList ( i . AlternateNames ) ;
2019-07-03 16:21:29 +00:00
if ( i . Tags ! = null ) result . Tags = result . Tags . AddToDelimitedList ( i . Tags ) ;
if ( i . Urls ! = null ) result . URLs = result . URLs . AddToDelimitedList ( i . Urls ) ;
if ( i . ImageUrls ! = null ) releaseImageUrls . AddRange ( i . ImageUrls ) ;
if ( i . ReleaseGenres ! = null ) releaseGenres . AddRange ( i . ReleaseGenres ) ;
result . CopyTo ( new Release
2018-12-15 22:35:20 +00:00
{
ReleaseDate = result . ReleaseDate ? ? i . ReleaseDate ,
AmgId = i . AmgId ,
Profile = i . Profile ,
ITunesId = i . iTunesId ,
Title = result . Title ? ? i . ReleaseTitle ,
2019-07-03 16:21:29 +00:00
Thumbnail = i . ReleaseThumbnailUrl ! = null
? WebHelper . BytesForImageUrl ( i . ReleaseThumbnailUrl )
: null ,
ReleaseType = result . ReleaseType = = ReleaseType . Unknown
? SafeParser . ToEnum < ReleaseType > ( i . ReleaseType )
: result . ReleaseType
2018-12-15 22:35:20 +00:00
} ) ;
2019-07-03 16:21:29 +00:00
if ( i . ReleaseLabel ! = null ) releaseLabels . AddRange ( i . ReleaseLabel ) ;
if ( i . ReleaseMedia ! = null ) releaseMedias . AddRange ( i . ReleaseMedia ) ;
2018-12-15 22:35:20 +00:00
}
2019-07-03 16:21:29 +00:00
if ( iTunesResult . Errors ! = null ) resultsExceptions . AddRange ( iTunesResult . Errors ) ;
2018-12-15 22:35:20 +00:00
}
#endregion ITunes
#region MusicBrainz
2019-07-03 16:21:29 +00:00
if ( MusicBrainzReleaseSearchEngine . IsEnabled )
2018-12-15 22:35:20 +00:00
{
2019-07-03 16:21:29 +00:00
Logger . LogTrace (
"MusicBrainzReleaseSearchEngine Release Search for ArtistName [{0}], ReleaseTitle [{1}]" ,
metaData . Artist , result . Title ) ;
var mbResult =
await MusicBrainzReleaseSearchEngine . PerformReleaseSearch ( metaData . Artist , result . Title , 1 ) ;
2018-12-15 22:35:20 +00:00
if ( mbResult . IsSuccess )
{
var mb = mbResult . Data . First ( ) ;
if ( mb . AlternateNames ! = null )
result . AlternateNames = result . AlternateNames . AddToDelimitedList ( mb . AlternateNames ) ;
2019-07-03 16:21:29 +00:00
if ( mb . Tags ! = null ) result . Tags = result . Tags . AddToDelimitedList ( mb . Tags ) ;
if ( mb . Urls ! = null ) result . URLs = result . URLs . AddToDelimitedList ( mb . Urls ) ;
if ( mb . ImageUrls ! = null ) releaseImageUrls . AddRange ( mb . ImageUrls ) ;
if ( mb . ReleaseGenres ! = null ) releaseGenres . AddRange ( mb . ReleaseGenres ) ;
if ( ! string . IsNullOrEmpty ( mb . ReleaseTitle ) & &
! mb . ReleaseTitle . Equals ( result . Title , StringComparison . OrdinalIgnoreCase ) )
result . AlternateNames . AddToDelimitedList ( new [ ] { mb . ReleaseTitle } ) ;
result . CopyTo ( new Release
2018-12-15 22:35:20 +00:00
{
ReleaseDate = result . ReleaseDate ? ? mb . ReleaseDate ,
AmgId = mb . AmgId ,
Profile = mb . Profile ,
2019-07-03 16:21:29 +00:00
TrackCount = mb . ReleaseMedia ! = null
? ( short ) mb . ReleaseMedia . Sum ( x = > x . TrackCount )
: ( short ) 0 ,
2018-12-15 22:35:20 +00:00
MusicBrainzId = mb . MusicBrainzId ,
ITunesId = mb . iTunesId ,
Title = result . Title ? ? mb . ReleaseTitle ,
2019-07-03 16:21:29 +00:00
Thumbnail = mb . ReleaseThumbnailUrl ! = null
? WebHelper . BytesForImageUrl ( mb . ReleaseThumbnailUrl )
: null ,
ReleaseType = result . ReleaseType = = ReleaseType . Unknown
? SafeParser . ToEnum < ReleaseType > ( mb . ReleaseType )
: result . ReleaseType
2018-12-15 22:35:20 +00:00
} ) ;
2019-07-03 16:21:29 +00:00
if ( mb . ReleaseLabel ! = null ) releaseLabels . AddRange ( mb . ReleaseLabel ) ;
if ( mb . ReleaseMedia ! = null ) releaseMedias . AddRange ( mb . ReleaseMedia ) ;
2018-12-15 22:35:20 +00:00
}
2019-07-03 16:21:29 +00:00
if ( mbResult . Errors ! = null ) resultsExceptions . AddRange ( mbResult . Errors ) ;
2018-12-15 22:35:20 +00:00
}
#endregion MusicBrainz
#region LastFm
2019-07-03 16:21:29 +00:00
if ( LastFmReleaseSearchEngine . IsEnabled )
2018-12-15 22:35:20 +00:00
{
2019-07-03 16:21:29 +00:00
Logger . LogTrace (
"LastFmReleaseSearchEngine Release Search for ArtistName [{0}], ReleaseTitle [{1}]" ,
metaData . Artist , result . Title ) ;
var lastFmResult =
await LastFmReleaseSearchEngine . PerformReleaseSearch ( metaData . Artist , result . Title , 1 ) ;
2018-12-15 22:35:20 +00:00
if ( lastFmResult . IsSuccess )
{
var l = lastFmResult . Data . First ( ) ;
if ( l . AlternateNames ! = null )
result . AlternateNames = result . AlternateNames . AddToDelimitedList ( l . AlternateNames ) ;
2019-07-03 16:21:29 +00:00
if ( l . Tags ! = null ) result . Tags = result . Tags . AddToDelimitedList ( l . Tags ) ;
if ( l . Urls ! = null ) result . URLs = result . URLs . AddToDelimitedList ( l . Urls ) ;
if ( l . ImageUrls ! = null ) releaseImageUrls . AddRange ( l . ImageUrls ) ;
if ( l . ReleaseGenres ! = null ) releaseGenres . AddRange ( l . ReleaseGenres ) ;
if ( ! string . IsNullOrEmpty ( l . ReleaseTitle ) & &
! l . ReleaseTitle . Equals ( result . Title , StringComparison . OrdinalIgnoreCase ) )
result . AlternateNames . AddToDelimitedList ( new [ ] { l . ReleaseTitle } ) ;
result . CopyTo ( new Release
2018-12-15 22:35:20 +00:00
{
ReleaseDate = result . ReleaseDate ? ? l . ReleaseDate ,
AmgId = l . AmgId ,
Profile = l . Profile ,
LastFMId = l . LastFMId ,
LastFMSummary = l . LastFMSummary ,
MusicBrainzId = l . MusicBrainzId ,
ITunesId = l . iTunesId ,
Title = result . Title ? ? l . ReleaseTitle ,
2019-07-03 16:21:29 +00:00
Thumbnail = l . ReleaseThumbnailUrl ! = null
? WebHelper . BytesForImageUrl ( l . ReleaseThumbnailUrl )
: null ,
ReleaseType = result . ReleaseType = = ReleaseType . Unknown
? SafeParser . ToEnum < ReleaseType > ( l . ReleaseType )
: result . ReleaseType
2018-12-15 22:35:20 +00:00
} ) ;
2019-07-03 16:21:29 +00:00
if ( l . ReleaseLabel ! = null ) releaseLabels . AddRange ( l . ReleaseLabel ) ;
if ( l . ReleaseMedia ! = null ) releaseMedias . AddRange ( l . ReleaseMedia ) ;
2018-12-15 22:35:20 +00:00
}
2019-07-03 16:21:29 +00:00
if ( lastFmResult . Errors ! = null ) resultsExceptions . AddRange ( lastFmResult . Errors ) ;
2018-12-15 22:35:20 +00:00
}
#endregion LastFm
#region Spotify
2019-07-03 16:21:29 +00:00
if ( SpotifyReleaseSearchEngine . IsEnabled )
2018-12-15 22:35:20 +00:00
{
2019-07-03 16:21:29 +00:00
Logger . LogTrace (
"SpotifyReleaseSearchEngine Release Search for ArtistName [{0}], ReleaseTitle [{1}]" ,
metaData . Artist , result . Title ) ;
var spotifyResult =
await SpotifyReleaseSearchEngine . PerformReleaseSearch ( metaData . Artist , result . Title , 1 ) ;
2018-12-15 22:35:20 +00:00
if ( spotifyResult . IsSuccess )
{
var s = spotifyResult . Data . First ( ) ;
2019-07-03 16:21:29 +00:00
if ( s . Tags ! = null ) result . Tags = result . Tags . AddToDelimitedList ( s . Tags ) ;
if ( s . Urls ! = null ) result . URLs = result . URLs . AddToDelimitedList ( s . Urls ) ;
if ( s . ImageUrls ! = null ) releaseImageUrls . AddRange ( s . ImageUrls ) ;
if ( s . ReleaseGenres ! = null ) releaseGenres . AddRange ( s . ReleaseGenres ) ;
if ( ! string . IsNullOrEmpty ( s . ReleaseTitle ) & &
! s . ReleaseTitle . Equals ( result . Title , StringComparison . OrdinalIgnoreCase ) )
result . AlternateNames . AddToDelimitedList ( new [ ] { s . ReleaseTitle } ) ;
result . CopyTo ( new Release
2018-12-15 22:35:20 +00:00
{
ReleaseDate = result . ReleaseDate ? ? s . ReleaseDate ,
AmgId = s . AmgId ,
2019-07-03 16:21:29 +00:00
Profile = HttpEncoder . HtmlEncode ( s . Profile ) ,
2018-12-15 22:35:20 +00:00
SpotifyId = s . SpotifyId ,
MusicBrainzId = s . MusicBrainzId ,
ITunesId = s . iTunesId ,
Title = result . Title ? ? s . ReleaseTitle ,
2019-07-03 16:21:29 +00:00
Thumbnail = s . ReleaseThumbnailUrl ! = null
? WebHelper . BytesForImageUrl ( s . ReleaseThumbnailUrl )
: null ,
ReleaseType = result . ReleaseType = = ReleaseType . Unknown
? SafeParser . ToEnum < ReleaseType > ( s . ReleaseType )
: result . ReleaseType
2018-12-15 22:35:20 +00:00
} ) ;
2019-07-03 16:21:29 +00:00
if ( s . ReleaseLabel ! = null ) releaseLabels . AddRange ( s . ReleaseLabel ) ;
if ( s . ReleaseMedia ! = null ) releaseMedias . AddRange ( s . ReleaseMedia ) ;
2018-12-15 22:35:20 +00:00
}
2019-07-03 16:21:29 +00:00
if ( spotifyResult . Errors ! = null ) resultsExceptions . AddRange ( spotifyResult . Errors ) ;
2018-12-15 22:35:20 +00:00
}
#endregion Spotify
#region Discogs
2019-07-03 16:21:29 +00:00
if ( DiscogsReleaseSearchEngine . IsEnabled )
2018-12-15 22:35:20 +00:00
{
2019-07-03 16:21:29 +00:00
Logger . LogTrace (
"DiscogsReleaseSearchEngine Release Search for ArtistName [{0}], ReleaseTitle [{1}]" ,
metaData . Artist , result . Title ) ;
var discogsResult =
await DiscogsReleaseSearchEngine . PerformReleaseSearch ( metaData . Artist , result . Title , 1 ) ;
2018-12-15 22:35:20 +00:00
if ( discogsResult . IsSuccess )
{
var d = discogsResult . Data . First ( ) ;
2019-07-03 16:21:29 +00:00
if ( d . Urls ! = null ) result . URLs = result . URLs . AddToDelimitedList ( d . Urls ) ;
if ( d . ImageUrls ! = null ) releaseImageUrls . AddRange ( d . ImageUrls ) ;
2018-12-15 22:35:20 +00:00
if ( d . AlternateNames ! = null )
result . AlternateNames = result . AlternateNames . AddToDelimitedList ( d . AlternateNames ) ;
2019-07-03 16:21:29 +00:00
if ( ! string . IsNullOrEmpty ( d . ReleaseTitle ) & &
! d . ReleaseTitle . Equals ( result . Title , StringComparison . OrdinalIgnoreCase ) )
result . AlternateNames . AddToDelimitedList ( new [ ] { d . ReleaseTitle } ) ;
result . CopyTo ( new Release
2018-12-15 22:35:20 +00:00
{
2019-07-03 16:21:29 +00:00
Profile = HttpEncoder . HtmlEncode ( d . Profile ) ,
2018-12-15 22:35:20 +00:00
DiscogsId = d . DiscogsId ,
Title = result . Title ? ? d . ReleaseTitle ,
2019-07-03 16:21:29 +00:00
Thumbnail = d . ReleaseThumbnailUrl ! = null
? WebHelper . BytesForImageUrl ( d . ReleaseThumbnailUrl )
: null ,
ReleaseType = result . ReleaseType = = ReleaseType . Unknown
? SafeParser . ToEnum < ReleaseType > ( d . ReleaseType )
: result . ReleaseType
2018-12-15 22:35:20 +00:00
} ) ;
2019-07-03 16:21:29 +00:00
if ( d . ReleaseLabel ! = null ) releaseLabels . AddRange ( d . ReleaseLabel ) ;
if ( d . ReleaseMedia ! = null ) releaseMedias . AddRange ( d . ReleaseMedia ) ;
2018-12-15 22:35:20 +00:00
}
2019-07-03 16:21:29 +00:00
if ( discogsResult . Errors ! = null ) resultsExceptions . AddRange ( discogsResult . Errors ) ;
2018-12-15 22:35:20 +00:00
}
#endregion Discogs
}
catch ( Exception ex )
{
2019-07-03 16:21:29 +00:00
Logger . LogError ( ex ) ;
2018-12-15 22:35:20 +00:00
}
2019-07-03 16:21:29 +00:00
Logger . LogTrace ( "Metadata Providers Search Complete. [{0}]" , sw . ElapsedMilliseconds ) ;
2018-12-15 22:35:20 +00:00
}
else
{
2019-07-03 16:21:29 +00:00
Logger . LogTrace (
"Skipped Metadata Providers Search, DontDoMetaDataProvidersSearchArtists set for Artist [{0}]." ,
metaData . Artist ) ;
2018-12-15 22:35:20 +00:00
}
if ( result . AlternateNames ! = null )
2019-07-03 16:21:29 +00:00
result . AlternateNames = string . Join ( "|" ,
result . AlternateNames . ToListFromDelimited ( ) . Distinct ( ) . OrderBy ( x = > x ) ) ;
2018-12-15 22:35:20 +00:00
if ( result . URLs ! = null )
result . URLs = string . Join ( "|" , result . URLs . ToListFromDelimited ( ) . Distinct ( ) . OrderBy ( x = > x ) ) ;
if ( result . Tags ! = null )
result . Tags = string . Join ( "|" , result . Tags . ToListFromDelimited ( ) . Distinct ( ) . OrderBy ( x = > x ) ) ;
if ( releaseGenres . Any ( ) )
{
result . Genres = new List < ReleaseGenre > ( ) ;
2019-07-04 16:00:55 +00:00
foreach ( var releaseGenre in releaseGenres . Where ( x = > ! string . IsNullOrEmpty ( x ) ) . GroupBy ( x = > x ) . Select ( x = > x . First ( ) ) )
2018-12-15 22:35:20 +00:00
{
var rg = releaseGenre . Trim ( ) ;
if ( ! string . IsNullOrEmpty ( rg ) )
2019-07-04 16:00:55 +00:00
{
2019-06-03 13:37:13 +00:00
foreach ( var g in ID3TagsHelper . SplitGenre ( rg ) )
2019-07-04 16:00:55 +00:00
{
2019-07-03 16:21:29 +00:00
result . Genres . Add ( new ReleaseGenre
2019-06-03 13:37:13 +00:00
{
2019-07-04 16:00:55 +00:00
Genre = DbContext . Genres . Where ( x = > x . Name . ToLower ( ) = = g . ToLower ( ) ) . FirstOrDefault ( ) ? ? new Genre
{
Name = g ,
NormalizedName = g . ToAlphanumericName ( )
}
2019-06-03 13:37:13 +00:00
} ) ;
2019-07-04 16:00:55 +00:00
}
}
} ;
2018-12-15 22:35:20 +00:00
}
2019-07-03 16:21:29 +00:00
2018-12-15 22:35:20 +00:00
if ( releaseImageUrls . Any ( ) )
{
2019-07-03 16:21:29 +00:00
var imageBag = new ConcurrentBag < Image > ( ) ;
2018-12-15 22:35:20 +00:00
var i = releaseImageUrls . Select ( async url = >
{
imageBag . Add ( await WebHelper . GetImageFromUrlAsync ( url ) ) ;
} ) ;
await Task . WhenAll ( i ) ;
// If the release has images merge any fetched images
2019-07-03 16:21:29 +00:00
var existingImages = result . Images ! = null ? result . Images . ToList ( ) : new List < Image > ( ) ;
2018-12-15 22:35:20 +00:00
existingImages . AddRange ( imageBag . ToList ( ) ) ;
// Now set release images to be unique image based on image hash
2019-07-03 16:21:29 +00:00
result . Images = existingImages . Where ( x = > x ! = null & & x . Bytes ! = null ) . GroupBy ( x = > x . Signature )
. Select ( x = > x . First ( ) ) . Take ( Configuration . Processing . MaximumReleaseImagesToAdd ) . ToList ( ) ;
if ( result . Thumbnail = = null & & result . Images ! = null ) result . Thumbnail = result . Images . First ( ) . Bytes ;
2018-12-15 22:35:20 +00:00
}
if ( releaseLabels . Any ( ) )
2019-07-03 16:21:29 +00:00
result . Labels = releaseLabels . GroupBy ( x = > x . CatalogNumber ) . Select ( x = > x . First ( ) ) . Select ( x = >
new ReleaseLabel
2018-12-15 22:35:20 +00:00
{
2019-07-03 16:21:29 +00:00
CatalogNumber = x . CatalogNumber ,
BeginDate = x . BeginDate ,
EndDate = x . EndDate ,
Status = Statuses . New ,
Label = new Label
{
Name = x . Label . LabelName ,
SortName = x . Label . LabelSortName ,
MusicBrainzId = x . Label . MusicBrainzId ,
BeginDate = x . Label . StartDate ,
EndDate = x . Label . EndDate ,
ImageUrl = x . Label . LabelImageUrl ,
AlternateNames = x . Label . AlternateNames . ToDelimitedList ( ) ,
URLs = x . Label . Urls . ToDelimitedList ( ) ,
Status = Statuses . New
}
} ) . ToList ( ) ;
2018-12-15 22:35:20 +00:00
if ( releaseMedias . Any ( ) )
{
2019-07-03 16:21:29 +00:00
var resultReleaseMedias = new List < ReleaseMedia > ( ) ;
2018-12-15 22:35:20 +00:00
foreach ( var releaseMedia in releaseMedias . GroupBy ( x = > x . ReleaseMediaNumber ) . Select ( x = > x . First ( ) ) )
{
2019-07-03 16:21:29 +00:00
var rm = new ReleaseMedia
2018-12-15 22:35:20 +00:00
{
MediaNumber = releaseMedia . ReleaseMediaNumber ? ? 0 ,
SubTitle = releaseMedia . ReleaseMediaSubTitle ,
TrackCount = releaseMedia . TrackCount ? ? 0 ,
Status = Statuses . New
} ;
2019-07-03 16:21:29 +00:00
var rmTracks = new List < Track > ( ) ;
foreach ( var releaseTrack in releaseMedias
. Where ( x = > x . ReleaseMediaNumber = = releaseMedia . ReleaseMediaNumber )
. SelectMany ( x = > x . Tracks )
. Where ( x = > x . TrackNumber . HasValue )
. OrderBy ( x = > x . TrackNumber ) )
2018-12-15 22:35:20 +00:00
{
var foundTrack = true ;
var rmTrack = rmTracks . FirstOrDefault ( x = > x . TrackNumber = = releaseTrack . TrackNumber . Value ) ;
if ( rmTrack = = null )
{
2019-07-03 16:21:29 +00:00
Artist trackArtist = null ;
2018-12-15 22:35:20 +00:00
if ( releaseTrack . Artist ! = null )
2019-07-03 16:21:29 +00:00
trackArtist = new Artist
2018-12-15 22:35:20 +00:00
{
Name = releaseTrack . Artist . ArtistName ,
SpotifyId = releaseTrack . Artist . SpotifyId ,
ArtistType = releaseTrack . Artist . ArtistType
} ;
2019-07-03 16:21:29 +00:00
rmTrack = new Track
2018-12-15 22:35:20 +00:00
{
TrackArtist = trackArtist ,
TrackArtists = releaseTrack . Artists ,
TrackNumber = releaseTrack . TrackNumber . Value ,
MusicBrainzId = releaseTrack . MusicBrainzId ,
SpotifyId = releaseTrack . SpotifyId ,
AmgId = releaseTrack . AmgId ,
Title = releaseTrack . Title ,
AlternateNames = releaseTrack . AlternateNames . ToDelimitedList ( ) ,
Duration = releaseTrack . Duration ,
Tags = releaseTrack . Tags . ToDelimitedList ( ) ,
ISRC = releaseTrack . ISRC ,
LastFMId = releaseTrack . LastFMId ,
Status = Statuses . New
} ;
foundTrack = false ;
}
2019-07-03 16:21:29 +00:00
2018-12-15 22:35:20 +00:00
rmTrack . Duration = rmTrack . Duration ? ? releaseTrack . Duration ;
rmTrack . MusicBrainzId = rmTrack . MusicBrainzId ? ? releaseTrack . MusicBrainzId ;
rmTrack . SpotifyId = rmTrack . SpotifyId ? ? releaseTrack . SpotifyId ;
rmTrack . AmgId = rmTrack . AmgId ? ? releaseTrack . AmgId ;
rmTrack . Title = rmTrack . Title ? ? releaseTrack . Title ;
rmTrack . Duration = releaseTrack . Duration ;
2019-07-03 16:21:29 +00:00
rmTrack . Tags = rmTrack . Tags = = null
? releaseTrack . Tags . ToDelimitedList ( )
: rmTrack . Tags . AddToDelimitedList ( releaseTrack . Tags ) ;
rmTrack . AlternateNames = rmTrack . AlternateNames = = null
? releaseTrack . AlternateNames . ToDelimitedList ( )
: rmTrack . AlternateNames . AddToDelimitedList ( releaseTrack . AlternateNames ) ;
2018-12-15 22:35:20 +00:00
rmTrack . ISRC = rmTrack . ISRC ? ? releaseTrack . ISRC ;
rmTrack . LastFMId = rmTrack . LastFMId ? ? releaseTrack . LastFMId ;
2019-07-03 16:21:29 +00:00
if ( ! foundTrack ) rmTracks . Add ( rmTrack ) ;
2018-12-15 22:35:20 +00:00
}
2019-07-03 16:21:29 +00:00
2018-12-15 22:35:20 +00:00
rm . Tracks = rmTracks ;
rm . TrackCount = ( short ) rmTracks . Count ( ) ;
resultReleaseMedias . Add ( rm ) ;
}
2019-07-03 16:21:29 +00:00
2018-12-15 22:35:20 +00:00
result . Medias = resultReleaseMedias ;
result . TrackCount = ( short ) releaseMedias . SelectMany ( x = > x . Tracks ) . Count ( ) ;
}
if ( metaData . Images ! = null & & metaData . Images . Any ( ) )
{
var image = metaData . Images . FirstOrDefault ( x = > x . Type = = AudioMetaDataImageType . FrontCover ) ;
2019-07-03 16:21:29 +00:00
if ( image = = null ) image = metaData . Images . FirstOrDefault ( ) ;
2018-12-15 22:35:20 +00:00
// If there is an image on the metadata file itself then that over-rides metadata providers.
2019-07-03 16:21:29 +00:00
if ( image ! = null ) result . Thumbnail = image . Data ;
2018-12-15 22:35:20 +00:00
}
2019-07-03 16:21:29 +00:00
2018-12-15 22:35:20 +00:00
if ( ! string . IsNullOrEmpty ( artistFolder ) )
{
// If any file exist for cover that over-rides whatever if found in metadata providers.
2019-02-10 00:19:26 +00:00
var releaseFolder = new DirectoryInfo ( result . ReleaseFileFolder ( artistFolder ) ) ;
if ( releaseFolder . Exists )
2018-12-15 22:35:20 +00:00
{
2019-06-02 23:52:09 +00:00
string coverFileName = null ;
2019-02-10 00:19:26 +00:00
var cover = ImageHelper . FindImageTypeInDirectory ( releaseFolder , ImageType . Release ) ;
2019-07-03 16:21:29 +00:00
if ( ! cover . Any ( ) )
2019-06-02 23:52:09 +00:00
{
// See if cover exist by filename
2019-07-03 16:21:29 +00:00
var imageFilesInFolder =
ImageHelper . ImageFilesInFolder ( releaseFolder . FullName , SearchOption . AllDirectories ) ;
2019-06-02 23:52:09 +00:00
if ( imageFilesInFolder ! = null & & imageFilesInFolder . Any ( ) )
{
2019-07-03 16:21:29 +00:00
var imageCoverByReleaseName = imageFilesInFolder . FirstOrDefault ( x = >
x = = result . Title | | x = = result . Title . ToFileNameFriendly ( ) ) ;
if ( imageCoverByReleaseName ! = null ) coverFileName = imageCoverByReleaseName ;
2019-06-02 23:52:09 +00:00
}
}
2019-07-03 16:21:29 +00:00
else if ( cover . Any ( ) )
2019-06-02 23:52:09 +00:00
{
coverFileName = cover . First ( ) . FullName ;
}
2019-07-03 16:21:29 +00:00
if ( ! string . IsNullOrEmpty ( coverFileName ) )
2018-12-15 22:35:20 +00:00
{
// Read image and convert to jpeg
result . Thumbnail = File . ReadAllBytes ( coverFileName ) ;
2019-07-03 16:21:29 +00:00
Logger . LogDebug ( "Using Release Cover File [{0}]" , coverFileName ) ;
2018-12-15 22:35:20 +00:00
}
}
}
if ( result . Thumbnail ! = null )
{
2019-07-03 16:21:29 +00:00
result . Thumbnail = ImageHelper . ResizeImage ( result . Thumbnail , Configuration . ThumbnailImageSize . Width ,
Configuration . ThumbnailImageSize . Height ) ;
2018-12-15 22:35:20 +00:00
result . Thumbnail = ImageHelper . ConvertToJpegFormat ( result . Thumbnail ) ;
2019-07-03 16:21:29 +00:00
if ( result . Thumbnail . Length > = ImageHelper . MaximumThumbnailByteSize )
2019-06-03 03:13:07 +00:00
{
2019-07-03 16:21:29 +00:00
Logger . LogWarning (
$"Release Thumbnail larger than maximum size after resizing to [{Configuration.ThumbnailImageSize.Width}x{Configuration.ThumbnailImageSize.Height}] Thumbnail Size [{result.Thumbnail.Length}]" ) ;
2019-06-03 03:13:07 +00:00
result . Thumbnail = null ;
}
2018-12-15 22:35:20 +00:00
}
2019-07-03 16:21:29 +00:00
2018-12-15 22:35:20 +00:00
sw . Stop ( ) ;
2019-07-03 16:21:29 +00:00
return new OperationResult < Release >
2018-12-15 22:35:20 +00:00
{
Data = result ,
IsSuccess = result ! = null ,
Errors = resultsExceptions ,
OperationTime = sw . ElapsedMilliseconds
} ;
}
}
2019-07-03 16:21:29 +00:00
}