added new cabac value

This commit is contained in:
Luke Pulverenti
2014-10-23 00:26:01 -04:00
parent 35f40993b2
commit 5a5b48feff
56 changed files with 786 additions and 893 deletions

View File

@@ -286,6 +286,7 @@ namespace MediaBrowser.Providers.MediaInfo
{
var result = new MediaInfoLib().GetVideoInfo(video.Path);
videoStream.IsCabac = result.IsCabac ?? videoStream.IsCabac;
videoStream.IsInterlaced = result.IsInterlaced ?? videoStream.IsInterlaced;
videoStream.BitDepth = result.BitDepth ?? videoStream.BitDepth;
videoStream.RefFrames = result.RefFrames;

View File

@@ -18,7 +18,7 @@ namespace MediaBrowser.Providers.Movies
{
class FanartMovieUpdatesPostScanTask : ILibraryPostScanTask
{
private const string UpdatesUrl = "http://api.fanart.tv/webservice/newmovies/{0}/{1}/";
private const string UpdatesUrl = "http://webservice.fanart.tv/v3/movies/latest?api_key={0}&date={1}";
/// <summary>
/// The _HTTP client
@@ -118,11 +118,26 @@ namespace MediaBrowser.Providers.Movies
return new List<string>();
}
var updates = _jsonSerializer.DeserializeFromString<List<FanartUpdatesPostScanTask.FanArtUpdate>>(json);
var updates = _jsonSerializer.DeserializeFromString<List<RootObject>>(json);
var existingDictionary = existingIds.ToDictionary(i => i, StringComparer.OrdinalIgnoreCase);
return updates.Select(i => i.id).Where(existingDictionary.ContainsKey);
return updates.SelectMany(i =>
{
var list = new List<string>();
if (!string.IsNullOrWhiteSpace(i.imdb_id))
{
list.Add(i.imdb_id);
}
if (!string.IsNullOrWhiteSpace(i.tmdb_id))
{
list.Add(i.tmdb_id);
}
return list;
}).Where(existingDictionary.ContainsKey);
}
}
}
@@ -136,7 +151,7 @@ namespace MediaBrowser.Providers.Movies
{
_logger.Info("Updating movie " + id);
await FanartMovieImageProvider.Current.DownloadMovieXml(id, cancellationToken).ConfigureAwait(false);
await FanartMovieImageProvider.Current.DownloadMovieJson(id, cancellationToken).ConfigureAwait(false);
numComplete++;
double percent = numComplete;
@@ -157,9 +172,10 @@ namespace MediaBrowser.Providers.Movies
return (dateTime - new DateTime(1970, 1, 1).ToUniversalTime()).TotalSeconds;
}
public class FanArtUpdate
public class RootObject
{
public string id { get; set; }
public string tmdb_id { get; set; }
public string imdb_id { get; set; }
public string name { get; set; }
public string new_images { get; set; }
public string total_images { get; set; }

View File

@@ -1,25 +1,22 @@
using MediaBrowser.Common.Configuration;
using MediaBrowser.Common.IO;
using MediaBrowser.Common.Net;
using MediaBrowser.Controller.Channels;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Movies;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Channels;
using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Providers;
using MediaBrowser.Model.Serialization;
using MediaBrowser.Providers.Music;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Xml;
namespace MediaBrowser.Providers.Movies
{
@@ -29,16 +26,19 @@ namespace MediaBrowser.Providers.Movies
private readonly IServerConfigurationManager _config;
private readonly IHttpClient _httpClient;
private readonly IFileSystem _fileSystem;
private readonly IJsonSerializer _json;
private const string FanArtBaseUrl = "http://api.fanart.tv/webservice/movie/{0}/{1}/xml/all/1/1";
private const string FanArtBaseUrl = "http://webservice.fanart.tv/v3/movies/{1}?api_key={0}";
// &client_key=52c813aa7b8c8b3bb87f4797532a2f8c
internal static FanartMovieImageProvider Current;
public FanartMovieImageProvider(IServerConfigurationManager config, IHttpClient httpClient, IFileSystem fileSystem)
public FanartMovieImageProvider(IServerConfigurationManager config, IHttpClient httpClient, IFileSystem fileSystem, IJsonSerializer json)
{
_config = config;
_httpClient = httpClient;
_fileSystem = fileSystem;
_json = json;
Current = this;
}
@@ -88,13 +88,13 @@ namespace MediaBrowser.Providers.Movies
if (!string.IsNullOrEmpty(movieId))
{
await EnsureMovieXml(movieId, cancellationToken).ConfigureAwait(false);
await EnsureMovieJson(movieId, cancellationToken).ConfigureAwait(false);
var xmlPath = GetFanartXmlPath(movieId);
var path = GetFanartJsonPath(movieId);
try
{
AddImages(list, xmlPath, cancellationToken);
AddImages(list, path, cancellationToken);
}
catch (FileNotFoundException)
{
@@ -130,198 +130,63 @@ namespace MediaBrowser.Providers.Movies
.ThenByDescending(i => i.CommunityRating ?? 0);
}
private void AddImages(List<RemoteImageInfo> list, string xmlPath, CancellationToken cancellationToken)
private void AddImages(List<RemoteImageInfo> list, string path, CancellationToken cancellationToken)
{
using (var streamReader = new StreamReader(xmlPath, Encoding.UTF8))
{
// Use XmlReader for best performance
using (var reader = XmlReader.Create(streamReader, new XmlReaderSettings
{
CheckCharacters = false,
IgnoreProcessingInstructions = true,
IgnoreComments = true,
ValidationType = ValidationType.None
}))
{
reader.MoveToContent();
var root = _json.DeserializeFromFile<RootObject>(path);
// Loop through each element
while (reader.Read())
{
cancellationToken.ThrowIfCancellationRequested();
if (reader.NodeType == XmlNodeType.Element)
{
switch (reader.Name)
{
case "movie":
{
using (var subReader = reader.ReadSubtree())
{
AddImages(list, subReader, cancellationToken);
}
break;
}
default:
reader.Skip();
break;
}
}
}
}
}
AddImages(list, root, cancellationToken);
}
private void AddImages(List<RemoteImageInfo> list, XmlReader reader, CancellationToken cancellationToken)
private void AddImages(List<RemoteImageInfo> list, RootObject obj, CancellationToken cancellationToken)
{
reader.MoveToContent();
while (reader.Read())
{
if (reader.NodeType == XmlNodeType.Element)
{
switch (reader.Name)
{
case "hdmoviecleararts":
{
using (var subReader = reader.ReadSubtree())
{
PopulateImageCategory(list, subReader, cancellationToken, ImageType.Art, 1000, 562);
}
break;
}
case "hdmovielogos":
{
using (var subReader = reader.ReadSubtree())
{
PopulateImageCategory(list, subReader, cancellationToken, ImageType.Logo, 800, 310);
}
break;
}
case "moviediscs":
{
using (var subReader = reader.ReadSubtree())
{
PopulateImageCategory(list, subReader, cancellationToken, ImageType.Disc, 1000, 1000);
}
break;
}
case "movieposters":
{
using (var subReader = reader.ReadSubtree())
{
PopulateImageCategory(list, subReader, cancellationToken, ImageType.Primary, 1000, 1426);
}
break;
}
case "movielogos":
{
using (var subReader = reader.ReadSubtree())
{
PopulateImageCategory(list, subReader, cancellationToken, ImageType.Logo, 400, 155);
}
break;
}
case "moviearts":
{
using (var subReader = reader.ReadSubtree())
{
PopulateImageCategory(list, subReader, cancellationToken, ImageType.Art, 500, 281);
}
break;
}
case "moviethumbs":
{
using (var subReader = reader.ReadSubtree())
{
PopulateImageCategory(list, subReader, cancellationToken, ImageType.Thumb, 1000, 562);
}
break;
}
case "moviebanners":
{
using (var subReader = reader.ReadSubtree())
{
PopulateImageCategory(list, subReader, cancellationToken, ImageType.Banner, 1000, 185);
}
break;
}
case "moviebackgrounds":
{
using (var subReader = reader.ReadSubtree())
{
PopulateImageCategory(list, subReader, cancellationToken, ImageType.Backdrop, 1920, 1080);
}
break;
}
default:
{
using (reader.ReadSubtree())
{
}
break;
}
}
}
}
PopulateImages(list, obj.hdmovieclearart, ImageType.Art, 1000, 562);
PopulateImages(list, obj.hdmovielogo, ImageType.Logo, 800, 310);
PopulateImages(list, obj.moviedisc, ImageType.Disc, 1000, 1000);
PopulateImages(list, obj.movieposter, ImageType.Primary, 1000, 1426);
PopulateImages(list, obj.movielogo, ImageType.Logo, 400, 155);
PopulateImages(list, obj.movieart, ImageType.Art, 500, 281);
PopulateImages(list, obj.moviethumb, ImageType.Thumb, 1000, 562);
PopulateImages(list, obj.moviebanner, ImageType.Banner, 1000, 185);
PopulateImages(list, obj.moviebackground, ImageType.Backdrop, 1920, 1080);
}
private void PopulateImageCategory(List<RemoteImageInfo> list, XmlReader reader, CancellationToken cancellationToken, ImageType type, int width, int height)
private void PopulateImages(List<RemoteImageInfo> list, List<Image> images, ImageType type, int width, int height)
{
reader.MoveToContent();
while (reader.Read())
if (images == null)
{
cancellationToken.ThrowIfCancellationRequested();
if (reader.NodeType == XmlNodeType.Element)
{
switch (reader.Name)
{
case "hdmovielogo":
case "moviedisc":
case "hdmovieclearart":
case "movieposter":
case "movielogo":
case "movieart":
case "moviethumb":
case "moviebanner":
case "moviebackground":
{
var url = reader.GetAttribute("url");
if (!string.IsNullOrEmpty(url))
{
var likesString = reader.GetAttribute("likes");
int likes;
var info = new RemoteImageInfo
{
RatingType = RatingType.Likes,
Type = type,
Width = width,
Height = height,
ProviderName = Name,
Url = url,
Language = reader.GetAttribute("lang")
};
if (!string.IsNullOrEmpty(likesString) && int.TryParse(likesString, NumberStyles.Any, _usCulture, out likes))
{
info.CommunityRating = likes;
}
list.Add(info);
}
break;
}
default:
reader.Skip();
break;
}
}
return;
}
list.AddRange(images.Select(i =>
{
var url = i.url;
if (!string.IsNullOrEmpty(url))
{
var likesString = i.likes;
int likes;
var info = new RemoteImageInfo
{
RatingType = RatingType.Likes,
Type = type,
Width = width,
Height = height,
ProviderName = Name,
Url = url,
Language = i.lang
};
if (!string.IsNullOrEmpty(likesString) && int.TryParse(likesString, NumberStyles.Any, _usCulture, out likes))
{
info.CommunityRating = likes;
}
return info;
}
return null;
}).Where(i => i != null));
}
public int Order
@@ -347,13 +212,17 @@ namespace MediaBrowser.Providers.Movies
}
var id = item.GetProviderId(MetadataProviders.Tmdb);
if (string.IsNullOrEmpty(id))
{
id = item.GetProviderId(MetadataProviders.Imdb);
}
if (!string.IsNullOrEmpty(id))
{
// Process images
var xmlPath = GetFanartXmlPath(id);
var path = GetFanartJsonPath(id);
var fileInfo = new FileInfo(xmlPath);
var fileInfo = new FileInfo(path);
return !fileInfo.Exists || _fileSystem.GetLastWriteTimeUtc(fileInfo) > date;
}
@@ -364,12 +233,12 @@ namespace MediaBrowser.Providers.Movies
/// <summary>
/// Gets the movie data path.
/// </summary>
/// <param name="appPaths">The app paths.</param>
/// <param name="tmdbId">The TMDB id.</param>
/// <param name="appPaths">The application paths.</param>
/// <param name="id">The identifier.</param>
/// <returns>System.String.</returns>
internal static string GetMovieDataPath(IApplicationPaths appPaths, string tmdbId)
internal static string GetMovieDataPath(IApplicationPaths appPaths, string id)
{
var dataPath = Path.Combine(GetMoviesDataPath(appPaths), tmdbId);
var dataPath = Path.Combine(GetMoviesDataPath(appPaths), id);
return dataPath;
}
@@ -386,27 +255,27 @@ namespace MediaBrowser.Providers.Movies
return dataPath;
}
public string GetFanartXmlPath(string tmdbId)
public string GetFanartJsonPath(string id)
{
var movieDataPath = GetMovieDataPath(_config.ApplicationPaths, tmdbId);
return Path.Combine(movieDataPath, "fanart.xml");
var movieDataPath = GetMovieDataPath(_config.ApplicationPaths, id);
return Path.Combine(movieDataPath, "fanart.json");
}
/// <summary>
/// Downloads the movie XML.
/// Downloads the movie json.
/// </summary>
/// <param name="tmdbId">The TMDB id.</param>
/// <param name="id">The identifier.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task.</returns>
internal async Task DownloadMovieXml(string tmdbId, CancellationToken cancellationToken)
internal async Task DownloadMovieJson(string id, CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
var url = string.Format(FanArtBaseUrl, FanartArtistProvider.ApiKey, tmdbId);
var url = string.Format(FanArtBaseUrl, FanartArtistProvider.ApiKey, id);
var xmlPath = GetFanartXmlPath(tmdbId);
var path = GetFanartJsonPath(id);
Directory.CreateDirectory(Path.GetDirectoryName(xmlPath));
Directory.CreateDirectory(Path.GetDirectoryName(path));
using (var response = await _httpClient.Get(new HttpRequestOptions
{
@@ -416,17 +285,17 @@ namespace MediaBrowser.Providers.Movies
}).ConfigureAwait(false))
{
using (var xmlFileStream = _fileSystem.GetFileStream(xmlPath, FileMode.Create, FileAccess.Write, FileShare.Read, true))
using (var fileStream = _fileSystem.GetFileStream(path, FileMode.Create, FileAccess.Write, FileShare.Read, true))
{
await response.CopyToAsync(xmlFileStream).ConfigureAwait(false);
await response.CopyToAsync(fileStream).ConfigureAwait(false);
}
}
}
private readonly Task _cachedTask = Task.FromResult(true);
internal Task EnsureMovieXml(string tmdbId, CancellationToken cancellationToken)
internal Task EnsureMovieJson(string id, CancellationToken cancellationToken)
{
var path = GetFanartXmlPath(tmdbId);
var path = GetFanartJsonPath(id);
var fileInfo = _fileSystem.GetFileSystemInfo(path);
@@ -438,7 +307,31 @@ namespace MediaBrowser.Providers.Movies
}
}
return DownloadMovieXml(tmdbId, cancellationToken);
return DownloadMovieJson(id, cancellationToken);
}
public class Image
{
public string id { get; set; }
public string url { get; set; }
public string lang { get; set; }
public string likes { get; set; }
}
public class RootObject
{
public string name { get; set; }
public string tmdb_id { get; set; }
public string imdb_id { get; set; }
public List<Image> hdmovielogo { get; set; }
public List<Image> moviedisc { get; set; }
public List<Image> movielogo { get; set; }
public List<Image> movieposter { get; set; }
public List<Image> hdmovieclearart { get; set; }
public List<Image> movieart { get; set; }
public List<Image> moviebackground { get; set; }
public List<Image> moviebanner { get; set; }
public List<Image> moviethumb { get; set; }
}
}
}

