persist provider results

pull/702/head
Luke Pulverenti 10 years ago
parent d864ed87f5
commit 81d5e9f808

@ -364,11 +364,16 @@ namespace MediaBrowser.Controller.Entities
}
}
private string _forcedSortName;
/// <summary>
/// Gets or sets the name of the forced sort.
/// </summary>
/// <value>The name of the forced sort.</value>
public string ForcedSortName { get; set; }
public string ForcedSortName
{
get { return _forcedSortName; }
set { _forcedSortName = value; _sortName = null; }
}
private string _sortName;
/// <summary>

@ -146,13 +146,15 @@
<Compile Include="Providers\IDynamicInfoProvider.cs" />
<Compile Include="Providers\IHasMetadata.cs" />
<Compile Include="Providers\IImageProvider.cs" />
<Compile Include="Providers\IProviderRepository.cs" />
<Compile Include="Providers\IRemoteImageProvider.cs" />
<Compile Include="Providers\ILocalImageProvider.cs" />
<Compile Include="Providers\IMetadataProvider.cs" />
<Compile Include="Providers\IMetadataService.cs" />
<Compile Include="Providers\ItemId.cs" />
<Compile Include="Providers\MetadataRefreshOptions.cs" />
<Compile Include="Providers\NameParser.cs" />
<Compile Include="Providers\ProviderResult.cs" />
<Compile Include="Providers\MetadataStatus.cs" />
<Compile Include="Session\ISessionManager.cs" />
<Compile Include="Drawing\ImageExtensions.cs" />
<Compile Include="Entities\AggregateFolder.cs" />

@ -1,5 +1,4 @@
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Entities;
using System;
using System.Collections.Generic;
@ -112,22 +111,6 @@ namespace MediaBrowser.Controller.Persistence
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task.</returns>
Task SaveMediaStreams(Guid id, IEnumerable<MediaStream> streams, CancellationToken cancellationToken);
/// <summary>
/// Gets the provider history.
/// </summary>
/// <param name="itemId">The item identifier.</param>
/// <returns>IEnumerable{BaseProviderInfo}.</returns>
IEnumerable<BaseProviderInfo> GetProviderHistory(Guid itemId);
/// <summary>
/// Saves the provider history.
/// </summary>
/// <param name="id">The identifier.</param>
/// <param name="history">The history.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task.</returns>
Task SaveProviderHistory(Guid id, IEnumerable<BaseProviderInfo> history, CancellationToken cancellationToken);
}
}

@ -1,6 +1,4 @@
using MediaBrowser.Model.Entities;
using System;
using System.Collections.Generic;
using System;
using System.Threading;
using System.Threading.Tasks;
@ -52,21 +50,14 @@ namespace MediaBrowser.Controller.Providers
public interface IHasChangeMonitor
{
/// <summary>
/// Determines whether the specified date has changed.
/// Determines whether the specified item has changed.
/// </summary>
/// <param name="item">The item.</param>
/// <param name="date">The date.</param>
/// <returns><c>true</c> if the specified date has changed; otherwise, <c>false</c>.</returns>
/// <returns><c>true</c> if the specified item has changed; otherwise, <c>false</c>.</returns>
bool HasChanged(IHasMetadata item, DateTime date);
}
public enum MetadataProviderType
{
Embedded = 0,
Local = 1,
Remote = 2
}
public class MetadataResult<T>
where T : IHasMetadata
{
@ -74,17 +65,4 @@ namespace MediaBrowser.Controller.Providers
public T Item { get; set; }
}
public class ItemId : IHasProviderIds
{
public string Name { get; set; }
public string MetadataLanguage { get; set; }
public string MetadataCountryCode { get; set; }
public Dictionary<string, string> ProviderIds { get; set; }
public ItemId()
{
ProviderIds = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
}
}
}

@ -0,0 +1,48 @@
using MediaBrowser.Controller.Persistence;
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
namespace MediaBrowser.Controller.Providers
{
public interface IProviderRepository : IRepository
{
/// <summary>
/// Gets the provider history.
/// </summary>
/// <param name="itemId">The item identifier.</param>
/// <returns>IEnumerable{BaseProviderInfo}.</returns>
IEnumerable<BaseProviderInfo> GetProviderHistory(Guid itemId);
/// <summary>
/// Saves the provider history.
/// </summary>
/// <param name="id">The identifier.</param>
/// <param name="history">The history.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task.</returns>
Task SaveProviderHistory(Guid id, IEnumerable<BaseProviderInfo> history, CancellationToken cancellationToken);
/// <summary>
/// Gets the metadata status.
/// </summary>
/// <param name="itemId">The item identifier.</param>
/// <returns>MetadataStatus.</returns>
MetadataStatus GetMetadataStatus(Guid itemId);
/// <summary>
/// Saves the metadata status.
/// </summary>
/// <param name="status">The status.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task.</returns>
Task SaveMetadataStatus(MetadataStatus status, CancellationToken cancellationToken);
/// <summary>
/// Initializes this instance.
/// </summary>
/// <returns>Task.</returns>
Task Initialize();
}
}

