Re-designed item identity providers
This commit is contained in:
parent
c3d6c19cc3
commit
556b34d000
|
@ -38,7 +38,6 @@ namespace MediaBrowser.Controller.Entities
|
||||||
ProviderIds = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
ProviderIds = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
||||||
LockedFields = new List<MetadataFields>();
|
LockedFields = new List<MetadataFields>();
|
||||||
ImageInfos = new List<ItemImageInfo>();
|
ImageInfos = new List<ItemImageInfo>();
|
||||||
Identities = new List<IItemIdentity>();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -337,9 +336,6 @@ namespace MediaBrowser.Controller.Entities
|
||||||
|
|
||||||
public bool IsUnidentified { get; set; }
|
public bool IsUnidentified { get; set; }
|
||||||
|
|
||||||
[IgnoreDataMember]
|
|
||||||
public List<IItemIdentity> Identities { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the locked fields.
|
/// Gets or sets the locked fields.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -50,11 +50,6 @@ namespace MediaBrowser.Controller.Entities
|
||||||
/// <value><c>true</c> if this instance is unidentified; otherwise, <c>false</c>.</value>
|
/// <value><c>true</c> if this instance is unidentified; otherwise, <c>false</c>.</value>
|
||||||
bool IsUnidentified { get; set; }
|
bool IsUnidentified { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the item identities.
|
|
||||||
/// </summary>
|
|
||||||
List<IItemIdentity> Identities { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Afters the metadata refresh.
|
/// Afters the metadata refresh.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -268,7 +268,6 @@
|
||||||
<Compile Include="Providers\DirectoryService.cs" />
|
<Compile Include="Providers\DirectoryService.cs" />
|
||||||
<Compile Include="Providers\DynamicImageInfo.cs" />
|
<Compile Include="Providers\DynamicImageInfo.cs" />
|
||||||
<Compile Include="Providers\DynamicImageResponse.cs" />
|
<Compile Include="Providers\DynamicImageResponse.cs" />
|
||||||
<Compile Include="Providers\EpisodeIdentity.cs" />
|
|
||||||
<Compile Include="Providers\EpisodeInfo.cs" />
|
<Compile Include="Providers\EpisodeInfo.cs" />
|
||||||
<Compile Include="Providers\ExtraInfo.cs" />
|
<Compile Include="Providers\ExtraInfo.cs" />
|
||||||
<Compile Include="Providers\ExtraSource.cs" />
|
<Compile Include="Providers\ExtraSource.cs" />
|
||||||
|
@ -282,14 +281,12 @@
|
||||||
<Compile Include="Providers\IForcedProvider.cs" />
|
<Compile Include="Providers\IForcedProvider.cs" />
|
||||||
<Compile Include="Providers\IHasChangeMonitor.cs" />
|
<Compile Include="Providers\IHasChangeMonitor.cs" />
|
||||||
<Compile Include="Entities\IHasMetadata.cs" />
|
<Compile Include="Entities\IHasMetadata.cs" />
|
||||||
<Compile Include="Providers\IHasIdentities.cs" />
|
|
||||||
<Compile Include="Providers\IHasItemChangeMonitor.cs" />
|
<Compile Include="Providers\IHasItemChangeMonitor.cs" />
|
||||||
<Compile Include="Providers\IHasLookupInfo.cs" />
|
<Compile Include="Providers\IHasLookupInfo.cs" />
|
||||||
<Compile Include="Providers\IHasOrder.cs" />
|
<Compile Include="Providers\IHasOrder.cs" />
|
||||||
<Compile Include="Providers\IImageFileSaver.cs" />
|
<Compile Include="Providers\IImageFileSaver.cs" />
|
||||||
<Compile Include="Providers\IImageProvider.cs" />
|
<Compile Include="Providers\IImageProvider.cs" />
|
||||||
<Compile Include="Providers\IImageSaver.cs" />
|
<Compile Include="Providers\IImageSaver.cs" />
|
||||||
<Compile Include="Providers\IItemIdentity.cs" />
|
|
||||||
<Compile Include="Providers\IItemIdentityConverter.cs" />
|
<Compile Include="Providers\IItemIdentityConverter.cs" />
|
||||||
<Compile Include="Providers\IItemIdentityProvider.cs" />
|
<Compile Include="Providers\IItemIdentityProvider.cs" />
|
||||||
<Compile Include="Providers\ILocalImageFileProvider.cs" />
|
<Compile Include="Providers\ILocalImageFileProvider.cs" />
|
||||||
|
@ -314,9 +311,7 @@
|
||||||
<Compile Include="Providers\MusicVideoInfo.cs" />
|
<Compile Include="Providers\MusicVideoInfo.cs" />
|
||||||
<Compile Include="Providers\PersonLookupInfo.cs" />
|
<Compile Include="Providers\PersonLookupInfo.cs" />
|
||||||
<Compile Include="Providers\RemoteSearchQuery.cs" />
|
<Compile Include="Providers\RemoteSearchQuery.cs" />
|
||||||
<Compile Include="Providers\SeasonIdentity.cs" />
|
|
||||||
<Compile Include="Providers\SeasonInfo.cs" />
|
<Compile Include="Providers\SeasonInfo.cs" />
|
||||||
<Compile Include="Providers\SeriesIdentity.cs" />
|
|
||||||
<Compile Include="Providers\SeriesInfo.cs" />
|
<Compile Include="Providers\SeriesInfo.cs" />
|
||||||
<Compile Include="Providers\SeriesOrderTypes.cs" />
|
<Compile Include="Providers\SeriesOrderTypes.cs" />
|
||||||
<Compile Include="Providers\SongInfo.cs" />
|
<Compile Include="Providers\SongInfo.cs" />
|
||||||
|
|
|
@ -1,12 +0,0 @@
|
||||||
namespace MediaBrowser.Controller.Providers
|
|
||||||
{
|
|
||||||
public class EpisodeIdentity : IItemIdentity
|
|
||||||
{
|
|
||||||
public string Type { get; set; }
|
|
||||||
|
|
||||||
public string SeriesId { get; set; }
|
|
||||||
public int? SeasonIndex { get; set; }
|
|
||||||
public int IndexNumber { get; set; }
|
|
||||||
public int? IndexNumberEnd { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,15 +1,10 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
|
||||||
using System.Threading;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace MediaBrowser.Controller.Providers
|
namespace MediaBrowser.Controller.Providers
|
||||||
{
|
{
|
||||||
public class EpisodeInfo : ItemLookupInfo, IHasIdentities<EpisodeIdentity>
|
public class EpisodeInfo : ItemLookupInfo
|
||||||
{
|
{
|
||||||
private List<EpisodeIdentity> _identities = new List<EpisodeIdentity>();
|
|
||||||
|
|
||||||
public Dictionary<string, string> SeriesProviderIds { get; set; }
|
public Dictionary<string, string> SeriesProviderIds { get; set; }
|
||||||
|
|
||||||
public int? IndexNumberEnd { get; set; }
|
public int? IndexNumberEnd { get; set; }
|
||||||
|
@ -19,16 +14,5 @@ namespace MediaBrowser.Controller.Providers
|
||||||
{
|
{
|
||||||
SeriesProviderIds = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
SeriesProviderIds = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerable<EpisodeIdentity> Identities
|
|
||||||
{
|
|
||||||
get { return _identities; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task FindIdentities(IProviderManager providerManager, CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
var identifier = new ItemIdentifier<EpisodeInfo, EpisodeIdentity>();
|
|
||||||
_identities = (await identifier.FindIdentities(this, providerManager, cancellationToken)).ToList();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,14 +0,0 @@
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Threading;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace MediaBrowser.Controller.Providers
|
|
||||||
{
|
|
||||||
public interface IHasIdentities<out TIdentity>
|
|
||||||
where TIdentity : IItemIdentity
|
|
||||||
{
|
|
||||||
IEnumerable<TIdentity> Identities { get; }
|
|
||||||
|
|
||||||
Task FindIdentities(IProviderManager providerManager, CancellationToken cancellationToken);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,7 +0,0 @@
|
||||||
namespace MediaBrowser.Controller.Providers
|
|
||||||
{
|
|
||||||
public interface IItemIdentity
|
|
||||||
{
|
|
||||||
string Type { get; }
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,4 +1,4 @@
|
||||||
namespace MediaBrowser.Controller.Providers
|
namespace MediaBrowser.Controller.Providers
|
||||||
{
|
{
|
||||||
public interface IItemIdentityConverter : IHasOrder { }
|
public interface IItemIdentityConverter { }
|
||||||
}
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
namespace MediaBrowser.Controller.Providers
|
namespace MediaBrowser.Controller.Providers
|
||||||
{
|
{
|
||||||
public interface IItemIdentityProvider : IHasOrder { }
|
public interface IItemIdentityProvider { }
|
||||||
}
|
}
|
|
@ -195,18 +195,16 @@ namespace MediaBrowser.Controller.Providers
|
||||||
/// Gets the item identity providers.
|
/// Gets the item identity providers.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="TLookupInfo">The type of the t lookup information.</typeparam>
|
/// <typeparam name="TLookupInfo">The type of the t lookup information.</typeparam>
|
||||||
/// <typeparam name="TIdentity">The type of the t identity.</typeparam>
|
|
||||||
/// <returns>IEnumerable<IItemIdentityProvider<TLookupInfo, TIdentity>>.</returns>
|
/// <returns>IEnumerable<IItemIdentityProvider<TLookupInfo, TIdentity>>.</returns>
|
||||||
IEnumerable<IItemIdentityProvider<TLookupInfo, TIdentity>> GetItemIdentityProviders<TLookupInfo, TIdentity>()
|
IEnumerable<IItemIdentityProvider<TLookupInfo>> GetItemIdentityProviders<TLookupInfo>()
|
||||||
where TLookupInfo : ItemLookupInfo
|
where TLookupInfo : ItemLookupInfo;
|
||||||
where TIdentity : IItemIdentity;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the item identity converters.
|
/// Gets the item identity converters.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="TIdentity">The type of the t identity.</typeparam>
|
/// <typeparam name="TLookupInfo">The type of the t lookup information.</typeparam>
|
||||||
/// <returns>IEnumerable<IItemIdentityConverter<TIdentity>>.</returns>
|
/// <returns>IEnumerable<IItemIdentityConverter<TIdentity>>.</returns>
|
||||||
IEnumerable<IItemIdentityConverter<TIdentity>> GetItemIdentityConverters<TIdentity>()
|
IEnumerable<IItemIdentityConverter<TLookupInfo>> GetItemIdentityConverters<TLookupInfo>()
|
||||||
where TIdentity : IItemIdentity;
|
where TLookupInfo : ItemLookupInfo;
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,73 +1,36 @@
|
||||||
using System.Collections.Generic;
|
using System.Linq;
|
||||||
using System.Linq;
|
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace MediaBrowser.Controller.Providers
|
namespace MediaBrowser.Controller.Providers
|
||||||
{
|
{
|
||||||
public class ItemIdentifier<TLookupInfo, TIdentity>
|
public static class ItemIdentifier<TLookupInfo>
|
||||||
where TLookupInfo : ItemLookupInfo
|
where TLookupInfo : ItemLookupInfo
|
||||||
where TIdentity : IItemIdentity
|
|
||||||
{
|
{
|
||||||
public async Task<IEnumerable<TIdentity>> FindIdentities(TLookupInfo item, IProviderManager providerManager, CancellationToken cancellationToken)
|
public static async Task FindIdentities(TLookupInfo item, IProviderManager providerManager, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var providers = providerManager.GetItemIdentityProviders<TLookupInfo, TIdentity>();
|
var providers = providerManager.GetItemIdentityProviders<TLookupInfo>();
|
||||||
var converters = providerManager.GetItemIdentityConverters<TIdentity>();
|
var converters = providerManager.GetItemIdentityConverters<TLookupInfo>().ToList();
|
||||||
|
|
||||||
var identities = new List<IdentityPair>();
|
|
||||||
|
|
||||||
foreach (var provider in providers)
|
foreach (var provider in providers)
|
||||||
{
|
{
|
||||||
var result = new IdentityPair
|
await provider.Identify(item);
|
||||||
{
|
|
||||||
Identity = await provider.FindIdentity(item),
|
|
||||||
Order = provider.Order
|
|
||||||
};
|
|
||||||
|
|
||||||
if (!Equals(result.Identity, default(TIdentity)))
|
|
||||||
{
|
|
||||||
identities.Add(result);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var convertersAvailable = new List<IItemIdentityConverter<TIdentity>>(converters);
|
bool changesMade = true;
|
||||||
bool changesMade;
|
|
||||||
|
|
||||||
do
|
while (changesMade)
|
||||||
{
|
{
|
||||||
changesMade = false;
|
changesMade = false;
|
||||||
|
|
||||||
for (int i = convertersAvailable.Count - 1; i >= 0; i--)
|
foreach (var converter in converters)
|
||||||
{
|
{
|
||||||
var converter = convertersAvailable[i];
|
if (await converter.Convert(item))
|
||||||
var input = identities.FirstOrDefault(id => id.Identity.Type == converter.SourceType);
|
|
||||||
var existing = identities.Where(id => id.Identity.Type == converter.ResultType);
|
|
||||||
|
|
||||||
if (input != null && !existing.Any(id => id.Order <= converter.Order))
|
|
||||||
{
|
{
|
||||||
var result = new IdentityPair
|
|
||||||
{
|
|
||||||
Identity = await converter.Convert(input.Identity).ConfigureAwait(false),
|
|
||||||
Order = converter.Order
|
|
||||||
};
|
|
||||||
|
|
||||||
if (!Equals(result.Identity, default(TIdentity)))
|
|
||||||
{
|
|
||||||
identities.Add(result);
|
|
||||||
convertersAvailable.RemoveAt(i);
|
|
||||||
changesMade = true;
|
changesMade = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} while (changesMade);
|
|
||||||
|
|
||||||
return identities.OrderBy(id => id.Order).Select(id => id.Identity);
|
|
||||||
}
|
|
||||||
|
|
||||||
private class IdentityPair
|
|
||||||
{
|
|
||||||
public TIdentity Identity;
|
|
||||||
public int Order;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -2,20 +2,15 @@
|
||||||
|
|
||||||
namespace MediaBrowser.Controller.Providers
|
namespace MediaBrowser.Controller.Providers
|
||||||
{
|
{
|
||||||
public interface IItemIdentityProvider<in TLookupInfo, TIdentity> : IItemIdentityProvider
|
public interface IItemIdentityProvider<in TLookupInfo> : IItemIdentityProvider
|
||||||
where TLookupInfo : ItemLookupInfo
|
where TLookupInfo : ItemLookupInfo
|
||||||
where TIdentity : IItemIdentity
|
|
||||||
{
|
{
|
||||||
Task<TIdentity> FindIdentity(TLookupInfo info);
|
Task Identify(TLookupInfo info);
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface IItemIdentityConverter<TIdentity> : IItemIdentityConverter
|
public interface IItemIdentityConverter<in TLookupInfo> : IItemIdentityConverter
|
||||||
where TIdentity : IItemIdentity
|
where TLookupInfo : ItemLookupInfo
|
||||||
{
|
{
|
||||||
Task<TIdentity> Convert(TIdentity identity);
|
Task<bool> Convert(TLookupInfo info);
|
||||||
|
|
||||||
string SourceType { get; }
|
|
||||||
|
|
||||||
string ResultType { get; }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,11 +0,0 @@
|
||||||
namespace MediaBrowser.Controller.Providers
|
|
||||||
{
|
|
||||||
public class SeasonIdentity : IItemIdentity
|
|
||||||
{
|
|
||||||
public string Type { get; set; }
|
|
||||||
|
|
||||||
public string SeriesId { get; set; }
|
|
||||||
|
|
||||||
public int SeasonIndex { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,15 +1,10 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
|
||||||
using System.Threading;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace MediaBrowser.Controller.Providers
|
namespace MediaBrowser.Controller.Providers
|
||||||
{
|
{
|
||||||
public class SeasonInfo : ItemLookupInfo, IHasIdentities<SeasonIdentity>
|
public class SeasonInfo : ItemLookupInfo
|
||||||
{
|
{
|
||||||
private List<SeasonIdentity> _identities = new List<SeasonIdentity>();
|
|
||||||
|
|
||||||
public Dictionary<string, string> SeriesProviderIds { get; set; }
|
public Dictionary<string, string> SeriesProviderIds { get; set; }
|
||||||
public int? AnimeSeriesIndex { get; set; }
|
public int? AnimeSeriesIndex { get; set; }
|
||||||
|
|
||||||
|
@ -17,16 +12,5 @@ namespace MediaBrowser.Controller.Providers
|
||||||
{
|
{
|
||||||
SeriesProviderIds = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
SeriesProviderIds = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerable<SeasonIdentity> Identities
|
|
||||||
{
|
|
||||||
get { return _identities; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task FindIdentities(IProviderManager providerManager, CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
var identifier = new ItemIdentifier<SeasonInfo, SeasonIdentity>();
|
|
||||||
_identities = (await identifier.FindIdentities(this, providerManager, cancellationToken)).ToList();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,9 +0,0 @@
|
||||||
namespace MediaBrowser.Controller.Providers
|
|
||||||
{
|
|
||||||
public class SeriesIdentity : IItemIdentity
|
|
||||||
{
|
|
||||||
public string Type { get; set; }
|
|
||||||
|
|
||||||
public string Id { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,25 +1,7 @@
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Threading;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace MediaBrowser.Controller.Providers
|
namespace MediaBrowser.Controller.Providers
|
||||||
{
|
{
|
||||||
public class SeriesInfo : ItemLookupInfo, IHasIdentities<SeriesIdentity>
|
public class SeriesInfo : ItemLookupInfo
|
||||||
{
|
{
|
||||||
private List<SeriesIdentity> _identities = new List<SeriesIdentity>();
|
|
||||||
|
|
||||||
public int? AnimeSeriesIndex { get; set; }
|
public int? AnimeSeriesIndex { get; set; }
|
||||||
|
|
||||||
public IEnumerable<SeriesIdentity> Identities
|
|
||||||
{
|
|
||||||
get { return _identities; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task FindIdentities(IProviderManager providerManager, CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
var identifier = new ItemIdentifier<SeriesInfo, SeriesIdentity>();
|
|
||||||
_identities = (await identifier.FindIdentities(this, providerManager, cancellationToken)).ToList();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -141,7 +141,8 @@ namespace MediaBrowser.Providers.Manager
|
||||||
|
|
||||||
if (providers.Count > 0)
|
if (providers.Count > 0)
|
||||||
{
|
{
|
||||||
var id = await CreateInitialLookupInfo(itemOfType, cancellationToken).ConfigureAwait(false);
|
var id = itemOfType.GetLookupInfo();
|
||||||
|
await ItemIdentifier<TIdType>.FindIdentities(id, ProviderManager, cancellationToken);
|
||||||
|
|
||||||
var result = await RefreshWithProviders(metadataResult, id, refreshOptions, providers, itemImageProvider, cancellationToken).ConfigureAwait(false);
|
var result = await RefreshWithProviders(metadataResult, id, refreshOptions, providers, itemImageProvider, cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
|
@ -155,8 +156,6 @@ namespace MediaBrowser.Providers.Manager
|
||||||
{
|
{
|
||||||
refreshResult.SetDateLastMetadataRefresh(null);
|
refreshResult.SetDateLastMetadataRefresh(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
MergeIdentities(itemOfType, id);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -224,15 +223,6 @@ namespace MediaBrowser.Providers.Manager
|
||||||
return _cachedTask;
|
return _cachedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void MergeIdentities(TItemType item, TIdType id)
|
|
||||||
{
|
|
||||||
var hasIdentity = id as IHasIdentities<IItemIdentity>;
|
|
||||||
if (hasIdentity != null)
|
|
||||||
{
|
|
||||||
item.Identities = hasIdentity.Identities.ToList();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private readonly Task<ItemUpdateType> _cachedResult = Task.FromResult(ItemUpdateType.None);
|
private readonly Task<ItemUpdateType> _cachedResult = Task.FromResult(ItemUpdateType.None);
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Befores the save.
|
/// Befores the save.
|
||||||
|
@ -623,26 +613,6 @@ namespace MediaBrowser.Providers.Manager
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<TIdType> CreateInitialLookupInfo(TItemType item, CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
var info = item.GetLookupInfo();
|
|
||||||
|
|
||||||
var hasIdentity = info as IHasIdentities<IItemIdentity>;
|
|
||||||
if (hasIdentity != null)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
await hasIdentity.FindIdentities(ProviderManager, cancellationToken).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Logger.ErrorException("Error in identity providers", ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return info;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void MergeNewData(TItemType source, TIdType lookupInfo)
|
private void MergeNewData(TItemType source, TIdType lookupInfo)
|
||||||
{
|
{
|
||||||
// Copy new provider id's that may have been obtained
|
// Copy new provider id's that may have been obtained
|
||||||
|
|
|
@ -298,17 +298,16 @@ namespace MediaBrowser.Providers.Manager
|
||||||
.ThenBy(GetDefaultOrder);
|
.ThenBy(GetDefaultOrder);
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerable<IItemIdentityProvider<TLookupInfo, TIdentity>> GetItemIdentityProviders<TLookupInfo, TIdentity>()
|
public IEnumerable<IItemIdentityProvider<TLookupInfo>> GetItemIdentityProviders<TLookupInfo>()
|
||||||
where TLookupInfo : ItemLookupInfo
|
where TLookupInfo : ItemLookupInfo
|
||||||
where TIdentity : IItemIdentity
|
|
||||||
{
|
{
|
||||||
return _identityProviders.OfType<IItemIdentityProvider<TLookupInfo, TIdentity>>();
|
return _identityProviders.OfType<IItemIdentityProvider<TLookupInfo>>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerable<IItemIdentityConverter<TIdentity>> GetItemIdentityConverters<TIdentity>()
|
public IEnumerable<IItemIdentityConverter<TLookupInfo>> GetItemIdentityConverters<TLookupInfo>()
|
||||||
where TIdentity : IItemIdentity
|
where TLookupInfo : ItemLookupInfo
|
||||||
{
|
{
|
||||||
return _identityConverters.OfType<IItemIdentityConverter<TIdentity>>();
|
return _identityConverters.OfType<IItemIdentityConverter<TLookupInfo>>();
|
||||||
}
|
}
|
||||||
|
|
||||||
private IEnumerable<IRemoteImageProvider> GetRemoteImageProviders(IHasImages item, bool includeDisabled)
|
private IEnumerable<IRemoteImageProvider> GetRemoteImageProviders(IHasImages item, bool includeDisabled)
|
||||||
|
|
|
@ -24,8 +24,11 @@ namespace MediaBrowser.Providers.TV
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Class RemoteEpisodeProvider
|
/// Class RemoteEpisodeProvider
|
||||||
/// </summary>
|
/// </summary>
|
||||||
class TvdbEpisodeProvider : IRemoteMetadataProvider<Episode, EpisodeInfo>, IItemIdentityProvider<EpisodeInfo, EpisodeIdentity>, IHasChangeMonitor
|
class TvdbEpisodeProvider : IRemoteMetadataProvider<Episode, EpisodeInfo>, IItemIdentityProvider<EpisodeInfo>, IHasChangeMonitor
|
||||||
{
|
{
|
||||||
|
private const string FullIdFormat = "{0}:{1}:{2}"; // seriesId:seasonIndex:episodeNumbers
|
||||||
|
private static readonly string FullIdKey = MetadataProviders.Tvdb + "-Full";
|
||||||
|
|
||||||
internal static TvdbEpisodeProvider Current;
|
internal static TvdbEpisodeProvider Current;
|
||||||
private readonly IFileSystem _fileSystem;
|
private readonly IFileSystem _fileSystem;
|
||||||
private readonly IServerConfigurationManager _config;
|
private readonly IServerConfigurationManager _config;
|
||||||
|
@ -45,18 +48,24 @@ namespace MediaBrowser.Providers.TV
|
||||||
{
|
{
|
||||||
var list = new List<RemoteSearchResult>();
|
var list = new List<RemoteSearchResult>();
|
||||||
|
|
||||||
var identity = searchInfo.Identities.FirstOrDefault(id => id.Type == MetadataProviders.Tvdb.ToString()) ?? await FindIdentity(searchInfo).ConfigureAwait(false);
|
var identity = ParseIdentity(searchInfo.GetProviderId(FullIdKey));
|
||||||
|
|
||||||
|
if (identity == null)
|
||||||
|
{
|
||||||
|
await Identify(searchInfo).ConfigureAwait(false);
|
||||||
|
identity = ParseIdentity(searchInfo.GetProviderId(FullIdKey));
|
||||||
|
}
|
||||||
|
|
||||||
if (identity != null)
|
if (identity != null)
|
||||||
{
|
{
|
||||||
await TvdbSeriesProvider.Current.EnsureSeriesInfo(identity.SeriesId, searchInfo.MetadataLanguage,
|
await TvdbSeriesProvider.Current.EnsureSeriesInfo(identity.Value.SeriesId, searchInfo.MetadataLanguage,
|
||||||
cancellationToken).ConfigureAwait(false);
|
cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
var seriesDataPath = TvdbSeriesProvider.GetSeriesDataPath(_config.ApplicationPaths, identity.SeriesId);
|
var seriesDataPath = TvdbSeriesProvider.GetSeriesDataPath(_config.ApplicationPaths, identity.Value.SeriesId);
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var metadataResult = FetchEpisodeData(searchInfo, identity, seriesDataPath, searchInfo.SeriesProviderIds, cancellationToken);
|
var metadataResult = FetchEpisodeData(searchInfo, identity.Value, seriesDataPath, searchInfo.SeriesProviderIds, cancellationToken);
|
||||||
|
|
||||||
if (metadataResult.HasMetadata)
|
if (metadataResult.HasMetadata)
|
||||||
{
|
{
|
||||||
|
@ -95,17 +104,23 @@ namespace MediaBrowser.Providers.TV
|
||||||
|
|
||||||
public async Task<MetadataResult<Episode>> GetMetadata(EpisodeInfo searchInfo, CancellationToken cancellationToken)
|
public async Task<MetadataResult<Episode>> GetMetadata(EpisodeInfo searchInfo, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var identity = searchInfo.Identities.FirstOrDefault(id => id.Type == MetadataProviders.Tvdb.ToString()) ?? await FindIdentity(searchInfo).ConfigureAwait(false);
|
var identity = ParseIdentity(searchInfo.GetProviderId(FullIdKey));
|
||||||
|
|
||||||
|
if (identity == null)
|
||||||
|
{
|
||||||
|
await Identify(searchInfo).ConfigureAwait(false);
|
||||||
|
identity = ParseIdentity(searchInfo.GetProviderId(FullIdKey));
|
||||||
|
}
|
||||||
|
|
||||||
var result = new MetadataResult<Episode>();
|
var result = new MetadataResult<Episode>();
|
||||||
|
|
||||||
if (identity != null)
|
if (identity != null)
|
||||||
{
|
{
|
||||||
var seriesDataPath = TvdbSeriesProvider.GetSeriesDataPath(_config.ApplicationPaths, identity.SeriesId);
|
var seriesDataPath = TvdbSeriesProvider.GetSeriesDataPath(_config.ApplicationPaths, identity.Value.SeriesId);
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
result = FetchEpisodeData(searchInfo, identity, seriesDataPath, searchInfo.SeriesProviderIds, cancellationToken);
|
result = FetchEpisodeData(searchInfo, identity.Value, seriesDataPath, searchInfo.SeriesProviderIds, cancellationToken);
|
||||||
}
|
}
|
||||||
catch (FileNotFoundException)
|
catch (FileNotFoundException)
|
||||||
{
|
{
|
||||||
|
@ -231,9 +246,9 @@ namespace MediaBrowser.Providers.TV
|
||||||
/// <param name="seriesProviderIds">The series provider ids.</param>
|
/// <param name="seriesProviderIds">The series provider ids.</param>
|
||||||
/// <param name="cancellationToken">The cancellation token.</param>
|
/// <param name="cancellationToken">The cancellation token.</param>
|
||||||
/// <returns>Task{System.Boolean}.</returns>
|
/// <returns>Task{System.Boolean}.</returns>
|
||||||
private MetadataResult<Episode> FetchEpisodeData(EpisodeInfo id, EpisodeIdentity identity, string seriesDataPath, Dictionary<string, string> seriesProviderIds, CancellationToken cancellationToken)
|
private MetadataResult<Episode> FetchEpisodeData(EpisodeInfo id, Identity identity, string seriesDataPath, Dictionary<string, string> seriesProviderIds, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var episodeNumber = identity.IndexNumber;
|
var episodeNumber = identity.EpisodeNumber;
|
||||||
var seasonOffset = TvdbSeriesProvider.GetSeriesOffset(seriesProviderIds) ?? 0;
|
var seasonOffset = TvdbSeriesProvider.GetSeriesOffset(seriesProviderIds) ?? 0;
|
||||||
var seasonNumber = identity.SeasonIndex + seasonOffset;
|
var seasonNumber = identity.SeasonIndex + seasonOffset;
|
||||||
|
|
||||||
|
@ -278,7 +293,7 @@ namespace MediaBrowser.Providers.TV
|
||||||
usingAbsoluteData = true;
|
usingAbsoluteData = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
var end = identity.IndexNumberEnd ?? episodeNumber;
|
var end = identity.EpisodeNumberEnd ?? episodeNumber;
|
||||||
episodeNumber++;
|
episodeNumber++;
|
||||||
|
|
||||||
while (episodeNumber <= end)
|
while (episodeNumber <= end)
|
||||||
|
@ -753,28 +768,86 @@ namespace MediaBrowser.Providers.TV
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task<EpisodeIdentity> FindIdentity(EpisodeInfo info)
|
public Task Identify(EpisodeInfo info)
|
||||||
{
|
{
|
||||||
|
if (info.ProviderIds.ContainsKey(FullIdKey))
|
||||||
|
{
|
||||||
|
return Task.FromResult<object>(null);
|
||||||
|
}
|
||||||
|
|
||||||
string seriesTvdbId;
|
string seriesTvdbId;
|
||||||
info.SeriesProviderIds.TryGetValue(MetadataProviders.Tvdb.ToString(), out seriesTvdbId);
|
info.SeriesProviderIds.TryGetValue(MetadataProviders.Tvdb.ToString(), out seriesTvdbId);
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(seriesTvdbId) || info.IndexNumber == null)
|
if (string.IsNullOrEmpty(seriesTvdbId) || info.IndexNumber == null)
|
||||||
{
|
{
|
||||||
return Task.FromResult<EpisodeIdentity>(null);
|
return Task.FromResult<object>(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
var id = new EpisodeIdentity
|
var number = info.IndexNumber.Value.ToString();
|
||||||
{
|
if (info.IndexNumberEnd != null)
|
||||||
Type = MetadataProviders.Tvdb.ToString(),
|
number += "-" + info.IndexNumberEnd;
|
||||||
SeriesId = seriesTvdbId,
|
|
||||||
SeasonIndex = info.ParentIndexNumber,
|
var id = string.Format(
|
||||||
IndexNumber = info.IndexNumber.Value,
|
FullIdFormat,
|
||||||
IndexNumberEnd = info.IndexNumberEnd
|
seriesTvdbId,
|
||||||
};
|
info.ParentIndexNumber.HasValue ? info.ParentIndexNumber.Value.ToString() : "A",
|
||||||
|
number);
|
||||||
|
|
||||||
|
info.SetProviderId(FullIdKey, FullIdFormat);
|
||||||
|
|
||||||
return Task.FromResult(id);
|
return Task.FromResult(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Identity? ParseIdentity(string id)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(id))
|
||||||
|
return null;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var parts = id.Split(':');
|
||||||
|
var series = parts[0];
|
||||||
|
var season = parts[1] != "A" ? (int?) int.Parse(parts[1]) : null;
|
||||||
|
|
||||||
|
int index;
|
||||||
|
int? indexEnd;
|
||||||
|
|
||||||
|
if (parts[2].Contains("-"))
|
||||||
|
{
|
||||||
|
var split = parts[2].IndexOf("-", StringComparison.OrdinalIgnoreCase);
|
||||||
|
index = int.Parse(parts[2].Substring(0, split));
|
||||||
|
indexEnd = int.Parse(parts[2].Substring(split + 1));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
index = int.Parse(parts[2]);
|
||||||
|
indexEnd = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Identity(series, season, index, indexEnd);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public int Order { get { return 0; } }
|
public int Order { get { return 0; } }
|
||||||
|
|
||||||
|
private struct Identity
|
||||||
|
{
|
||||||
|
public string SeriesId { get; private set; }
|
||||||
|
public int? SeasonIndex { get; private set; }
|
||||||
|
public int EpisodeNumber { get; private set; }
|
||||||
|
public int? EpisodeNumberEnd { get; private set; }
|
||||||
|
|
||||||
|
public Identity(string seriesId, int? seasonIndex, int episodeNumber, int? episodeNumberEnd)
|
||||||
|
{
|
||||||
|
SeriesId = seriesId;
|
||||||
|
SeasonIndex = seasonIndex;
|
||||||
|
EpisodeNumber = episodeNumber;
|
||||||
|
EpisodeNumberEnd = episodeNumberEnd;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,26 +4,50 @@ using MediaBrowser.Model.Entities;
|
||||||
|
|
||||||
namespace MediaBrowser.Providers.TV
|
namespace MediaBrowser.Providers.TV
|
||||||
{
|
{
|
||||||
public class TvdbSeasonIdentityProvider : IItemIdentityProvider<SeasonInfo, SeasonIdentity>
|
public class TvdbSeasonIdentityProvider : IItemIdentityProvider<SeasonInfo>
|
||||||
{
|
{
|
||||||
public Task<SeasonIdentity> FindIdentity(SeasonInfo info)
|
public static readonly string FullIdKey = MetadataProviders.Tvdb + "-Full";
|
||||||
|
|
||||||
|
public Task Identify(SeasonInfo info)
|
||||||
{
|
{
|
||||||
string tvdbSeriesId;
|
string tvdbSeriesId;
|
||||||
if (!info.SeriesProviderIds.TryGetValue(MetadataProviders.Tvdb.ToString(), out tvdbSeriesId) || string.IsNullOrEmpty(tvdbSeriesId) || info.IndexNumber == null)
|
if (!info.SeriesProviderIds.TryGetValue(MetadataProviders.Tvdb.ToString(), out tvdbSeriesId) || string.IsNullOrEmpty(tvdbSeriesId) || info.IndexNumber == null)
|
||||||
{
|
{
|
||||||
return Task.FromResult<SeasonIdentity>(null);
|
return Task.FromResult<object>(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
var result = new SeasonIdentity
|
if (string.IsNullOrEmpty(info.GetProviderId(FullIdKey)))
|
||||||
{
|
{
|
||||||
Type = MetadataProviders.Tvdb.ToString(),
|
var id = string.Format("{0}:{1}", tvdbSeriesId, info.IndexNumber.Value);
|
||||||
SeriesId = tvdbSeriesId,
|
info.SetProviderId(FullIdKey, id);
|
||||||
SeasonIndex = info.IndexNumber.Value
|
|
||||||
};
|
|
||||||
|
|
||||||
return Task.FromResult(result);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public int Order { get { return 0; } }
|
return Task.FromResult<object>(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TvdbSeasonIdentity? ParseIdentity(string id)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var parts = id.Split(':');
|
||||||
|
return new TvdbSeasonIdentity(parts[0], int.Parse(parts[1]));
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public struct TvdbSeasonIdentity
|
||||||
|
{
|
||||||
|
public string SeriesId { get; private set; }
|
||||||
|
public int Index { get; private set; }
|
||||||
|
|
||||||
|
public TvdbSeasonIdentity(string seriesId, int index)
|
||||||
|
{
|
||||||
|
SeriesId = seriesId;
|
||||||
|
Index = index;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -65,26 +65,23 @@ namespace MediaBrowser.Providers.TV
|
||||||
var season = (Season)item;
|
var season = (Season)item;
|
||||||
var series = season.Series;
|
var series = season.Series;
|
||||||
|
|
||||||
var seriesId = series != null ? series.GetProviderId(MetadataProviders.Tvdb) : null;
|
var identity = TvdbSeasonIdentityProvider.ParseIdentity(season.GetProviderId(TvdbSeasonIdentityProvider.FullIdKey));
|
||||||
|
if (identity == null && series != null && season.IndexNumber.HasValue)
|
||||||
if (!string.IsNullOrEmpty(seriesId) && season.IndexNumber.HasValue)
|
|
||||||
{
|
{
|
||||||
await TvdbSeriesProvider.Current.EnsureSeriesInfo(seriesId, series.GetPreferredMetadataLanguage(), cancellationToken).ConfigureAwait(false);
|
identity = new TvdbSeasonIdentity(series.GetProviderId(MetadataProviders.Tvdb), season.IndexNumber.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (identity != null && series != null)
|
||||||
|
{
|
||||||
|
var id = identity.Value;
|
||||||
|
await TvdbSeriesProvider.Current.EnsureSeriesInfo(id.SeriesId, series.GetPreferredMetadataLanguage(), cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
// Process images
|
// Process images
|
||||||
var seriesDataPath = TvdbSeriesProvider.GetSeriesDataPath(_config.ApplicationPaths, seriesId);
|
var seriesDataPath = TvdbSeriesProvider.GetSeriesDataPath(_config.ApplicationPaths, id.SeriesId);
|
||||||
|
|
||||||
var path = Path.Combine(seriesDataPath, "banners.xml");
|
var path = Path.Combine(seriesDataPath, "banners.xml");
|
||||||
|
|
||||||
var identity = season.Identities.OfType<SeasonIdentity>()
|
var seasonNumber = AdjustForSeriesOffset(series, id.Index);
|
||||||
.FirstOrDefault(id => id.Type == MetadataProviders.Tvdb.ToString());
|
|
||||||
|
|
||||||
var seasonNumber = season.IndexNumber.Value;
|
|
||||||
|
|
||||||
if (identity != null)
|
|
||||||
{
|
|
||||||
seasonNumber = AdjustForSeriesOffset(series, identity.SeasonIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
|
|
@ -25,7 +25,7 @@ using System.Xml;
|
||||||
|
|
||||||
namespace MediaBrowser.Providers.TV
|
namespace MediaBrowser.Providers.TV
|
||||||
{
|
{
|
||||||
public class TvdbSeriesProvider : IRemoteMetadataProvider<Series, SeriesInfo>, IItemIdentityProvider<SeriesInfo, SeriesIdentity>, IHasOrder
|
public class TvdbSeriesProvider : IRemoteMetadataProvider<Series, SeriesInfo>, IItemIdentityProvider<SeriesInfo>, IHasOrder
|
||||||
{
|
{
|
||||||
private const string TvdbSeriesOffset = "TvdbSeriesOffset";
|
private const string TvdbSeriesOffset = "TvdbSeriesOffset";
|
||||||
private const string TvdbSeriesOffsetFormat = "{0}-{1}";
|
private const string TvdbSeriesOffsetFormat = "{0}-{1}";
|
||||||
|
@ -94,22 +94,8 @@ namespace MediaBrowser.Providers.TV
|
||||||
|
|
||||||
if (string.IsNullOrWhiteSpace(seriesId))
|
if (string.IsNullOrWhiteSpace(seriesId))
|
||||||
{
|
{
|
||||||
seriesId = itemId.Identities
|
await Identify(itemId).ConfigureAwait(false);
|
||||||
.Where(id => id.Type == MetadataProviders.Tvdb.ToString())
|
seriesId = itemId.GetProviderId(MetadataProviders.Tvdb);
|
||||||
.Select(id => id.Id)
|
|
||||||
.FirstOrDefault();
|
|
||||||
|
|
||||||
if (string.IsNullOrWhiteSpace(seriesId))
|
|
||||||
{
|
|
||||||
var srch = await GetSearchResults(itemId, cancellationToken).ConfigureAwait(false);
|
|
||||||
|
|
||||||
var entry = srch.FirstOrDefault();
|
|
||||||
|
|
||||||
if (entry != null)
|
|
||||||
{
|
|
||||||
seriesId = entry.GetProviderId(MetadataProviders.Tvdb);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cancellationToken.ThrowIfCancellationRequested();
|
cancellationToken.ThrowIfCancellationRequested();
|
||||||
|
@ -1239,27 +1225,20 @@ namespace MediaBrowser.Providers.TV
|
||||||
get { return "TheTVDB"; }
|
get { return "TheTVDB"; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<SeriesIdentity> FindIdentity(SeriesInfo info)
|
public async Task Identify(SeriesInfo info)
|
||||||
{
|
{
|
||||||
string tvdbId;
|
if (string.IsNullOrEmpty(info.GetProviderId(MetadataProviders.Tvdb)))
|
||||||
if (!info.ProviderIds.TryGetValue(MetadataProviders.Tvdb.ToString(), out tvdbId))
|
|
||||||
{
|
{
|
||||||
var srch = await GetSearchResults(info, CancellationToken.None).ConfigureAwait(false);
|
var srch = await FindSeries(info.Name, info.MetadataLanguage, CancellationToken.None).ConfigureAwait(false);
|
||||||
|
|
||||||
var entry = srch.FirstOrDefault();
|
var entry = srch.FirstOrDefault();
|
||||||
|
|
||||||
if (entry != null)
|
if (entry != null)
|
||||||
{
|
{
|
||||||
tvdbId = entry.GetProviderId(MetadataProviders.Tvdb);
|
var id = entry.GetProviderId(MetadataProviders.Tvdb);
|
||||||
|
info.SetProviderId(MetadataProviders.Tvdb, id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(tvdbId))
|
|
||||||
{
|
|
||||||
return new SeriesIdentity { Type = MetadataProviders.Tvdb.ToString(), Id = tvdbId };
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public int Order
|
public int Order
|
||||||
|
|
Loading…
Reference in New Issue
Block a user