View File

@@ -7,16 +7,15 @@ using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Providers;
using MediaBrowser.Model.Serialization;
using MediaBrowser.Providers.Music;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Xml;
namespace MediaBrowser.Providers.TV
{
@@ -26,12 +25,14 @@ namespace MediaBrowser.Providers.TV
private readonly IServerConfigurationManager _config;
private readonly IHttpClient _httpClient;
private readonly IFileSystem _fileSystem;
private readonly IJsonSerializer _json;
public FanArtSeasonProvider(IServerConfigurationManager config, IHttpClient httpClient, IFileSystem fileSystem)
public FanArtSeasonProvider(IServerConfigurationManager config, IHttpClient httpClient, IFileSystem fileSystem, IJsonSerializer json)
{
_config = config;
_httpClient = httpClient;
_fileSystem = fileSystem;
_json = json;
}
public string Name
@@ -71,14 +72,14 @@ namespace MediaBrowser.Providers.TV
if (!string.IsNullOrEmpty(id) && season.IndexNumber.HasValue)
{
await FanartSeriesProvider.Current.EnsureSeriesXml(id, cancellationToken).ConfigureAwait(false);
await FanartSeriesProvider.Current.EnsureSeriesJson(id, cancellationToken).ConfigureAwait(false);
var xmlPath = FanartSeriesProvider.Current.GetFanartXmlPath(id);
var path = FanartSeriesProvider.Current.GetFanartJsonPath(id);
try
{
int seasonNumber = AdjustForSeriesOffset(series, season.IndexNumber.Value);
AddImages(list, seasonNumber, xmlPath, cancellationToken);
AddImages(list, seasonNumber, path, cancellationToken);
}
catch (FileNotFoundException)
{
@@ -125,142 +126,67 @@ namespace MediaBrowser.Providers.TV
return seasonNumber;
}
private void AddImages(List<RemoteImageInfo> list, int seasonNumber, string xmlPath, CancellationToken cancellationToken)
private void AddImages(List<RemoteImageInfo> list, int seasonNumber, string path, CancellationToken cancellationToken)
{
using (var streamReader = new StreamReader(xmlPath, Encoding.UTF8))
{
// Use XmlReader for best performance
using (var reader = XmlReader.Create(streamReader, new XmlReaderSettings
{
CheckCharacters = false,
IgnoreProcessingInstructions = true,
IgnoreComments = true,
ValidationType = ValidationType.None
}))
{
reader.MoveToContent();
var root = _json.DeserializeFromFile<FanartSeriesProvider.RootObject>(path);
// Loop through each element
while (reader.Read())
{
cancellationToken.ThrowIfCancellationRequested();
if (reader.NodeType == XmlNodeType.Element)
{
switch (reader.Name)
{
case "series":
{
using (var subReader = reader.ReadSubtree())
{
AddImages(list, subReader, seasonNumber, cancellationToken);
}
break;
}
default:
reader.Skip();
break;
}
}
}
}
}
AddImages(list, root, seasonNumber, cancellationToken);
}
private void AddImages(List<RemoteImageInfo> list, XmlReader reader, int seasonNumber, CancellationToken cancellationToken)
private void AddImages(List<RemoteImageInfo> list, FanartSeriesProvider.RootObject obj, int seasonNumber, CancellationToken cancellationToken)
{
reader.MoveToContent();
while (reader.Read())
{
if (reader.NodeType == XmlNodeType.Element)
{
switch (reader.Name)
{
case "seasonthumbs":
{
using (var subReader = reader.ReadSubtree())
{
PopulateImageCategory(list, subReader, cancellationToken, ImageType.Thumb, 500, 281, seasonNumber);
}
break;
}
case "showbackgrounds":
{
using (var subReader = reader.ReadSubtree())
{
PopulateImageCategory(list, subReader, cancellationToken, ImageType.Backdrop, 1920, 1080, seasonNumber);
}
break;
}
default:
{
using (reader.ReadSubtree())
{
}
break;
}
}
}
}
PopulateImages(list, obj.seasonthumb, ImageType.Thumb, 500, 281, seasonNumber);
PopulateImages(list, obj.showbackground, ImageType.Backdrop, 1920, 1080, seasonNumber);
}
private void PopulateImageCategory(List<RemoteImageInfo> list, XmlReader reader, CancellationToken cancellationToken, ImageType type, int width, int height, int seasonNumber)
private void PopulateImages(List<RemoteImageInfo> list,
List<FanartSeriesProvider.Image> images,
ImageType type,
int width,
int height,
int seasonNumber)
{
reader.MoveToContent();
while (reader.Read())
if (images == null)
{
cancellationToken.ThrowIfCancellationRequested();
if (reader.NodeType == XmlNodeType.Element)
{
switch (reader.Name)
{
case "seasonthumb":
case "showbackground":
{
var url = reader.GetAttribute("url");
var season = reader.GetAttribute("season");
int imageSeasonNumber;
if (!string.IsNullOrEmpty(url) &&
!string.IsNullOrEmpty(season) &&
int.TryParse(season, NumberStyles.Any, _usCulture, out imageSeasonNumber) &&
seasonNumber == imageSeasonNumber)
{
var likesString = reader.GetAttribute("likes");
int likes;
var info = new RemoteImageInfo
{
RatingType = RatingType.Likes,
Type = type,
Width = width,
Height = height,
ProviderName = Name,
Url = url,
Language = reader.GetAttribute("lang")
};
if (!string.IsNullOrEmpty(likesString) && int.TryParse(likesString, NumberStyles.Any, _usCulture, out likes))
{
info.CommunityRating = likes;
}
list.Add(info);
}
break;
}
default:
reader.Skip();
break;
}
}
return;
}
list.AddRange(images.Select(i =>
{
var url = i.url;
var season = i.season;
int imageSeasonNumber;
if (!string.IsNullOrEmpty(url) &&
!string.IsNullOrEmpty(season) &&
int.TryParse(season, NumberStyles.Any, _usCulture, out imageSeasonNumber) &&
seasonNumber == imageSeasonNumber)
{
var likesString = i.likes;
int likes;
var info = new RemoteImageInfo
{
RatingType = RatingType.Likes,
Type = type,
Width = width,
Height = height,
ProviderName = Name,
Url = url,
Language = i.lang
};
if (!string.IsNullOrEmpty(likesString) && int.TryParse(likesString, NumberStyles.Any, _usCulture, out likes))
{
info.CommunityRating = likes;
}
return info;
}
return null;
}).Where(i => i != null));
}
public int Order
@@ -298,9 +224,9 @@ namespace MediaBrowser.Providers.TV
if (!String.IsNullOrEmpty(tvdbId))
{
// Process images
var imagesXmlPath = FanartSeriesProvider.Current.GetFanartXmlPath(tvdbId);
var imagesFilePath = FanartSeriesProvider.Current.GetFanartJsonPath(tvdbId);
var fileInfo = new FileInfo(imagesXmlPath);
var fileInfo = new FileInfo(imagesFilePath);
return !fileInfo.Exists || _fileSystem.GetLastWriteTimeUtc(fileInfo) > date;
}

View File

@@ -18,7 +18,7 @@ namespace MediaBrowser.Providers.TV
{
class FanArtTvUpdatesPostScanTask : ILibraryPostScanTask
{
private const string UpdatesUrl = "http://api.fanart.tv/webservice/newtv/{0}/{1}/";
private const string UpdatesUrl = "http://webservice.fanart.tv/v3/tv/latest?api_key={0}&date={1}";
/// <summary>
/// The _HTTP client
@@ -150,7 +150,7 @@ namespace MediaBrowser.Providers.TV
{
_logger.Info("Updating series " + id);
await FanartSeriesProvider.Current.DownloadSeriesXml(id, cancellationToken).ConfigureAwait(false);
await FanartSeriesProvider.Current.DownloadSeriesJson(id, cancellationToken).ConfigureAwait(false);
numComplete++;
double percent = numComplete;

View File

@@ -8,16 +8,15 @@ using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Providers;
using MediaBrowser.Model.Serialization;
using MediaBrowser.Providers.Music;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Xml;
namespace MediaBrowser.Providers.TV
{
@@ -27,16 +26,19 @@ namespace MediaBrowser.Providers.TV
private readonly IServerConfigurationManager _config;
private readonly IHttpClient _httpClient;
private readonly IFileSystem _fileSystem;
private readonly IJsonSerializer _json;
protected string FanArtBaseUrl = "http://api.fanart.tv/webservice/series/{0}/{1}/xml/all/1/1";
private const string FanArtBaseUrl = "http://webservice.fanart.tv/v3/tv/{1}?api_key={0}";
// &client_key=52c813aa7b8c8b3bb87f4797532a2f8c
internal static FanartSeriesProvider Current { get; private set; }
public FanartSeriesProvider(IServerConfigurationManager config, IHttpClient httpClient, IFileSystem fileSystem)
public FanartSeriesProvider(IServerConfigurationManager config, IHttpClient httpClient, IFileSystem fileSystem, IJsonSerializer json)
{
_config = config;
_httpClient = httpClient;
_fileSystem = fileSystem;
_json = json;
Current = this;
}
@@ -79,13 +81,13 @@ namespace MediaBrowser.Providers.TV
if (!string.IsNullOrEmpty(id))
{
await EnsureSeriesXml(id, cancellationToken).ConfigureAwait(false);
await EnsureSeriesJson(id, cancellationToken).ConfigureAwait(false);
var xmlPath = GetFanartXmlPath(id);
var path = GetFanartJsonPath(id);
try
{
AddImages(list, xmlPath, cancellationToken);
AddImages(list, path, cancellationToken);
}
catch (FileNotFoundException)
{
@@ -122,203 +124,72 @@ namespace MediaBrowser.Providers.TV
.ThenByDescending(i => i.VoteCount ?? 0);
}
private void AddImages(List<RemoteImageInfo> list, string xmlPath, CancellationToken cancellationToken)
private void AddImages(List<RemoteImageInfo> list, string path, CancellationToken cancellationToken)
{
using (var streamReader = new StreamReader(xmlPath, Encoding.UTF8))
{
// Use XmlReader for best performance
using (var reader = XmlReader.Create(streamReader, new XmlReaderSettings
{
CheckCharacters = false,
IgnoreProcessingInstructions = true,
IgnoreComments = true,
ValidationType = ValidationType.None
}))
{
reader.MoveToContent();
var root = _json.DeserializeFromFile<RootObject>(path);
// Loop through each element
while (reader.Read())
{
cancellationToken.ThrowIfCancellationRequested();
if (reader.NodeType == XmlNodeType.Element)
{
switch (reader.Name)
{
case "series":
{
using (var subReader = reader.ReadSubtree())
{
AddImages(list, subReader, cancellationToken);
}
break;
}
default:
reader.Skip();
break;
}
}
}
}
}
AddImages(list, root, cancellationToken);
}
private void AddImages(List<RemoteImageInfo> list, XmlReader reader, CancellationToken cancellationToken)
private void AddImages(List<RemoteImageInfo> list, RootObject obj, CancellationToken cancellationToken)
{
reader.MoveToContent();
while (reader.Read())
{
if (reader.NodeType == XmlNodeType.Element)
{
switch (reader.Name)
{
case "hdtvlogos":
{
using (var subReader = reader.ReadSubtree())
{
PopulateImageCategory(list, subReader, cancellationToken, ImageType.Logo, 800, 310);
}
break;
}
case "hdcleararts":
{
using (var subReader = reader.ReadSubtree())
{
PopulateImageCategory(list, subReader, cancellationToken, ImageType.Art, 1000, 562);
}
break;
}
case "clearlogos":
{
using (var subReader = reader.ReadSubtree())
{
PopulateImageCategory(list, subReader, cancellationToken, ImageType.Logo, 400, 155);
}
break;
}
case "cleararts":
{
using (var subReader = reader.ReadSubtree())
{
PopulateImageCategory(list, subReader, cancellationToken, ImageType.Art, 500, 281);
}
break;
}
case "showbackgrounds":
{
using (var subReader = reader.ReadSubtree())
{
PopulateImageCategory(list, subReader, cancellationToken, ImageType.Backdrop, 1920, 1080, true);
}
break;
}
case "seasonthumbs":
{
using (var subReader = reader.ReadSubtree())
{
PopulateImageCategory(list, subReader, cancellationToken, ImageType.Thumb, 500, 281);
}
break;
}
case "tvthumbs":
{
using (var subReader = reader.ReadSubtree())
{
PopulateImageCategory(list, subReader, cancellationToken, ImageType.Thumb, 500, 281);
}
break;
}
case "tvbanners":
{
using (var subReader = reader.ReadSubtree())
{
PopulateImageCategory(list, subReader, cancellationToken, ImageType.Banner, 1000, 185);
}
break;
}
case "tvposters":
{
using (var subReader = reader.ReadSubtree())
{
PopulateImageCategory(list, subReader, cancellationToken, ImageType.Primary, 1000, 1426);
}
break;
}
default:
{
using (reader.ReadSubtree())
{
}
break;
}
}
}
}
PopulateImages(list, obj.hdtvlogo, ImageType.Logo, 800, 310);
PopulateImages(list, obj.hdclearart, ImageType.Art, 1000, 562);
PopulateImages(list, obj.clearlogo, ImageType.Logo, 400, 155);
PopulateImages(list, obj.clearart, ImageType.Art, 500, 281);
PopulateImages(list, obj.showbackground, ImageType.Backdrop, 1920, 1080, true);
PopulateImages(list, obj.seasonthumb, ImageType.Thumb, 500, 281);
PopulateImages(list, obj.tvthumb, ImageType.Thumb, 500, 281);
PopulateImages(list, obj.tvbanner, ImageType.Banner, 1000, 185);
PopulateImages(list, obj.tvposter, ImageType.Primary, 1000, 1426);
}
private void PopulateImageCategory(List<RemoteImageInfo> list, XmlReader reader, CancellationToken cancellationToken, ImageType type, int width, int height, bool allowSeasonAll = false)
private void PopulateImages(List<RemoteImageInfo> list,
List<Image> images,
ImageType type,
int width,
int height,
bool allowSeasonAll = false)
{
reader.MoveToContent();
while (reader.Read())
if (images == null)
{
cancellationToken.ThrowIfCancellationRequested();
if (reader.NodeType == XmlNodeType.Element)
{
switch (reader.Name)
{
case "hdtvlogo":
case "hdclearart":
case "clearlogo":
case "clearart":
case "showbackground":
case "seasonthumb":
case "tvthumb":
case "tvbanner":
case "tvposter":
{
var url = reader.GetAttribute("url");
var season = reader.GetAttribute("season");
var isSeasonValid = string.IsNullOrEmpty(season) ||
(allowSeasonAll && string.Equals(season, "all", StringComparison.OrdinalIgnoreCase));
if (!string.IsNullOrEmpty(url) && isSeasonValid)
{
var likesString = reader.GetAttribute("likes");
int likes;
var info = new RemoteImageInfo
{
RatingType = RatingType.Likes,
Type = type,
Width = width,
Height = height,
ProviderName = Name,
Url = url,
Language = reader.GetAttribute("lang")
};
if (!string.IsNullOrEmpty(likesString) && int.TryParse(likesString, NumberStyles.Any, _usCulture, out likes))
{
info.CommunityRating = likes;
}
list.Add(info);
}
break;
}
default:
reader.Skip();
break;
}
}
return;
}
list.AddRange(images.Select(i =>
{
var url = i.url;
var season = i.season;
var isSeasonValid = string.IsNullOrEmpty(season) ||
(allowSeasonAll && string.Equals(season, "all", StringComparison.OrdinalIgnoreCase));
if (!string.IsNullOrEmpty(url) && isSeasonValid)
{
var likesString = i.likes;
int likes;
var info = new RemoteImageInfo
{
RatingType = RatingType.Likes,
Type = type,
Width = width,
Height = height,
ProviderName = Name,
Url = url,
Language = i.lang
};
if (!string.IsNullOrEmpty(likesString) && int.TryParse(likesString, NumberStyles.Any, _usCulture, out likes))
{
info.CommunityRating = likes;
}
return info;
}
return null;
}).Where(i => i != null));
}
public int Order
@@ -361,23 +232,23 @@ namespace MediaBrowser.Providers.TV
return dataPath;
}
public string GetFanartXmlPath(string tvdbId)
public string GetFanartJsonPath(string tvdbId)
{
var dataPath = GetSeriesDataPath(_config.ApplicationPaths, tvdbId);
return Path.Combine(dataPath, "fanart.xml");
return Path.Combine(dataPath, "fanart.json");
}
private readonly SemaphoreSlim _ensureSemaphore = new SemaphoreSlim(1, 1);
internal async Task EnsureSeriesXml(string tvdbId, CancellationToken cancellationToken)
internal async Task EnsureSeriesJson(string tvdbId, CancellationToken cancellationToken)
{
var xmlPath = GetFanartXmlPath(tvdbId);
var path = GetFanartJsonPath(tvdbId);
// Only allow one thread in here at a time since every season will be calling this method, possibly concurrently
await _ensureSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false);
try
{
var fileInfo = _fileSystem.GetFileSystemInfo(xmlPath);
var fileInfo = _fileSystem.GetFileSystemInfo(path);
if (fileInfo.Exists)
{
@@ -387,7 +258,7 @@ namespace MediaBrowser.Providers.TV
}
}
await DownloadSeriesXml(tvdbId, cancellationToken).ConfigureAwait(false);
await DownloadSeriesJson(tvdbId, cancellationToken).ConfigureAwait(false);
}
finally
{
@@ -396,20 +267,20 @@ namespace MediaBrowser.Providers.TV
}
/// <summary>
/// Downloads the series XML.
/// Downloads the series json.
/// </summary>
/// <param name="tvdbId">The TVDB id.</param>
/// <param name="tvdbId">The TVDB identifier.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task.</returns>
internal async Task DownloadSeriesXml(string tvdbId, CancellationToken cancellationToken)
internal async Task DownloadSeriesJson(string tvdbId, CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
var url = string.Format(FanArtBaseUrl, FanartArtistProvider.ApiKey, tvdbId);
var xmlPath = GetFanartXmlPath(tvdbId);
var path = GetFanartJsonPath(tvdbId);
Directory.CreateDirectory(Path.GetDirectoryName(xmlPath));
Directory.CreateDirectory(Path.GetDirectoryName(path));
using (var response = await _httpClient.Get(new HttpRequestOptions
{
@@ -419,9 +290,9 @@ namespace MediaBrowser.Providers.TV
}).ConfigureAwait(false))
{
using (var xmlFileStream = _fileSystem.GetFileStream(xmlPath, FileMode.Create, FileAccess.Write, FileShare.Read, true))
using (var fileStream = _fileSystem.GetFileStream(path, FileMode.Create, FileAccess.Write, FileShare.Read, true))
{
await response.CopyToAsync(xmlFileStream).ConfigureAwait(false);
await response.CopyToAsync(fileStream).ConfigureAwait(false);
}
}
}
@@ -438,14 +309,41 @@ namespace MediaBrowser.Providers.TV
if (!String.IsNullOrEmpty(tvdbId))
{
// Process images
var imagesXmlPath = GetFanartXmlPath(tvdbId);
var imagesFilePath = GetFanartJsonPath(tvdbId);
var fileInfo = new FileInfo(imagesXmlPath);
var fileInfo = new FileInfo(imagesFilePath);
return !fileInfo.Exists || _fileSystem.GetLastWriteTimeUtc(fileInfo) > date;
}
return false;
}
public class Image
{
public string id { get; set; }
public string url { get; set; }
public string lang { get; set; }
public string likes { get; set; }
public string season { get; set; }
}
public class RootObject
{
public string name { get; set; }
public string thetvdb_id { get; set; }
public List<Image> clearlogo { get; set; }
public List<Image> hdtvlogo { get; set; }
public List<Image> clearart { get; set; }
public List<Image> showbackground { get; set; }
public List<Image> tvthumb { get; set; }
public List<Image> seasonposter { get; set; }
public List<Image> seasonthumb { get; set; }
public List<Image> hdclearart { get; set; }
public List<Image> tvbanner { get; set; }
public List<Image> characterart { get; set; }
public List<Image> tvposter { get; set; }
public List<Image> seasonbanner { get; set; }
}
}
}