@ -0,0 +1,35 @@
using MediaBrowser.Model.Entities;
using System;
using System.Collections.Generic;
namespace MediaBrowser.Controller.Providers
{
public class ItemId : IHasProviderIds
{
/// <summary>
/// Gets or sets the name.
/// </summary>
/// <value>The name.</value>
public string Name { get; set; }
/// <summary>
/// Gets or sets the metadata language.
/// </summary>
/// <value>The metadata language.</value>
public string MetadataLanguage { get; set; }
/// <summary>
/// Gets or sets the metadata country code.
/// </summary>
/// <value>The metadata country code.</value>
public string MetadataCountryCode { get; set; }
/// <summary>
/// Gets or sets the provider ids.
/// </summary>
/// <value>The provider ids.</value>
public Dictionary<string, string> ProviderIds { get; set; }
public ItemId()
{
ProviderIds = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
}
}
}

@ -0,0 +1,122 @@
using System;
using System.Collections.Generic;
using System.Linq;
using MediaBrowser.Common.Extensions;
namespace MediaBrowser.Controller.Providers
{
public class MetadataStatus
{
/// <summary>
/// Gets or sets the item identifier.
/// </summary>
/// <value>The item identifier.</value>
public Guid ItemId { get; set; }
/// <summary>
/// Gets or sets the date last metadata refresh.
/// </summary>
/// <value>The date last metadata refresh.</value>
public DateTime? DateLastMetadataRefresh { get; set; }
/// <summary>
/// Gets or sets the date last images refresh.
/// </summary>
/// <value>The date last images refresh.</value>
public DateTime? DateLastImagesRefresh { get; set; }
/// <summary>
/// Gets or sets the last result.
/// </summary>
/// <value>The last result.</value>
public ProviderRefreshStatus LastStatus { get; set; }
/// <summary>
/// Gets or sets the last result error message.
/// </summary>
/// <value>The last result error message.</value>
public string LastErrorMessage { get; set; }
/// <summary>
/// Gets or sets the providers refreshed.
/// </summary>
/// <value>The providers refreshed.</value>
public List<Guid> MetadataProvidersRefreshed { get; set; }
public List<Guid> ImageProvidersRefreshed { get; set; }
public void AddStatus(ProviderRefreshStatus status, string errorMessage)
{
if (LastStatus != status)
{
IsDirty = true;
}
if (string.IsNullOrEmpty(LastErrorMessage))
{
LastErrorMessage = errorMessage;
}
if (LastStatus == ProviderRefreshStatus.Success)
{
LastStatus = status;
}
}
public MetadataStatus()
{
LastStatus = ProviderRefreshStatus.Success;
MetadataProvidersRefreshed = new List<Guid>();
ImageProvidersRefreshed = new List<Guid>();
}
public bool IsDirty { get; private set; }
public void SetDateLastMetadataRefresh(DateTime date)
{
if (date != (DateLastMetadataRefresh ?? DateTime.MinValue))
{
IsDirty = true;
}
DateLastMetadataRefresh = date;
}
public void SetDateLastImagesRefresh(DateTime date)
{
if (date != (DateLastImagesRefresh ?? DateTime.MinValue))
{
IsDirty = true;
}
DateLastImagesRefresh = date;
}
public void AddImageProvidersRefreshed(List<Guid> providerIds)
{
var count = ImageProvidersRefreshed.Count;
providerIds.AddRange(ImageProvidersRefreshed);
ImageProvidersRefreshed = providerIds.Distinct().ToList();
if (ImageProvidersRefreshed.Count != count)
{
IsDirty = true;
}
}
public void AddMetadataProvidersRefreshed(List<Guid> providerIds)
{
var count = MetadataProvidersRefreshed.Count;
providerIds.AddRange(MetadataProvidersRefreshed);
MetadataProvidersRefreshed = providerIds.Distinct().ToList();
if (MetadataProvidersRefreshed.Count != count)
{
IsDirty = true;
}
}
}
}

