using MediaBrowser.Common.IO; using MediaBrowser.Common.Net; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Library; using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Logging; using MediaBrowser.Model.Serialization; using MediaBrowser.Providers.Music; using MediaBrowser.Providers.TV; 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; namespace MediaBrowser.Providers.Movies { class FanartMovieUpdatesPostScanTask : ILibraryPostScanTask { private const string UpdatesUrl = "http://webservice.fanart.tv/v3/movies/latest?api_key={0}&date={1}"; /// /// The _HTTP client /// private readonly IHttpClient _httpClient; /// /// The _logger /// private readonly ILogger _logger; /// /// The _config /// private readonly IServerConfigurationManager _config; private readonly IJsonSerializer _jsonSerializer; private readonly IFileSystem _fileSystem; private static readonly CultureInfo UsCulture = new CultureInfo("en-US"); public FanartMovieUpdatesPostScanTask(IJsonSerializer jsonSerializer, IServerConfigurationManager config, ILogger logger, IHttpClient httpClient, IFileSystem fileSystem) { _jsonSerializer = jsonSerializer; _config = config; _logger = logger; _httpClient = httpClient; _fileSystem = fileSystem; } /// /// Runs the specified progress. /// /// The progress. /// The cancellation token. /// Task. public async Task Run(IProgress progress, CancellationToken cancellationToken) { var options = FanartSeriesProvider.Current.GetFanartOptions(); if (!options.EnableAutomaticUpdates) { progress.Report(100); return; } var path = FanartMovieImageProvider.GetMoviesDataPath(_config.CommonApplicationPaths); Directory.CreateDirectory(path); var timestampFile = Path.Combine(path, "time.txt"); var timestampFileInfo = new FileInfo(timestampFile); // Don't check for updates every single time if (timestampFileInfo.Exists && (DateTime.UtcNow - _fileSystem.GetLastWriteTimeUtc(timestampFileInfo)).TotalDays < 3) { return; } // Find out the last time we queried for updates var lastUpdateTime = timestampFileInfo.Exists ? File.ReadAllText(timestampFile, Encoding.UTF8) : string.Empty; var existingDirectories = Directory.EnumerateDirectories(path).Select(Path.GetFileName).ToList(); // If this is our first time, don't do any updates and just record the timestamp if (!string.IsNullOrEmpty(lastUpdateTime)) { var moviesToUpdate = await GetMovieIdsToUpdate(existingDirectories, lastUpdateTime, options, cancellationToken).ConfigureAwait(false); progress.Report(5); await UpdateMovies(moviesToUpdate, progress, cancellationToken).ConfigureAwait(false); } var newUpdateTime = Convert.ToInt64(DateTimeToUnixTimestamp(DateTime.UtcNow)).ToString(UsCulture); File.WriteAllText(timestampFile, newUpdateTime, Encoding.UTF8); progress.Report(100); } private async Task> GetMovieIdsToUpdate(IEnumerable existingIds, string lastUpdateTime, FanartOptions options, CancellationToken cancellationToken) { var url = string.Format(UpdatesUrl, FanartArtistProvider.ApiKey, lastUpdateTime); var clientKey = options.UserApiKey; if (!string.IsNullOrWhiteSpace(clientKey)) { url += "&client_key=" + clientKey; } // First get last time using (var stream = await _httpClient.Get(new HttpRequestOptions { Url = url, CancellationToken = cancellationToken, EnableHttpCompression = true, ResourcePool = FanartArtistProvider.Current.FanArtResourcePool }).ConfigureAwait(false)) { using (var reader = new StreamReader(stream)) { var json = await reader.ReadToEndAsync().ConfigureAwait(false); // If empty fanart will return a string of "null", rather than an empty list if (string.Equals(json, "null", StringComparison.OrdinalIgnoreCase)) { return new List(); } var updates = _jsonSerializer.DeserializeFromString>(json); var existingDictionary = existingIds.ToDictionary(i => i, StringComparer.OrdinalIgnoreCase); return updates.SelectMany(i => { var list = new List(); 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); } } } private async Task UpdateMovies(IEnumerable idList, IProgress progress, CancellationToken cancellationToken) { var list = idList.ToList(); var numComplete = 0; foreach (var id in list) { _logger.Info("Updating movie " + id); await FanartMovieImageProvider.Current.DownloadMovieJson(id, cancellationToken).ConfigureAwait(false); numComplete++; double percent = numComplete; percent /= list.Count; percent *= 95; progress.Report(percent + 5); } } /// /// Dates the time to unix timestamp. /// /// The date time. /// System.Double. private static double DateTimeToUnixTimestamp(DateTime dateTime) { return (dateTime - new DateTime(1970, 1, 1).ToUniversalTime()).TotalSeconds; } public class RootObject { 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; } } } }