de-normalize item by name data. create counts during library scan for fast access.

This commit is contained in:
Luke Pulverenti
2013-09-10 14:56:00 -04:00
parent d078edfb96
commit 740a10a4e3
63 changed files with 1923 additions and 971 deletions

View File

@@ -98,13 +98,13 @@ namespace MediaBrowser.Providers
var args = GetResolveArgsContainingImages(item);
// Make sure current image paths still exist
ValidateImages(item);
item.ValidateImages();
cancellationToken.ThrowIfCancellationRequested();
// Make sure current backdrop paths still exist
ValidateBackdrops(item);
ValidateScreenshots(item, args);
item.ValidateBackdrops();
item.ValidateScreenshots();
cancellationToken.ThrowIfCancellationRequested();
@@ -128,74 +128,6 @@ namespace MediaBrowser.Providers
return item.ResolveArgs;
}
/// <summary>
/// Validates that images within the item are still on the file system
/// </summary>
/// <param name="item">The item.</param>
internal static void ValidateImages(BaseItem item)
{
// Only validate paths from the same directory - need to copy to a list because we are going to potentially modify the collection below
var deletedKeys = item.Images
.ToList()
.Where(image => !File.Exists(image.Value))
.Select(i => i.Key)
.ToList();
// Now remove them from the dictionary
foreach (var key in deletedKeys)
{
item.Images.Remove(key);
}
}
/// <summary>
/// Validates that backdrops within the item are still on the file system
/// </summary>
/// <param name="item">The item.</param>
internal static void ValidateBackdrops(BaseItem item)
{
// Only validate paths from the same directory - need to copy to a list because we are going to potentially modify the collection below
var deletedImages = item.BackdropImagePaths
.Where(path => !File.Exists(path))
.ToList();
// Now remove them from the dictionary
foreach (var path in deletedImages)
{
item.BackdropImagePaths.Remove(path);
}
}
/// <summary>
/// Validates the screenshots.
/// </summary>
/// <param name="item">The item.</param>
/// <param name="args">The args.</param>
private void ValidateScreenshots(BaseItem item, ItemResolveArgs args)
{
// Only validate paths from the same directory - need to copy to a list because we are going to potentially modify the collection below
var deletedImages = item.ScreenshotImagePaths
.Where(path => !File.Exists(path))
.ToList();
// Now remove them from the dictionary
foreach (var path in deletedImages)
{
item.ScreenshotImagePaths.Remove(path);
}
}
/// <summary>
/// Determines whether [is in same directory] [the specified item].
/// </summary>
/// <param name="item">The item.</param>
/// <param name="path">The path.</param>
/// <returns><c>true</c> if [is in same directory] [the specified item]; otherwise, <c>false</c>.</returns>
private bool IsInMetaLocation(BaseItem item, string path)
{
return string.Equals(Path.GetDirectoryName(path), item.MetaLocation, StringComparison.OrdinalIgnoreCase);
}
/// <summary>
/// Gets the image.
/// </summary>

View File

@@ -70,7 +70,6 @@
<Compile Include="Music\AlbumInfoFromSongProvider.cs" />
<Compile Include="Music\ArtistInfoFromSongProvider.cs" />
<Compile Include="Music\ArtistProviderFromXml.cs" />
<Compile Include="Music\ArtistsPostScanTask.cs" />
<Compile Include="Music\FanArtAlbumProvider.cs" />
<Compile Include="Music\FanArtArtistByNameProvider.cs" />
<Compile Include="Music\FanArtArtistProvider.cs" />
@@ -81,6 +80,7 @@
<Compile Include="Music\LastfmArtistProvider.cs" />
<Compile Include="Music\LastfmBaseProvider.cs" />
<Compile Include="Music\LastfmHelper.cs" />
<Compile Include="Music\MusicAlbumDynamicInfoProvider.cs" />
<Compile Include="Music\MusicVideoXmlParser.cs" />
<Compile Include="Music\SoundtrackPostScanTask.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
@@ -106,9 +106,9 @@
<Compile Include="TV\RemoteSeasonProvider.cs" />
<Compile Include="TV\RemoteSeriesProvider.cs" />
<Compile Include="TV\SeasonProviderFromXml.cs" />
<Compile Include="TV\SeriesPostScanTask.cs" />
<Compile Include="TV\SeriesProviderFromXml.cs" />
<Compile Include="TV\SeriesXmlParser.cs" />
<Compile Include="TV\SeriesPostScanTask.cs" />
<Compile Include="TV\TvdbPersonImageProvider.cs" />
<Compile Include="TV\TvdbPrescanTask.cs" />
<Compile Include="TV\TvdbSeriesImageProvider.cs" />

View File