@ -1,60 +0,0 @@
using System;
namespace MediaBrowser.Controller.Providers
{
public class ProviderResult
{
/// <summary>
/// Gets or sets the item identifier.
/// </summary>
/// <value>The item identifier.</value>
public Guid ItemId { get; set; }
/// <summary>
/// Gets or sets a value indicating whether this instance has refreshed metadata.
/// </summary>
/// <value><c>true</c> if this instance has refreshed metadata; otherwise, <c>false</c>.</value>
public bool HasRefreshedMetadata { get; set; }
/// <summary>
/// Gets or sets a value indicating whether this instance has refreshed images.
/// </summary>
/// <value><c>true</c> if this instance has refreshed images; otherwise, <c>false</c>.</value>
public bool HasRefreshedImages { get; set; }
/// <summary>
/// Gets or sets the date last refreshed.
/// </summary>
/// <value>The date last refreshed.</value>
public DateTime DateLastRefreshed { get; set; }
/// <summary>
/// Gets or sets the last result.
/// </summary>
/// <value>The last result.</value>
public ProviderRefreshStatus Status { get; set; }
/// <summary>
/// Gets or sets the last result error message.
/// </summary>
/// <value>The last result error message.</value>
public string ErrorMessage { get; set; }
public void AddStatus(ProviderRefreshStatus status, string errorMessage)
{
if (string.IsNullOrEmpty(ErrorMessage))
{
ErrorMessage = errorMessage;
}
if (Status == ProviderRefreshStatus.Success)
{
Status = status;
}
}
public ProviderResult()
{
Status = ProviderRefreshStatus.Success;
}
}
}

@ -15,8 +15,8 @@ namespace MediaBrowser.Providers.GameGenres
{
private readonly ILibraryManager _libraryManager;
public GameGenreMetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, ILibraryManager libraryManager)
: base(serverConfigurationManager, logger, providerManager)
public GameGenreMetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, IProviderRepository providerRepo, ILibraryManager libraryManager)
: base(serverConfigurationManager, logger, providerManager, providerRepo)
{
_libraryManager = libraryManager;
}

@ -15,8 +15,8 @@ namespace MediaBrowser.Providers.Genres
{
private readonly ILibraryManager _libraryManager;
public GenreMetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, ILibraryManager libraryManager)
: base(serverConfigurationManager, logger, providerManager)
public GenreMetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, IProviderRepository providerRepo, ILibraryManager libraryManager)
: base(serverConfigurationManager, logger, providerManager, providerRepo)
{
_libraryManager = libraryManager;
}

@ -1,4 +1,5 @@
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Common.Extensions;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Providers;
@ -51,16 +52,24 @@ namespace MediaBrowser.Providers.Manager
var providers = GetImageProviders(item, imageProviders).ToList();
var providerIds = new List<Guid>();
foreach (var provider in providers.OfType<IRemoteImageProvider>())
{
await RefreshFromProvider(item, provider, options, result, cancellationToken).ConfigureAwait(false);
providerIds.Add(provider.GetType().FullName.GetMD5());
}
foreach (var provider in providers.OfType<IDynamicImageProvider>())
{
await RefreshFromProvider(item, provider, result, cancellationToken).ConfigureAwait(false);
providerIds.Add(provider.GetType().FullName.GetMD5());
}
result.Providers = providerIds;
return result;
}

