mirror of
https://github.com/jellyfin/jellyfin.git
synced 2026-07-20 05:04:18 +01:00
Merge pull request #1185 from TomGillen/absolute-ids
Re-designed item identity providers
This commit is contained in:
@@ -141,7 +141,8 @@ namespace MediaBrowser.Providers.Manager
|
||||
|
||||
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);
|
||||
|
||||
@@ -155,8 +156,6 @@ namespace MediaBrowser.Providers.Manager
|
||||
{
|
||||
refreshResult.SetDateLastMetadataRefresh(null);
|
||||
}
|
||||
|
||||
MergeIdentities(itemOfType, id);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -223,16 +222,7 @@ namespace MediaBrowser.Providers.Manager
|
||||
item.AfterMetadataRefresh();
|
||||
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);
|
||||
/// <summary>
|
||||
/// 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)
|
||||
{
|
||||
// Copy new provider id's that may have been obtained
|
||||
|
||||
@@ -298,17 +298,16 @@ namespace MediaBrowser.Providers.Manager
|
||||
.ThenBy(GetDefaultOrder);
|
||||
}
|
||||
|
||||
public IEnumerable<IItemIdentityProvider<TLookupInfo, TIdentity>> GetItemIdentityProviders<TLookupInfo, TIdentity>()
|
||||
public IEnumerable<IItemIdentityProvider<TLookupInfo>> GetItemIdentityProviders<TLookupInfo>()
|
||||
where TLookupInfo : ItemLookupInfo
|
||||
where TIdentity : IItemIdentity
|
||||
{
|
||||
return _identityProviders.OfType<IItemIdentityProvider<TLookupInfo, TIdentity>>();
|
||||
return _identityProviders.OfType<IItemIdentityProvider<TLookupInfo>>();
|
||||
}
|
||||
|
||||
public IEnumerable<IItemIdentityConverter<TIdentity>> GetItemIdentityConverters<TIdentity>()
|
||||
where TIdentity : IItemIdentity
|
||||
public IEnumerable<IItemIdentityConverter<TLookupInfo>> GetItemIdentityConverters<TLookupInfo>()
|
||||
where TLookupInfo : ItemLookupInfo
|
||||
{
|
||||
return _identityConverters.OfType<IItemIdentityConverter<TIdentity>>();
|
||||
return _identityConverters.OfType<IItemIdentityConverter<TLookupInfo>>();
|
||||
}
|
||||
|
||||
private IEnumerable<IRemoteImageProvider> GetRemoteImageProviders(IHasImages item, bool includeDisabled)
|
||||
|
||||
@@ -24,8 +24,11 @@ namespace MediaBrowser.Providers.TV
|
||||
/// <summary>
|
||||
/// Class RemoteEpisodeProvider
|
||||
/// </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;
|
||||
private readonly IFileSystem _fileSystem;
|
||||
private readonly IServerConfigurationManager _config;
|
||||
@@ -45,18 +48,24 @@ namespace MediaBrowser.Providers.TV
|
||||
{
|
||||
var list = new List<RemoteSearchResult>();
|
||||
|
||||
var identity = searchInfo.Identities.FirstOrDefault(id => id.Type == MetadataProviders.Tvdb.ToString()) ?? await FindIdentity(searchInfo).ConfigureAwait(false);
|
||||
var identity = Identity.ParseIdentity(searchInfo.GetProviderId(FullIdKey));
|
||||
|
||||
if (identity == null)
|
||||
{
|
||||
await Identify(searchInfo).ConfigureAwait(false);
|
||||
identity = Identity.ParseIdentity(searchInfo.GetProviderId(FullIdKey));
|
||||
}
|
||||
|
||||
if (identity != null)
|
||||
{
|
||||
await TvdbSeriesProvider.Current.EnsureSeriesInfo(identity.SeriesId, searchInfo.MetadataLanguage,
|
||||
await TvdbSeriesProvider.Current.EnsureSeriesInfo(identity.Value.SeriesId, searchInfo.MetadataLanguage,
|
||||
cancellationToken).ConfigureAwait(false);
|
||||
|
||||
var seriesDataPath = TvdbSeriesProvider.GetSeriesDataPath(_config.ApplicationPaths, identity.SeriesId);
|
||||
var seriesDataPath = TvdbSeriesProvider.GetSeriesDataPath(_config.ApplicationPaths, identity.Value.SeriesId);
|
||||
|
||||
try
|
||||
{
|
||||
var metadataResult = FetchEpisodeData(searchInfo, identity, seriesDataPath, searchInfo.SeriesProviderIds, cancellationToken);
|
||||
var metadataResult = FetchEpisodeData(searchInfo, identity.Value, seriesDataPath, searchInfo.SeriesProviderIds, cancellationToken);
|
||||
|
||||
if (metadataResult.HasMetadata)
|
||||
{
|
||||
@@ -95,17 +104,23 @@ namespace MediaBrowser.Providers.TV
|
||||
|
||||
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 = Identity.ParseIdentity(searchInfo.GetProviderId(FullIdKey));
|
||||
|
||||
if (identity == null)
|
||||
{
|
||||
await Identify(searchInfo).ConfigureAwait(false);
|
||||
identity = Identity.ParseIdentity(searchInfo.GetProviderId(FullIdKey));
|
||||
}
|
||||
|
||||
var result = new MetadataResult<Episode>();
|
||||
|
||||
if (identity != null)
|
||||
{
|
||||
var seriesDataPath = TvdbSeriesProvider.GetSeriesDataPath(_config.ApplicationPaths, identity.SeriesId);
|
||||
var seriesDataPath = TvdbSeriesProvider.GetSeriesDataPath(_config.ApplicationPaths, identity.Value.SeriesId);
|
||||
|
||||
try
|
||||
{
|
||||
result = FetchEpisodeData(searchInfo, identity, seriesDataPath, searchInfo.SeriesProviderIds, cancellationToken);
|
||||
result = FetchEpisodeData(searchInfo, identity.Value, seriesDataPath, searchInfo.SeriesProviderIds, cancellationToken);
|
||||
}
|
||||
catch (FileNotFoundException)
|
||||
{
|
||||
@@ -231,9 +246,9 @@ namespace MediaBrowser.Providers.TV
|
||||
/// <param name="seriesProviderIds">The series provider ids.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <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 seasonNumber = identity.SeasonIndex + seasonOffset;
|
||||
|
||||
@@ -278,7 +293,7 @@ namespace MediaBrowser.Providers.TV
|
||||
usingAbsoluteData = true;
|
||||
}
|
||||
|
||||
var end = identity.IndexNumberEnd ?? episodeNumber;
|
||||
var end = identity.EpisodeNumberEnd ?? episodeNumber;
|
||||
episodeNumber++;
|
||||
|
||||
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;
|
||||
info.SeriesProviderIds.TryGetValue(MetadataProviders.Tvdb.ToString(), out seriesTvdbId);
|
||||
|
||||
if (string.IsNullOrEmpty(seriesTvdbId) || info.IndexNumber == null)
|
||||
{
|
||||
return Task.FromResult<EpisodeIdentity>(null);
|
||||
return Task.FromResult<object>(null);
|
||||
}
|
||||
|
||||
var id = new EpisodeIdentity
|
||||
{
|
||||
Type = MetadataProviders.Tvdb.ToString(),
|
||||
SeriesId = seriesTvdbId,
|
||||
SeasonIndex = info.ParentIndexNumber,
|
||||
IndexNumber = info.IndexNumber.Value,
|
||||
IndexNumberEnd = info.IndexNumberEnd
|
||||
};
|
||||
|
||||
var id = new Identity(seriesTvdbId, info.ParentIndexNumber, info.IndexNumber.Value, info.IndexNumberEnd);
|
||||
info.SetProviderId(FullIdKey, id.ToString());
|
||||
|
||||
return Task.FromResult(id);
|
||||
}
|
||||
|
||||
public int Order { get { return 0; } }
|
||||
|
||||
public 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 id)
|
||||
: this()
|
||||
{
|
||||
this = ParseIdentity(id).Value;
|
||||
}
|
||||
|
||||
public Identity(string seriesId, int? seasonIndex, int episodeNumber, int? episodeNumberEnd)
|
||||
: this()
|
||||
{
|
||||
SeriesId = seriesId;
|
||||
SeasonIndex = seasonIndex;
|
||||
EpisodeNumber = episodeNumber;
|
||||
EpisodeNumberEnd = episodeNumberEnd;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return string.Format("{0}:{1}:{2}",
|
||||
SeriesId,
|
||||
SeasonIndex != null ? SeasonIndex.Value.ToString() : "A",
|
||||
EpisodeNumber + (EpisodeNumberEnd != null ? "-" + EpisodeNumberEnd.Value.ToString() : ""));
|
||||
}
|
||||
|
||||
public static 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,26 +4,57 @@ using MediaBrowser.Model.Entities;
|
||||
|
||||
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;
|
||||
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(),
|
||||
SeriesId = tvdbSeriesId,
|
||||
SeasonIndex = info.IndexNumber.Value
|
||||
};
|
||||
|
||||
return Task.FromResult(result);
|
||||
var id = string.Format("{0}:{1}", tvdbSeriesId, info.IndexNumber.Value);
|
||||
info.SetProviderId(FullIdKey, id);
|
||||
}
|
||||
|
||||
return Task.FromResult<object>(null);
|
||||
}
|
||||
|
||||
public int Order { get { return 0; } }
|
||||
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 id)
|
||||
: this()
|
||||
{
|
||||
this = TvdbSeasonIdentityProvider.ParseIdentity(id).Value;
|
||||
}
|
||||
|
||||
public TvdbSeasonIdentity(string seriesId, int index)
|
||||
: this()
|
||||
{
|
||||
SeriesId = seriesId;
|
||||
Index = index;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -65,26 +65,23 @@ namespace MediaBrowser.Providers.TV
|
||||
var season = (Season)item;
|
||||
var series = season.Series;
|
||||
|
||||
var seriesId = series != null ? series.GetProviderId(MetadataProviders.Tvdb) : null;
|
||||
|
||||
if (!string.IsNullOrEmpty(seriesId) && season.IndexNumber.HasValue)
|
||||
var identity = TvdbSeasonIdentityProvider.ParseIdentity(season.GetProviderId(TvdbSeasonIdentityProvider.FullIdKey));
|
||||
if (identity == null && series != null && 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
|
||||
var seriesDataPath = TvdbSeriesProvider.GetSeriesDataPath(_config.ApplicationPaths, seriesId);
|
||||
var seriesDataPath = TvdbSeriesProvider.GetSeriesDataPath(_config.ApplicationPaths, id.SeriesId);
|
||||
|
||||
var path = Path.Combine(seriesDataPath, "banners.xml");
|
||||
|
||||
var identity = season.Identities.OfType<SeasonIdentity>()
|
||||
.FirstOrDefault(id => id.Type == MetadataProviders.Tvdb.ToString());
|
||||
|
||||
var seasonNumber = season.IndexNumber.Value;
|
||||
|
||||
if (identity != null)
|
||||
{
|
||||
seasonNumber = AdjustForSeriesOffset(series, identity.SeasonIndex);
|
||||
}
|
||||
var seasonNumber = AdjustForSeriesOffset(series, id.Index);
|
||||
|
||||
try
|
||||
{
|
||||
|
||||
@@ -25,7 +25,7 @@ using System.Xml;
|
||||
|
||||
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 TvdbSeriesOffsetFormat = "{0}-{1}";
|
||||
@@ -94,24 +94,10 @@ namespace MediaBrowser.Providers.TV
|
||||
|
||||
if (string.IsNullOrWhiteSpace(seriesId))
|
||||
{
|
||||
seriesId = itemId.Identities
|
||||
.Where(id => id.Type == MetadataProviders.Tvdb.ToString())
|
||||
.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);
|
||||
}
|
||||
}
|
||||
await Identify(itemId).ConfigureAwait(false);
|
||||
seriesId = itemId.GetProviderId(MetadataProviders.Tvdb);
|
||||
}
|
||||
|
||||
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(seriesId))
|
||||
@@ -1239,27 +1225,20 @@ namespace MediaBrowser.Providers.TV
|
||||
get { return "TheTVDB"; }
|
||||
}
|
||||
|
||||
public async Task<SeriesIdentity> FindIdentity(SeriesInfo info)
|
||||
public async Task Identify(SeriesInfo info)
|
||||
{
|
||||
string tvdbId;
|
||||
if (!info.ProviderIds.TryGetValue(MetadataProviders.Tvdb.ToString(), out tvdbId))
|
||||
if (string.IsNullOrEmpty(info.GetProviderId(MetadataProviders.Tvdb)))
|
||||
{
|
||||
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();
|
||||
|
||||
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
|
||||
|
||||
Reference in New Issue
Block a user