@@ -1,161 +0,0 @@
using MediaBrowser.Common.Progress;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Audio;
using MediaBrowser.Controller.Library;
using MediaBrowser.Model.Entities;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace MediaBrowser.Providers.Music
{
/// <summary>
/// Class ArtistsPostScanTask
/// </summary>
public class ArtistsPostScanTask : ILibraryPostScanTask
{
/// <summary>
/// The _library manager
/// </summary>
private readonly ILibraryManager _libraryManager;
/// <summary>
/// Initializes a new instance of the <see cref="ArtistsPostScanTask"/> class.
/// </summary>
/// <param name="libraryManager">The library manager.</param>
public ArtistsPostScanTask(ILibraryManager libraryManager)
{
_libraryManager = libraryManager;
}
/// <summary>
/// Runs the specified progress.
/// </summary>
/// <param name="progress">The progress.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task.</returns>
public async Task Run(IProgress<double> progress, CancellationToken cancellationToken)
{
var allItems = _libraryManager.RootFolder.RecursiveChildren.ToList();
var allArtists = await GetAllArtists(allItems).ConfigureAwait(false);
progress.Report(10);
var allMusicArtists = allItems.OfType<MusicArtist>().ToList();
var allSongs = allItems.OfType<Audio>().ToList();
var numComplete = 0;
foreach (var artist in allArtists)
{
var musicArtist = FindMusicArtist(artist, allMusicArtists);
if (musicArtist != null)
{
MergeImages(musicArtist.Images, artist.Images);
// Merge backdrops
var backdrops = musicArtist.BackdropImagePaths.ToList();
backdrops.InsertRange(0, artist.BackdropImagePaths);
artist.BackdropImagePaths = backdrops.Distinct(StringComparer.OrdinalIgnoreCase)
.ToList();
ImageFromMediaLocationProvider.ValidateImages(artist);
ImageFromMediaLocationProvider.ValidateBackdrops(artist);
}
if (!artist.LockedFields.Contains(MetadataFields.Genres))
{
// Avoid implicitly captured closure
var artist1 = artist;
artist.Genres = allSongs.Where(i => i.HasArtist(artist1.Name))
.SelectMany(i => i.Genres)
.Distinct(StringComparer.OrdinalIgnoreCase)
.ToList();
}
numComplete++;
double percent = numComplete;
percent /= allArtists.Length;
percent *= 5;
progress.Report(10 + percent);
}
var innerProgress = new ActionableProgress<double>();
innerProgress.RegisterAction(pct => progress.Report(15 + pct * .85));
await _libraryManager.ValidateArtists(cancellationToken, innerProgress).ConfigureAwait(false);
}
private void MergeImages(Dictionary<ImageType, string> source, Dictionary<ImageType, string> target)
{
foreach (var key in source.Keys
.ToList()
.Where(k => !target.ContainsKey(k)))
{
string path;
if (source.TryGetValue(key, out path))
{
target[key] = path;
}
}
}
/// <summary>
/// Gets all artists.
/// </summary>
/// <param name="allItems">All items.</param>
/// <returns>Task{Artist[]}.</returns>
private Task<Artist[]> GetAllArtists(IEnumerable<BaseItem> allItems)
{
var itemsList = allItems.OfType<Audio>().ToList();
var tasks = itemsList
.SelectMany(i =>
{
var list = new List<string>();
if (!string.IsNullOrEmpty(i.AlbumArtist))
{
list.Add(i.AlbumArtist);
}
list.AddRange(i.Artists);
return list;
})
.Distinct(StringComparer.OrdinalIgnoreCase)
.Select(i => _libraryManager.GetArtist(i));
return Task.WhenAll(tasks);
}
/// <summary>
/// Finds the music artist.
/// </summary>
/// <param name="artist">The artist.</param>
/// <param name="allMusicArtists">All music artists.</param>
/// <returns>MusicArtist.</returns>
private static MusicArtist FindMusicArtist(Artist artist, IEnumerable<MusicArtist> allMusicArtists)
{
var musicBrainzId = artist.GetProviderId(MetadataProviders.Musicbrainz);
return allMusicArtists.FirstOrDefault(i =>
{
if (!string.IsNullOrWhiteSpace(musicBrainzId) && string.Equals(musicBrainzId, i.GetProviderId(MetadataProviders.Musicbrainz), StringComparison.OrdinalIgnoreCase))
{
return true;
}
return string.Compare(i.Name, artist.Name, CultureInfo.CurrentCulture, CompareOptions.IgnoreNonSpace | CompareOptions.IgnoreCase | CompareOptions.IgnoreSymbols) == 0;
});
}
}
}

View File

@@ -0,0 +1,85 @@
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Audio;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Logging;
using System;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace MediaBrowser.Providers.Music
{
/// <summary>
/// Class MusicAlbumDynamicInfoProvider
/// </summary>
public class MusicAlbumDynamicInfoProvider : BaseMetadataProvider, IDynamicInfoProvider
{
/// <summary>
/// Initializes a new instance of the <see cref="BaseMetadataProvider" /> class.
/// </summary>
/// <param name="logManager">The log manager.</param>
/// <param name="configurationManager">The configuration manager.</param>
public MusicAlbumDynamicInfoProvider(ILogManager logManager, IServerConfigurationManager configurationManager)
: base(logManager, configurationManager)
{
}
/// <summary>
/// Supportses the specified item.
/// </summary>
/// <param name="item">The item.</param>
/// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns>
public override bool Supports(BaseItem item)
{
return item is MusicAlbum;
}
/// <summary>
/// Needses the refresh internal.
/// </summary>
/// <param name="item">The item.</param>
/// <param name="providerInfo">The provider info.</param>
/// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns>
protected override bool NeedsRefreshInternal(BaseItem item, BaseProviderInfo providerInfo)
{
return true;
}
/// <summary>
/// Fetches metadata and returns true or false indicating if any work that requires persistence was done
/// </summary>
/// <param name="item">The item.</param>
/// <param name="force">if set to <c>true</c> [force].</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task{System.Boolean}.</returns>
public override Task<bool> FetchAsync(BaseItem item, bool force, CancellationToken cancellationToken)
{
var album = (MusicAlbum)item;
var songs = album.RecursiveChildren
.OfType<Audio>()
.ToList();
album.AlbumArtist = songs
.Select(i => i.AlbumArtist)
.FirstOrDefault(i => !string.IsNullOrEmpty(i));
album.Artists = songs.SelectMany(i => i.Artists)
.Distinct(StringComparer.OrdinalIgnoreCase)
.ToArray();
// Don't save to the db
return FalseTaskResult;
}
/// <summary>
/// Gets the priority.
/// </summary>
/// <value>The priority.</value>
public override MetadataProviderPriority Priority
{
get { return MetadataProviderPriority.Last; }
}
}
}