@ -1,4 +1,5 @@
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Common.Extensions;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Providers;
@ -18,16 +19,18 @@ namespace MediaBrowser.Providers.Manager
protected readonly IServerConfigurationManager ServerConfigurationManager;
protected readonly ILogger Logger;
protected readonly IProviderManager ProviderManager;
private readonly IProviderRepository _providerRepo;
private IMetadataProvider<TItemType>[] _providers = { };
private IImageProvider[] _imageProviders = { };
protected MetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager)
protected MetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, IProviderRepository providerRepo)
{
ServerConfigurationManager = serverConfigurationManager;
Logger = logger;
ProviderManager = providerManager;
_providerRepo = providerRepo;
}
/// <summary>
@ -48,9 +51,9 @@ namespace MediaBrowser.Providers.Manager
/// </summary>
/// <param name="result">The result.</param>
/// <returns>Task.</returns>
protected Task SaveProviderResult(ProviderResult result)
protected Task SaveProviderResult(MetadataStatus result)
{
return Task.FromResult(true);
return _providerRepo.SaveMetadataStatus(result, CancellationToken.None);
}
/// <summary>
@ -58,12 +61,9 @@ namespace MediaBrowser.Providers.Manager
/// </summary>
/// <param name="itemId">The item identifier.</param>
/// <returns>ProviderResult.</returns>
protected ProviderResult GetLastResult(Guid itemId)
protected MetadataStatus GetLastResult(Guid itemId)
{
return new ProviderResult
{
ItemId = itemId
};
return _providerRepo.GetMetadataStatus(itemId) ?? new MetadataStatus { ItemId = itemId };
}
public async Task RefreshMetadata(IHasMetadata item, MetadataRefreshOptions options, CancellationToken cancellationToken)
@ -72,7 +72,9 @@ namespace MediaBrowser.Providers.Manager
var updateType = ItemUpdateType.Unspecified;
var lastResult = GetLastResult(item.Id);
var refreshResult = new ProviderResult { ItemId = item.Id };
var refreshResult = lastResult;
refreshResult.LastErrorMessage = string.Empty;
refreshResult.LastStatus = ProviderRefreshStatus.Success;
var imageProviders = GetImageProviders(item).ToList();
var itemImageProvider = new ItemImageProvider(Logger, ProviderManager, ServerConfigurationManager);
@ -97,7 +99,7 @@ namespace MediaBrowser.Providers.Manager
// Next run metadata providers
if (options.MetadataRefreshMode != MetadataRefreshMode.None)
{
var providers = GetProviders(item, lastResult.HasRefreshedMetadata, options).ToList();
var providers = GetProviders(item, lastResult.DateLastMetadataRefresh.HasValue, options).ToList();
if (providers.Count > 0)
{
@ -105,22 +107,23 @@ namespace MediaBrowser.Providers.Manager
updateType = updateType | result.UpdateType;
refreshResult.AddStatus(result.Status, result.ErrorMessage);
refreshResult.SetDateLastMetadataRefresh(DateTime.UtcNow);
refreshResult.AddImageProvidersRefreshed(result.Providers);
}
refreshResult.HasRefreshedMetadata = true;
}
// Next run remote image providers, but only if local image providers didn't throw an exception
if (!localImagesFailed)
{
if ((options.ImageRefreshMode == MetadataRefreshMode.EnsureMetadata && !lastResult.HasRefreshedImages) ||
if ((options.ImageRefreshMode == MetadataRefreshMode.EnsureMetadata && !lastResult.DateLastImagesRefresh.HasValue) ||
options.ImageRefreshMode == MetadataRefreshMode.FullRefresh)
{
var imagesReult = await itemImageProvider.RefreshImages(itemOfType, imageProviders, options, cancellationToken).ConfigureAwait(false);
var result = await itemImageProvider.RefreshImages(itemOfType, imageProviders, options, cancellationToken).ConfigureAwait(false);
updateType = updateType | imagesReult.UpdateType;
refreshResult.AddStatus(imagesReult.Status, imagesReult.ErrorMessage);
refreshResult.HasRefreshedImages = true;
updateType = updateType | result.UpdateType;
refreshResult.AddStatus(result.Status, result.ErrorMessage);
refreshResult.SetDateLastImagesRefresh(DateTime.UtcNow);
refreshResult.AddImageProvidersRefreshed(result.Providers);
}
}
@ -137,9 +140,8 @@ namespace MediaBrowser.Providers.Manager
await SaveItem(itemOfType, updateType, cancellationToken);
}
if (providersHadChanges)
if (providersHadChanges || refreshResult.IsDirty)
{
refreshResult.DateLastRefreshed = DateTime.UtcNow;
await SaveProviderResult(refreshResult).ConfigureAwait(false);
}
}
@ -165,7 +167,7 @@ namespace MediaBrowser.Providers.Manager
var currentItem = item;
var providersWithChanges = providers.OfType<IHasChangeMonitor>()
.Where(i => i.HasChanged(currentItem, item.DateLastSaved))
.Where(i => i.HasChanged(currentItem, currentItem.DateLastSaved))
.ToList();
// If local providers are the only ones with changes, then just run those
@ -219,7 +221,11 @@ namespace MediaBrowser.Providers.Manager
protected virtual async Task<RefreshResult> RefreshWithProviders(TItemType item, MetadataRefreshOptions options, List<IMetadataProvider> providers, CancellationToken cancellationToken)
{
var refreshResult = new RefreshResult { UpdateType = ItemUpdateType.Unspecified };
var refreshResult = new RefreshResult
{
UpdateType = ItemUpdateType.Unspecified,
Providers = providers.Select(i => i.GetType().FullName.GetMD5()).ToList()
};
var temp = new TItemType();
@ -347,5 +353,6 @@ namespace MediaBrowser.Providers.Manager
public ItemUpdateType UpdateType { get; set; }
public ProviderRefreshStatus Status { get; set; }
public string ErrorMessage { get; set; }
public List<Guid> Providers { get; set; }
}
}

