diff --git a/MediaBrowser.Controller/MediaBrowser.Controller.csproj b/MediaBrowser.Controller/MediaBrowser.Controller.csproj index 38955f728e..9915ac0441 100644 --- a/MediaBrowser.Controller/MediaBrowser.Controller.csproj +++ b/MediaBrowser.Controller/MediaBrowser.Controller.csproj @@ -188,6 +188,7 @@ + diff --git a/MediaBrowser.Controller/Providers/ISeriesOrderManager.cs b/MediaBrowser.Controller/Providers/ISeriesOrderManager.cs new file mode 100644 index 0000000000..a3adab1b90 --- /dev/null +++ b/MediaBrowser.Controller/Providers/ISeriesOrderManager.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using MediaBrowser.Common; + +namespace MediaBrowser.Controller.Providers +{ + public interface ISeriesOrderProvider + { + string OrderType { get; } + Task FindSeriesIndex(string seriesName); + } + + public static class SeriesOrderTypes + { + public const string Anime = "Anime"; + } + + public interface ISeriesOrderManager + { + Task FindSeriesIndex(string orderType, string seriesName); + void AddParts(IEnumerable orderProviders); + } +} diff --git a/MediaBrowser.Providers/Manager/SeriesOrderManager.cs b/MediaBrowser.Providers/Manager/SeriesOrderManager.cs new file mode 100644 index 0000000000..39175d1f94 --- /dev/null +++ b/MediaBrowser.Providers/Manager/SeriesOrderManager.cs @@ -0,0 +1,36 @@ +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using MediaBrowser.Common; +using MediaBrowser.Controller.Providers; + +namespace MediaBrowser.Providers.Manager +{ + public class SeriesOrderManager : ISeriesOrderManager + { + private Dictionary _providers; + + public void AddParts(IEnumerable orderProviders) + { + _providers = orderProviders + .GroupBy(p => p.OrderType) + .ToDictionary(g => g.Key, g => g.ToArray()); + } + + public async Task FindSeriesIndex(string orderType, string seriesName) + { + ISeriesOrderProvider[] providers; + if (!_providers.TryGetValue(orderType, out providers)) + return null; + + foreach (ISeriesOrderProvider provider in providers) + { + int? index = await provider.FindSeriesIndex(seriesName); + if (index != null) + return index; + } + + return null; + } + } +} \ No newline at end of file diff --git a/MediaBrowser.Providers/MediaBrowser.Providers.csproj b/MediaBrowser.Providers/MediaBrowser.Providers.csproj index f347e72290..ff39ec70d7 100644 --- a/MediaBrowser.Providers/MediaBrowser.Providers.csproj +++ b/MediaBrowser.Providers/MediaBrowser.Providers.csproj @@ -103,6 +103,7 @@ + diff --git a/MediaBrowser.Providers/TV/FanArtSeasonProvider.cs b/MediaBrowser.Providers/TV/FanArtSeasonProvider.cs index 470bd7b3a9..5bc58af915 100644 --- a/MediaBrowser.Providers/TV/FanArtSeasonProvider.cs +++ b/MediaBrowser.Providers/TV/FanArtSeasonProvider.cs @@ -77,7 +77,8 @@ namespace MediaBrowser.Providers.TV try { - AddImages(list, season.IndexNumber.Value, xmlPath, cancellationToken); + int seasonNumber = AdjustForSeriesOffset(series, season.IndexNumber.Value); + AddImages(list, seasonNumber, xmlPath, cancellationToken); } catch (FileNotFoundException) { @@ -115,6 +116,15 @@ namespace MediaBrowser.Providers.TV .ThenByDescending(i => i.VoteCount ?? 0); } + private int AdjustForSeriesOffset(Series series, int seasonNumber) + { + var offset = TvdbSeriesProvider.GetSeriesOffset(series.ProviderIds); + if (offset != null) + return (int)(seasonNumber + offset); + + return seasonNumber; + } + private void AddImages(List list, int seasonNumber, string xmlPath, CancellationToken cancellationToken) { using (var streamReader = new StreamReader(xmlPath, Encoding.UTF8)) diff --git a/MediaBrowser.Providers/TV/TvdbEpisodeImageProvider.cs b/MediaBrowser.Providers/TV/TvdbEpisodeImageProvider.cs index 36e349f600..ef37784501 100644 --- a/MediaBrowser.Providers/TV/TvdbEpisodeImageProvider.cs +++ b/MediaBrowser.Providers/TV/TvdbEpisodeImageProvider.cs @@ -62,8 +62,9 @@ namespace MediaBrowser.Providers.TV { // Process images var seriesDataPath = TvdbSeriesProvider.GetSeriesDataPath(_config.ApplicationPaths, seriesId); + var indexOffset = TvdbSeriesProvider.GetSeriesOffset(series.ProviderIds) ?? 0; - var files = TvdbEpisodeProvider.Current.GetEpisodeXmlFiles(episode.ParentIndexNumber, episode.IndexNumber, episode.IndexNumberEnd, seriesDataPath); + var files = TvdbEpisodeProvider.Current.GetEpisodeXmlFiles(episode.ParentIndexNumber + indexOffset, episode.IndexNumber, episode.IndexNumberEnd, seriesDataPath); var result = files.Select(i => GetImageInfo(i, cancellationToken)) .Where(i => i != null); diff --git a/MediaBrowser.Providers/TV/TvdbEpisodeProvider.cs b/MediaBrowser.Providers/TV/TvdbEpisodeProvider.cs index 5f6bdfa042..922c29fe97 100644 --- a/MediaBrowser.Providers/TV/TvdbEpisodeProvider.cs +++ b/MediaBrowser.Providers/TV/TvdbEpisodeProvider.cs @@ -52,7 +52,7 @@ namespace MediaBrowser.Providers.TV try { - var item = FetchEpisodeData(searchInfo, seriesDataPath, cancellationToken); + var item = FetchEpisodeData(searchInfo, seriesDataPath, searchInfo.SeriesProviderIds, cancellationToken); if (item != null) { @@ -96,7 +96,7 @@ namespace MediaBrowser.Providers.TV try { - result.Item = FetchEpisodeData(searchInfo, seriesDataPath, cancellationToken); + result.Item = FetchEpisodeData(searchInfo, seriesDataPath, searchInfo.SeriesProviderIds, cancellationToken); result.HasMetadata = result.Item != null; } catch (FileNotFoundException) @@ -213,7 +213,7 @@ namespace MediaBrowser.Providers.TV /// The series data path. /// The cancellation token. /// Task{System.Boolean}. - private Episode FetchEpisodeData(EpisodeInfo id, string seriesDataPath, CancellationToken cancellationToken) + private Episode FetchEpisodeData(EpisodeInfo id, string seriesDataPath, Dictionary seriesProviderIds, CancellationToken cancellationToken) { if (id.IndexNumber == null) { @@ -221,7 +221,8 @@ namespace MediaBrowser.Providers.TV } var episodeNumber = id.IndexNumber.Value; - var seasonNumber = id.ParentIndexNumber; + var seasonOffset = TvdbSeriesProvider.GetSeriesOffset(seriesProviderIds) ?? 0; + var seasonNumber = id.ParentIndexNumber + seasonOffset; if (seasonNumber == null) { diff --git a/MediaBrowser.Providers/TV/TvdbSeasonImageProvider.cs b/MediaBrowser.Providers/TV/TvdbSeasonImageProvider.cs index c0c103b7fb..5a9981c6e6 100644 --- a/MediaBrowser.Providers/TV/TvdbSeasonImageProvider.cs +++ b/MediaBrowser.Providers/TV/TvdbSeasonImageProvider.cs @@ -22,8 +22,9 @@ namespace MediaBrowser.Providers.TV { public class TvdbSeasonImageProvider : IRemoteImageProvider, IHasOrder, IHasChangeMonitor { + private static readonly CultureInfo UsCulture = new CultureInfo("en-US"); + private readonly IServerConfigurationManager _config; - private readonly CultureInfo _usCulture = new CultureInfo("en-US"); private readonly IHttpClient _httpClient; private readonly IFileSystem _fileSystem; @@ -77,7 +78,8 @@ namespace MediaBrowser.Providers.TV try { - return GetImages(path, item.GetPreferredMetadataLanguage(), season.IndexNumber.Value, cancellationToken); + int seasonNumber = AdjustForSeriesOffset(series, season.IndexNumber.Value); + return GetImages(path, item.GetPreferredMetadataLanguage(), seasonNumber, cancellationToken); } catch (FileNotFoundException) { @@ -88,7 +90,16 @@ namespace MediaBrowser.Providers.TV return new RemoteImageInfo[] { }; } - private IEnumerable GetImages(string xmlPath, string preferredLanguage, int seasonNumber, CancellationToken cancellationToken) + private int AdjustForSeriesOffset(Series series, int seasonNumber) + { + var offset = TvdbSeriesProvider.GetSeriesOffset(series.ProviderIds); + if (offset != null) + return (int) (seasonNumber + offset); + + return seasonNumber; + } + + internal static IEnumerable GetImages(string xmlPath, string preferredLanguage, int seasonNumber, CancellationToken cancellationToken) { var settings = new XmlReaderSettings { @@ -159,7 +170,7 @@ namespace MediaBrowser.Providers.TV .ToList(); } - private void AddImage(XmlReader reader, List images, int seasonNumber) + private static void AddImage(XmlReader reader, List images, int seasonNumber) { reader.MoveToContent(); @@ -186,7 +197,7 @@ namespace MediaBrowser.Providers.TV double rval; - if (double.TryParse(val, NumberStyles.Any, _usCulture, out rval)) + if (double.TryParse(val, NumberStyles.Any, UsCulture, out rval)) { rating = rval; } @@ -200,7 +211,7 @@ namespace MediaBrowser.Providers.TV int rval; - if (int.TryParse(val, NumberStyles.Integer, _usCulture, out rval)) + if (int.TryParse(val, NumberStyles.Integer, UsCulture, out rval)) { voteCount = rval; } @@ -237,12 +248,12 @@ namespace MediaBrowser.Providers.TV { int rval; - if (int.TryParse(resolutionParts[0], NumberStyles.Integer, _usCulture, out rval)) + if (int.TryParse(resolutionParts[0], NumberStyles.Integer, UsCulture, out rval)) { width = rval; } - if (int.TryParse(resolutionParts[1], NumberStyles.Integer, _usCulture, out rval)) + if (int.TryParse(resolutionParts[1], NumberStyles.Integer, UsCulture, out rval)) { height = rval; } @@ -285,7 +296,7 @@ namespace MediaBrowser.Providers.TV CommunityRating = rating, VoteCount = voteCount, Url = TVUtils.BannerUrl + url, - ProviderName = Name, + ProviderName = ProviderName, Language = language, Width = width, Height = height diff --git a/MediaBrowser.Providers/TV/TvdbSeriesImageProvider.cs b/MediaBrowser.Providers/TV/TvdbSeriesImageProvider.cs index 761c774435..d1171f34bf 100644 --- a/MediaBrowser.Providers/TV/TvdbSeriesImageProvider.cs +++ b/MediaBrowser.Providers/TV/TvdbSeriesImageProvider.cs @@ -77,6 +77,10 @@ namespace MediaBrowser.Providers.TV try { + var seriesOffset = TvdbSeriesProvider.GetSeriesOffset(series.ProviderIds); + if (seriesOffset != null) + return TvdbSeasonImageProvider.GetImages(path, language, seriesOffset.Value + 1, cancellationToken); + return GetImages(path, language, cancellationToken); } catch (FileNotFoundException) diff --git a/MediaBrowser.Providers/TV/TvdbSeriesProvider.cs b/MediaBrowser.Providers/TV/TvdbSeriesProvider.cs index 4b78c1a962..a76e101113 100644 --- a/MediaBrowser.Providers/TV/TvdbSeriesProvider.cs +++ b/MediaBrowser.Providers/TV/TvdbSeriesProvider.cs @@ -25,6 +25,8 @@ namespace MediaBrowser.Providers.TV { public class TvdbSeriesProvider : IRemoteMetadataProvider, IHasOrder { + internal const string TvdbSeriesOffset = "TvdbSeriesOffset"; + internal readonly SemaphoreSlim TvDbResourcePool = new SemaphoreSlim(2, 2); internal static TvdbSeriesProvider Current { get; private set; } private readonly IZipClient _zipClient; @@ -33,14 +35,16 @@ namespace MediaBrowser.Providers.TV private readonly IServerConfigurationManager _config; private readonly CultureInfo _usCulture = new CultureInfo("en-US"); private readonly ILogger _logger; + private readonly ISeriesOrderManager _seriesOrder; - public TvdbSeriesProvider(IZipClient zipClient, IHttpClient httpClient, IFileSystem fileSystem, IServerConfigurationManager config, ILogger logger) + public TvdbSeriesProvider(IZipClient zipClient, IHttpClient httpClient, IFileSystem fileSystem, IServerConfigurationManager config, ILogger logger, ISeriesOrderManager seriesOrder) { _zipClient = zipClient; _httpClient = httpClient; _fileSystem = fileSystem; _config = config; _logger = logger; + _seriesOrder = seriesOrder; Current = this; } @@ -92,11 +96,35 @@ namespace MediaBrowser.Providers.TV result.HasMetadata = true; FetchSeriesData(result.Item, seriesId, cancellationToken); + await FindAnimeSeriesIndex(result.Item, itemId).ConfigureAwait(false); } return result; } + private async Task FindAnimeSeriesIndex(Series series, SeriesInfo info) + { + var index = await _seriesOrder.FindSeriesIndex(SeriesOrderTypes.Anime, series.Name); + if (index == null) + return; + + var offset = info.AnimeSeriesIndex - index; + series.SetProviderId(TvdbSeriesOffset, offset.ToString()); + } + + internal static int? GetSeriesOffset(Dictionary seriesProviderIds) + { + string offsetString; + if (!seriesProviderIds.TryGetValue(TvdbSeriesOffset, out offsetString)) + return null; + + int offset; + if (int.TryParse(offsetString, out offset)) + return offset; + + return null; + } + /// /// Fetches the series data. /// diff --git a/MediaBrowser.ServerApplication/ApplicationHost.cs b/MediaBrowser.ServerApplication/ApplicationHost.cs index dff6242d1a..6083158bcc 100644 --- a/MediaBrowser.ServerApplication/ApplicationHost.cs +++ b/MediaBrowser.ServerApplication/ApplicationHost.cs @@ -158,6 +158,7 @@ namespace MediaBrowser.ServerApplication private IHttpServer HttpServer { get; set; } private IDtoService DtoService { get; set; } private IImageProcessor ImageProcessor { get; set; } + private ISeriesOrderManager SeriesOrderManager { get; set; } /// /// Gets or sets the media encoder. @@ -454,6 +455,9 @@ namespace MediaBrowser.ServerApplication ProviderManager = new ProviderManager(HttpClient, ServerConfigurationManager, LibraryMonitor, LogManager, FileSystemManager); RegisterSingleInstance(ProviderManager); + SeriesOrderManager = new SeriesOrderManager(); + RegisterSingleInstance(SeriesOrderManager); + RegisterSingleInstance(() => new SearchEngine(LogManager, LibraryManager, UserManager)); SessionManager = new SessionManager(UserDataManager, ServerConfigurationManager, Logger, UserRepository, LibraryManager, UserManager); @@ -681,6 +685,8 @@ namespace MediaBrowser.ServerApplication GetExports(), GetExports()); + SeriesOrderManager.AddParts(GetExports()); + ImageProcessor.AddParts(GetExports()); LiveTvManager.AddParts(GetExports()); diff --git a/MediaBrowser.sln b/MediaBrowser.sln index 7dc06fb0ce..c2f9dff59c 100644 --- a/MediaBrowser.sln +++ b/MediaBrowser.sln @@ -267,7 +267,4 @@ Global GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection - GlobalSection(Performance) = preSolution - HasPerformanceSessions = true - EndGlobalSection EndGlobal