@ -55,7 +55,7 @@ namespace MediaBrowser.Providers.Manager
private readonly IFileSystem _fileSystem;
private readonly IItemRepository _itemRepo;
private readonly IProviderRepository _providerRepo;
private IMetadataService[] _metadataServices = { };
@ -67,15 +67,15 @@ namespace MediaBrowser.Providers.Manager
/// <param name="libraryMonitor">The directory watchers.</param>
/// <param name="logManager">The log manager.</param>
/// <param name="fileSystem">The file system.</param>
/// <param name="itemRepo">The item repo.</param>
public ProviderManager(IHttpClient httpClient, IServerConfigurationManager configurationManager, ILibraryMonitor libraryMonitor, ILogManager logManager, IFileSystem fileSystem, IItemRepository itemRepo)
/// <param name="providerRepo">The provider repo.</param>
public ProviderManager(IHttpClient httpClient, IServerConfigurationManager configurationManager, ILibraryMonitor libraryMonitor, ILogManager logManager, IFileSystem fileSystem, IProviderRepository providerRepo)
{
_logger = logManager.GetLogger("ProviderManager");
_httpClient = httpClient;
ConfigurationManager = configurationManager;
_libraryMonitor = libraryMonitor;
_fileSystem = fileSystem;
_itemRepo = itemRepo;
_providerRepo = providerRepo;
}
/// <summary>
@ -136,7 +136,7 @@ namespace MediaBrowser.Providers.Manager
var providerHistories = item.DateLastSaved == default(DateTime) ?
new List<BaseProviderInfo>() :
_itemRepo.GetProviderHistory(item.Id).ToList();
_providerRepo.GetProviderHistory(item.Id).ToList();
// Run the normal providers sequentially in order of priority
foreach (var provider in MetadataProviders)
@ -201,7 +201,7 @@ namespace MediaBrowser.Providers.Manager
if (result.HasValue || force)
{
await _itemRepo.SaveProviderHistory(item.Id, providerHistories, cancellationToken);
await _providerRepo.SaveProviderHistory(item.Id, providerHistories, cancellationToken);
}
return result;

@ -15,8 +15,8 @@ namespace MediaBrowser.Providers.MusicGenres
{
private readonly ILibraryManager _libraryManager;
public MusicGenreMetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, ILibraryManager libraryManager)
: base(serverConfigurationManager, logger, providerManager)
public MusicGenreMetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, IProviderRepository providerRepo, ILibraryManager libraryManager)
: base(serverConfigurationManager, logger, providerManager, providerRepo)
{
_libraryManager = libraryManager;
}

@ -15,8 +15,8 @@ namespace MediaBrowser.Providers.People
{
private readonly ILibraryManager _libraryManager;
public PersonMetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, ILibraryManager libraryManager)
: base(serverConfigurationManager, logger, providerManager)
public PersonMetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, IProviderRepository providerRepo, ILibraryManager libraryManager)
: base(serverConfigurationManager, logger, providerManager, providerRepo)
{
_libraryManager = libraryManager;
}

@ -15,8 +15,8 @@ namespace MediaBrowser.Providers.Studios
{
private readonly ILibraryManager _libraryManager;
public StudioMetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, ILibraryManager libraryManager)
: base(serverConfigurationManager, logger, providerManager)
public StudioMetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, IProviderRepository providerRepo, ILibraryManager libraryManager)
: base(serverConfigurationManager, logger, providerManager, providerRepo)
{
_libraryManager = libraryManager;
}

@ -56,21 +56,6 @@ namespace MediaBrowser.Server.Implementations.IO
_tempIgnoredPaths[path] = path;
}
/// <summary>
/// Removes the temp ignore.
/// </summary>
/// <param name="path">The path.</param>
private async void RemoveTempIgnore(string path)
{
// This is an arbitraty amount of time, but delay it because file system writes often trigger events after RemoveTempIgnore has been called.
// Seeing long delays in some situations, especially over the network.
// Seeing delays up to 40 seconds, but not going to ignore changes for that long.
await Task.Delay(1500).ConfigureAwait(false);
string val;
_tempIgnoredPaths.TryRemove(path, out val);
}
public void ReportFileSystemChangeBeginning(string path)
{
if (string.IsNullOrEmpty(path))
@ -81,14 +66,20 @@ namespace MediaBrowser.Server.Implementations.IO
TemporarilyIgnore(path);
}
public void ReportFileSystemChangeComplete(string path, bool refreshPath)
public async void ReportFileSystemChangeComplete(string path, bool refreshPath)
{
if (string.IsNullOrEmpty(path))
{
throw new ArgumentNullException("path");
}
RemoveTempIgnore(path);
// This is an arbitraty amount of time, but delay it because file system writes often trigger events after RemoveTempIgnore has been called.
// Seeing long delays in some situations, especially over the network.
// Seeing delays up to 40 seconds, but not going to ignore changes for that long.
await Task.Delay(1500).ConfigureAwait(false);
string val;
_tempIgnoredPaths.TryRemove(path, out val);
if (refreshPath)
{

@ -58,7 +58,6 @@ namespace MediaBrowser.Server.Implementations.Persistence
private SqliteChapterRepository _chapterRepository;
private SqliteMediaStreamsRepository _mediaStreamsRepository;
private SqliteProviderInfoRepository _providerInfoRepository;
private IDbCommand _deleteChildrenCommand;
private IDbCommand _saveChildrenCommand;
@ -99,10 +98,6 @@ namespace MediaBrowser.Server.Implementations.Persistence
var mediaStreamsDbFile = Path.Combine(_appPaths.DataPath, "mediainfo.db");
var mediaStreamsConnection = SqliteExtensions.ConnectToDb(mediaStreamsDbFile, _logger).Result;
_mediaStreamsRepository = new SqliteMediaStreamsRepository(mediaStreamsConnection, logManager);
var providerInfosDbFile = Path.Combine(_appPaths.DataPath, "providerinfo.db");
var providerInfoConnection = SqliteExtensions.ConnectToDb(providerInfosDbFile, _logger).Result;
_providerInfoRepository = new SqliteProviderInfoRepository(providerInfoConnection, logManager);
}
/// <summary>
@ -134,7 +129,6 @@ namespace MediaBrowser.Server.Implementations.Persistence
PrepareStatements();
_mediaStreamsRepository.Initialize();
_providerInfoRepository.Initialize();
_chapterRepository.Initialize();
_shrinkMemoryTimer = new SqliteShrinkMemoryTimer(_connection, _writeLock, _logger);
@ -436,12 +430,6 @@ namespace MediaBrowser.Server.Implementations.Persistence
_mediaStreamsRepository.Dispose();
_mediaStreamsRepository = null;
}
if (_providerInfoRepository != null)
{
_providerInfoRepository.Dispose();
_providerInfoRepository = null;
}
}
}
catch (Exception ex)
@ -556,15 +544,5 @@ namespace MediaBrowser.Server.Implementations.Persistence
{
return _mediaStreamsRepository.SaveMediaStreams(id, streams, cancellationToken);
}
public IEnumerable<BaseProviderInfo> GetProviderHistory(Guid itemId)
{
return _providerInfoRepository.GetBaseProviderInfos(itemId);
}
public Task SaveProviderHistory(Guid id, IEnumerable<BaseProviderInfo> history, CancellationToken cancellationToken)
{
return _providerInfoRepository.SaveProviderInfos(id, history, cancellationToken);
}
}
}

@ -1,4 +1,6 @@
using MediaBrowser.Controller.Providers;
using System.IO;
using MediaBrowser.Common.Configuration;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Logging;
using System;
using System.Collections.Generic;
@ -9,7 +11,7 @@ using System.Threading.Tasks;
namespace MediaBrowser.Server.Implementations.Persistence
{
class SqliteProviderInfoRepository
public class SqliteProviderInfoRepository : IProviderRepository
{
private IDbConnection _connection;
@ -17,32 +19,47 @@ namespace MediaBrowser.Server.Implementations.Persistence
private IDbCommand _deleteInfosCommand;
private IDbCommand _saveInfoCommand;
private IDbCommand _saveStatusCommand;
private readonly IApplicationPaths _appPaths;
public SqliteProviderInfoRepository(IDbConnection connection, ILogManager logManager)
public SqliteProviderInfoRepository(IApplicationPaths appPaths, ILogManager logManager)
{
_connection = connection;
_appPaths = appPaths;
_logger = logManager.GetLogger(GetType().Name);
}
private SqliteShrinkMemoryTimer _shrinkMemoryTimer;
/// <summary>
/// Gets the name of the repository
/// </summary>
/// <value>The name.</value>
public string Name
{
get
{
return "SQLite";
}
}
/// <summary>
/// Opens the connection to the database
/// </summary>
/// <returns>Task.</returns>
public void Initialize()
public async Task Initialize()
{
var createTableCommand
= "create table if not exists providerinfos ";
var dbFile = Path.Combine(_appPaths.DataPath, "providerinfo.db");
createTableCommand += "(ItemId GUID, ProviderId GUID, ProviderVersion TEXT, FileStamp GUID, LastRefreshStatus TEXT, LastRefreshed datetime, PRIMARY KEY (ItemId, ProviderId))";
_connection = await SqliteExtensions.ConnectToDb(dbFile, _logger).ConfigureAwait(false);
string[] queries = {
createTableCommand,
"create table if not exists providerinfos (ItemId GUID, ProviderId GUID, ProviderVersion TEXT, FileStamp GUID, LastRefreshStatus TEXT, LastRefreshed datetime, PRIMARY KEY (ItemId, ProviderId))",
"create index if not exists idx_providerinfos on providerinfos(ItemId, ProviderId)",
"create table if not exists MetadataStatus (ItemId GUID PRIMARY KEY, DateLastMetadataRefresh datetime, DateLastImagesRefresh datetime, LastStatus TEXT, LastErrorMessage TEXT, MetadataProvidersRefreshed TEXT, ImageProvidersRefreshed TEXT)",
"create index if not exists idx_MetadataStatus on MetadataStatus(ItemId)",
//pragmas
"pragma temp_store = memory",
@ -56,7 +73,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
_shrinkMemoryTimer = new SqliteShrinkMemoryTimer(_connection, _writeLock, _logger);
}
private static readonly string[] SaveColumns =
private static readonly string[] SaveHistoryColumns =
{
"ItemId",
"ProviderId",
@ -66,7 +83,18 @@ namespace MediaBrowser.Server.Implementations.Persistence
"LastRefreshed"
};
private readonly string[] _selectColumns = SaveColumns.Skip(1).ToArray();
private readonly string[] _historySelectColumns = SaveHistoryColumns.Skip(1).ToArray();
private static readonly string[] StatusColumns =
{
"ItemId",
"DateLastMetadataRefresh",
"DateLastImagesRefresh",
"LastStatus",
"LastErrorMessage",
"MetadataProvidersRefreshed",
"ImageProvidersRefreshed"
};
/// <summary>
/// The _write lock
@ -85,16 +113,27 @@ namespace MediaBrowser.Server.Implementations.Persistence
_saveInfoCommand = _connection.CreateCommand();
_saveInfoCommand.CommandText = string.Format("replace into providerinfos ({0}) values ({1})",
string.Join(",", SaveColumns),
string.Join(",", SaveColumns.Select(i => "@" + i).ToArray()));
string.Join(",", SaveHistoryColumns),
string.Join(",", SaveHistoryColumns.Select(i => "@" + i).ToArray()));
foreach (var col in SaveColumns)
foreach (var col in SaveHistoryColumns)
{
_saveInfoCommand.Parameters.Add(_saveInfoCommand, "@" + col);
}
_saveStatusCommand = _connection.CreateCommand();
_saveStatusCommand.CommandText = string.Format("replace into MetadataStatus ({0}) values ({1})",
string.Join(",", StatusColumns),
string.Join(",", StatusColumns.Select(i => "@" + i).ToArray()));
foreach (var col in StatusColumns)
{
_saveStatusCommand.Parameters.Add(_saveStatusCommand, "@" + col);
}
}
public IEnumerable<BaseProviderInfo> GetBaseProviderInfos(Guid itemId)
public IEnumerable<BaseProviderInfo> GetProviderHistory(Guid itemId)
{
if (itemId == Guid.Empty)
{
@ -103,7 +142,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
using (var cmd = _connection.CreateCommand())
{
var cmdText = "select " + string.Join(",", _selectColumns) + " from providerinfos where";
var cmdText = "select " + string.Join(",", _historySelectColumns) + " from providerinfos where";
cmdText += " ItemId=@ItemId";
cmd.Parameters.Add(cmd, "@ItemId", DbType.Guid).Value = itemId;
@ -121,10 +160,10 @@ namespace MediaBrowser.Server.Implementations.Persistence
}
/// <summary>
/// Gets the chapter.
/// Gets the base provider information.
/// </summary>
/// <param name="reader">The reader.</param>
/// <returns>ChapterInfo.</returns>
/// <returns>BaseProviderInfo.</returns>
private BaseProviderInfo GetBaseProviderInfo(IDataReader reader)
{
var item = new BaseProviderInfo
@ -144,7 +183,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
return item;
}
public async Task SaveProviderInfos(Guid id, IEnumerable<BaseProviderInfo> infos, CancellationToken cancellationToken)
public async Task SaveProviderHistory(Guid id, IEnumerable<BaseProviderInfo> infos, CancellationToken cancellationToken)
{
if (id == Guid.Empty)
{
@ -166,7 +205,6 @@ namespace MediaBrowser.Server.Implementations.Persistence
{
transaction = _connection.BeginTransaction();
// First delete chapters
_deleteInfosCommand.GetParameter(0).Value = id;
_deleteInfosCommand.Transaction = transaction;
@ -221,6 +259,136 @@ namespace MediaBrowser.Server.Implementations.Persistence
}
}
public MetadataStatus GetMetadataStatus(Guid itemId)
{
if (itemId == Guid.Empty)
{
throw new ArgumentNullException("itemId");
}
using (var cmd = _connection.CreateCommand())
{
var cmdText = "select " + string.Join(",", StatusColumns) + " from MetadataStatus where";
cmdText += " ItemId=@ItemId";
cmd.Parameters.Add(cmd, "@ItemId", DbType.Guid).Value = itemId;
cmd.CommandText = cmdText;
using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult | CommandBehavior.SingleRow))
{
while (reader.Read())
{
return GetStatus(reader);
}
return null;
}
}
}
private MetadataStatus GetStatus(IDataReader reader)
{
var result = new MetadataStatus
{
ItemId = reader.GetGuid(0)
};
if (!reader.IsDBNull(1))
{
result.DateLastMetadataRefresh = reader.GetDateTime(1).ToUniversalTime();
}
if (!reader.IsDBNull(2))
{
result.DateLastImagesRefresh = reader.GetDateTime(2).ToUniversalTime();
}
if (!reader.IsDBNull(3))
{
result.LastStatus = (ProviderRefreshStatus)Enum.Parse(typeof(ProviderRefreshStatus), reader.GetString(3), true);
}
if (!reader.IsDBNull(4))
{
result.LastErrorMessage = reader.GetString(4);
}
if (!reader.IsDBNull(5))
{
result.MetadataProvidersRefreshed = reader.GetString(5).Split('|').Where(i => !string.IsNullOrEmpty(i)).Select(i => new Guid(i)).ToList();
}
if (!reader.IsDBNull(6))
{
result.ImageProvidersRefreshed = reader.GetString(6).Split('|').Where(i => !string.IsNullOrEmpty(i)).Select(i => new Guid(i)).ToList();
}
return result;
}
public async Task SaveMetadataStatus(MetadataStatus status, CancellationToken cancellationToken)
{
if (status == null)
{
throw new ArgumentNullException("status");
}
cancellationToken.ThrowIfCancellationRequested();
await _writeLock.WaitAsync(cancellationToken).ConfigureAwait(false);
IDbTransaction transaction = null;
try
{
transaction = _connection.BeginTransaction();
_saveStatusCommand.GetParameter(0).Value = status.ItemId;
_saveStatusCommand.GetParameter(1).Value = status.DateLastMetadataRefresh;
_saveStatusCommand.GetParameter(2).Value = status.DateLastImagesRefresh;
_saveStatusCommand.GetParameter(3).Value = status.LastStatus.ToString();
_saveStatusCommand.GetParameter(4).Value = status.LastErrorMessage;
_saveStatusCommand.GetParameter(5).Value = string.Join("|", status.MetadataProvidersRefreshed.ToArray());
_saveStatusCommand.GetParameter(6).Value = string.Join("|", status.ImageProvidersRefreshed.ToArray());
_saveStatusCommand.Transaction = transaction;
_saveStatusCommand.ExecuteNonQuery();
transaction.Commit();
}
catch (OperationCanceledException)
{
if (transaction != null)
{
transaction.Rollback();
}
throw;
}
catch (Exception e)
{
_logger.ErrorException("Failed to save provider info:", e);
if (transaction != null)
{
transaction.Rollback();
}
throw;
}
finally
{
if (transaction != null)
{
transaction.Dispose();
}
_writeLock.Release();
}
}
/// <summary>
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
/// </summary>

@ -14,7 +14,6 @@ using MediaBrowser.Controller.Drawing;
using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.FileOrganization;
using MediaBrowser.Controller.IO;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.LiveTv;
using MediaBrowser.Controller.Localization;
@ -173,6 +172,7 @@ namespace MediaBrowser.ServerApplication
internal IItemRepository ItemRepository { get; set; }
private INotificationsRepository NotificationsRepository { get; set; }
private IFileOrganizationRepository FileOrganizationRepository { get; set; }
private IProviderRepository ProviderRepository { get; set; }
/// <summary>
/// Initializes a new instance of the <see cref="ApplicationHost"/> class.
@ -267,6 +267,9 @@ namespace MediaBrowser.ServerApplication
ItemRepository = new SqliteItemRepository(ApplicationPaths, JsonSerializer, LogManager);
RegisterSingleInstance(ItemRepository);
ProviderRepository = new SqliteProviderInfoRepository(ApplicationPaths, LogManager);
RegisterSingleInstance(ProviderRepository);
FileOrganizationRepository = await GetFileOrganizationRepository().ConfigureAwait(false);
RegisterSingleInstance(FileOrganizationRepository);
@ -279,7 +282,7 @@ namespace MediaBrowser.ServerApplication
LibraryMonitor = new LibraryMonitor(LogManager, TaskManager, LibraryManager, ServerConfigurationManager, FileSystemManager);
RegisterSingleInstance(LibraryMonitor);
ProviderManager = new ProviderManager(HttpClient, ServerConfigurationManager, LibraryMonitor, LogManager, FileSystemManager, ItemRepository);
ProviderManager = new ProviderManager(HttpClient, ServerConfigurationManager, LibraryMonitor, LogManager, FileSystemManager, ProviderRepository);
RegisterSingleInstance(ProviderManager);
RegisterSingleInstance<ISearchEngine>(() => new SearchEngine(LogManager, LibraryManager, UserManager));
@ -427,6 +430,8 @@ namespace MediaBrowser.ServerApplication
{
await ItemRepository.Initialize().ConfigureAwait(false);
await ProviderRepository.Initialize().ConfigureAwait(false);
((LibraryManager)LibraryManager).ItemRepository = ItemRepository;
}

Loading…
Cancel
Save