Exemple #1
0
        protected override DateTime CompareDate(BaseItem item)
        {
            var seriesId = item.GetProviderId(MetadataProviders.Tvdb);

            if (!string.IsNullOrEmpty(seriesId))
            {
                // Process images
                var imagesXmlPath = Path.Combine(TvdbSeriesProvider.GetSeriesDataPath(ConfigurationManager.ApplicationPaths, seriesId), "banners.xml");

                var imagesFileInfo = new FileInfo(imagesXmlPath);

                if (imagesFileInfo.Exists)
                {
                    return(_fileSystem.GetLastWriteTimeUtc(imagesFileInfo));
                }
            }

            return(base.CompareDate(item));
        }
Exemple #2
0
        public bool HasChanged(IHasMetadata item, MetadataStatus status, IDirectoryService directoryService)
        {
            if (!TvdbSeriesProvider.Current.GetTvDbOptions().EnableAutomaticUpdates)
            {
                return(false);
            }

            if (TvdbSeriesProvider.IsValidSeries(item.ProviderIds))
            {
                // Process images
                var imagesXmlPath = Path.Combine(TvdbSeriesProvider.GetSeriesDataPath(_config.ApplicationPaths, item.ProviderIds), "banners.xml");

                var fileInfo = _fileSystem.GetFileInfo(imagesXmlPath);

                return(fileInfo.Exists && _fileSystem.GetLastWriteTimeUtc(fileInfo) > (status.DateLastMetadataRefresh ?? DateTime.MinValue));
            }

            return(false);
        }
Exemple #3
0
        protected override bool NeedsRefreshBasedOnCompareDate(BaseItem item, BaseProviderInfo providerInfo)
        {
            var season   = (Season)item;
            var seriesId = season.Series != null?season.Series.GetProviderId(MetadataProviders.Tvdb) : null;

            if (!string.IsNullOrEmpty(seriesId))
            {
                // Process images
                var imagesXmlPath = Path.Combine(TvdbSeriesProvider.GetSeriesDataPath(ConfigurationManager.ApplicationPaths, seriesId), "banners.xml");

                var imagesFileInfo = new FileInfo(imagesXmlPath);

                if (imagesFileInfo.Exists)
                {
                    return(_fileSystem.GetLastWriteTimeUtc(imagesFileInfo) > providerInfo.LastRefreshed);
                }
            }
            return(false);
        }
        public async Task <IEnumerable <RemoteImageInfo> > GetImages(IHasImages item, CancellationToken cancellationToken)
        {
            var season = (Season)item;
            var series = season.Series;

            var seriesId = series != null?series.GetProviderId(MetadataProviders.Tvdb) : null;

            if (!string.IsNullOrEmpty(seriesId) && season.IndexNumber.HasValue)
            {
                await TvdbSeriesProvider.Current.EnsureSeriesInfo(seriesId, series.GetPreferredMetadataLanguage(), cancellationToken).ConfigureAwait(false);

                // Process images
                var seriesDataPath = TvdbSeriesProvider.GetSeriesDataPath(_config.ApplicationPaths, 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);
                }

                try
                {
                    return(GetImages(path, item.GetPreferredMetadataLanguage(), seasonNumber, cancellationToken));
                }
                catch (FileNotFoundException)
                {
                    // No tvdb data yet. Don't blow up
                }
                catch (DirectoryNotFoundException)
                {
                    // No tvdb data yet. Don't blow up
                }
            }

            return(new RemoteImageInfo[] { });
        }
Exemple #5
0
        public async Task <IEnumerable <RemoteSearchResult> > GetSearchResults(EpisodeInfo searchInfo, CancellationToken cancellationToken)
        {
            var list = new List <RemoteSearchResult>();

            string seriesTvdbId;

            searchInfo.SeriesProviderIds.TryGetValue(MetadataProviders.Tvdb.ToString(), out seriesTvdbId);

            if (!string.IsNullOrEmpty(seriesTvdbId))
            {
                await TvdbSeriesProvider.Current.EnsureSeriesInfo(seriesTvdbId, searchInfo.MetadataLanguage,
                                                                  cancellationToken).ConfigureAwait(false);

                var seriesDataPath = TvdbSeriesProvider.GetSeriesDataPath(_config.ApplicationPaths, seriesTvdbId);

                try
                {
                    var item = FetchEpisodeData(searchInfo, seriesDataPath, searchInfo.SeriesProviderIds, cancellationToken);

                    if (item != null)
                    {
                        list.Add(new RemoteSearchResult
                        {
                            IndexNumber        = item.IndexNumber,
                            Name               = item.Name,
                            ParentIndexNumber  = item.ParentIndexNumber,
                            PremiereDate       = item.PremiereDate,
                            ProductionYear     = item.ProductionYear,
                            ProviderIds        = item.ProviderIds,
                            SearchProviderName = Name,
                            IndexNumberEnd     = item.IndexNumberEnd
                        });
                    }
                }
                catch (FileNotFoundException)
                {
                    // Don't fail the provider because this will just keep on going and going.
                }
            }

            return(list);
        }
        public async Task <MetadataResult <Episode> > GetMetadata(EpisodeInfo searchInfo, CancellationToken cancellationToken)
        {
            var result = new MetadataResult <Episode>();

            result.QueriedById = true;

            if (TvdbSeriesProvider.IsValidSeries(searchInfo.SeriesProviderIds) &&
                (searchInfo.IndexNumber.HasValue || searchInfo.PremiereDate.HasValue))
            {
                await TvdbSeriesProvider.Current.EnsureSeriesInfo(searchInfo.SeriesProviderIds, searchInfo.MetadataLanguage, cancellationToken).ConfigureAwait(false);

                var seriesDataPath = TvdbSeriesProvider.GetSeriesDataPath(_config.ApplicationPaths, searchInfo.SeriesProviderIds);

                var searchNumbers = new EpisodeNumbers();
                if (searchInfo.IndexNumber.HasValue)
                {
                    searchNumbers.EpisodeNumber = searchInfo.IndexNumber.Value;
                }
                searchNumbers.SeasonNumber     = searchInfo.ParentIndexNumber;
                searchNumbers.EpisodeNumberEnd = searchInfo.IndexNumberEnd ?? searchNumbers.EpisodeNumber;

                try
                {
                    result = FetchEpisodeData(searchInfo, searchNumbers, seriesDataPath, cancellationToken);
                }
                catch (FileNotFoundException)
                {
                    // Don't fail the provider because this will just keep on going and going.
                }
                catch (DirectoryNotFoundException)
                {
                    // Don't fail the provider because this will just keep on going and going.
                }
            }
            else
            {
                _logger.Debug("No series identity found for {0}", searchInfo.Name);
            }

            return(result);
        }
Exemple #7
0
        public Task <IEnumerable <RemoteImageInfo> > GetAllImages(BaseItem item, CancellationToken cancellationToken)
        {
            var episode = (Episode)item;

            var seriesId = episode.Series != null?episode.Series.GetProviderId(MetadataProviders.Tvdb) : null;

            if (!string.IsNullOrEmpty(seriesId))
            {
                // Process images
                var seriesDataPath = TvdbSeriesProvider.GetSeriesDataPath(_config.ApplicationPaths, seriesId);

                var files = TvdbEpisodeProvider.Current.GetEpisodeXmlFiles(episode, seriesDataPath);

                var result = files.Select(i => GetImageInfo(i, cancellationToken))
                             .Where(i => i != null);

                return(Task.FromResult(result));
            }

            return(Task.FromResult <IEnumerable <RemoteImageInfo> >(new RemoteImageInfo[] { }));
        }
        public Task <IEnumerable <RemoteImageInfo> > GetImages(IHasMetadata item, CancellationToken cancellationToken)
        {
            var episode = (Episode)item;
            var series  = episode.Series;

            if (series != null && TvdbSeriesProvider.IsValidSeries(series.ProviderIds))
            {
                // Process images
                var seriesDataPath = TvdbSeriesProvider.GetSeriesDataPath(_config.ApplicationPaths, series.ProviderIds);

                var nodes = TvdbEpisodeProvider.Current.GetEpisodeXmlNodes(seriesDataPath, episode.GetLookupInfo());

                var result = nodes.Select(i => GetImageInfo(i, cancellationToken))
                             .Where(i => i != null)
                             .ToList();

                return(Task.FromResult <IEnumerable <RemoteImageInfo> >(result));
            }

            return(Task.FromResult <IEnumerable <RemoteImageInfo> >(new RemoteImageInfo[] { }));
        }
        public bool HasChanged(IHasMetadata item, IDirectoryService directoryService, DateTime date)
        {
            if (!_config.Configuration.EnableTvDbUpdates)
            {
                return(false);
            }

            var tvdbId = item.GetProviderId(MetadataProviders.Tvdb);

            if (!String.IsNullOrEmpty(tvdbId))
            {
                // Process images
                var imagesXmlPath = Path.Combine(TvdbSeriesProvider.GetSeriesDataPath(_config.ApplicationPaths, tvdbId), "banners.xml");

                var fileInfo = new FileInfo(imagesXmlPath);

                return(fileInfo.Exists && _fileSystem.GetLastWriteTimeUtc(fileInfo) > date);
            }

            return(false);
        }
Exemple #10
0
        protected override bool NeedsRefreshBasedOnCompareDate(BaseItem item, BaseProviderInfo providerInfo)
        {
            var episode = (Episode)item;

            var seriesId = episode.Series != null?episode.Series.GetProviderId(MetadataProviders.Tvdb) : null;

            if (!string.IsNullOrEmpty(seriesId))
            {
                // Process images
                var seriesDataPath = TvdbSeriesProvider.GetSeriesDataPath(ConfigurationManager.ApplicationPaths, seriesId);

                var files = GetEpisodeXmlFiles(episode, seriesDataPath);

                if (files.Count > 0)
                {
                    return(files.Select(i => _fileSystem.GetLastWriteTimeUtc(i)).Max() > providerInfo.LastRefreshed);
                }
            }

            return(false);
        }
        public Task <IEnumerable <RemoteImageInfo> > GetImages(IHasImages item, CancellationToken cancellationToken)
        {
            var episode = (Episode)item;
            var series  = episode.Series;

            if (series != null && TvdbSeriesProvider.IsValidSeries(series.ProviderIds))
            {
                // Process images
                var seriesDataPath = TvdbSeriesProvider.GetSeriesDataPath(_config.ApplicationPaths, series.ProviderIds);
                var indexOffset    = TvdbSeriesProvider.GetSeriesOffset(series.ProviderIds) ?? 0;

                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);

                return(Task.FromResult(result));
            }

            return(Task.FromResult <IEnumerable <RemoteImageInfo> >(new RemoteImageInfo[] { }));
        }
Exemple #12
0
        public bool HasChanged(IHasMetadata item, IDirectoryService directoryService)
        {
            if (!TvdbSeriesProvider.Current.GetTvDbOptions().EnableAutomaticUpdates)
            {
                return(false);
            }

            var season = (Season)item;
            var series = season.Series;

            if (series != null && TvdbSeriesProvider.IsValidSeries(series.ProviderIds))
            {
                // Process images
                var imagesXmlPath = Path.Combine(TvdbSeriesProvider.GetSeriesDataPath(_config.ApplicationPaths, series.ProviderIds), "banners.xml");

                var fileInfo = _fileSystem.GetFileInfo(imagesXmlPath);

                return(fileInfo.Exists && _fileSystem.GetLastWriteTimeUtc(fileInfo) > item.DateLastRefreshed);
            }

            return(false);
        }
        public async Task <IEnumerable <RemoteImageInfo> > GetImages(IHasImages item, CancellationToken cancellationToken)
        {
            var series   = (Series)item;
            var seriesId = series.GetProviderId(MetadataProviders.Tvdb);

            if (!string.IsNullOrEmpty(seriesId))
            {
                var language = item.GetPreferredMetadataLanguage();

                await TvdbSeriesProvider.Current.EnsureSeriesInfo(seriesId, language, cancellationToken).ConfigureAwait(false);

                // Process images
                var seriesDataPath = TvdbSeriesProvider.GetSeriesDataPath(_config.ApplicationPaths, seriesId);

                var path = Path.Combine(seriesDataPath, "banners.xml");

                try
                {
                    var seriesOffset = TvdbSeriesProvider.GetSeriesOffset(series.ProviderIds);
                    if (seriesOffset != null && seriesOffset.Value != 0)
                    {
                        return(TvdbSeasonImageProvider.GetImages(path, language, seriesOffset.Value + 1, cancellationToken));
                    }

                    return(GetImages(path, language, cancellationToken));
                }
                catch (FileNotFoundException)
                {
                    // No tvdb data yet. Don't blow up
                }
                catch (DirectoryNotFoundException)
                {
                    // No tvdb data yet. Don't blow up
                }
            }

            return(new RemoteImageInfo[] { });
        }
Exemple #14
0
        public bool HasChanged(IHasMetadata item, IDirectoryService directoryService, DateTime date)
        {
            // Only enable for virtual items
            if (item.LocationType != LocationType.Virtual)
            {
                return(false);
            }

            var episode = (Episode)item;
            var series  = episode.Series;

            if (series != null && TvdbSeriesProvider.IsValidSeries(series.ProviderIds))
            {
                // Process images
                var seriesDataPath = TvdbSeriesProvider.GetSeriesDataPath(_config.ApplicationPaths, series.ProviderIds);

                var files = GetEpisodeXmlFiles(episode.ParentIndexNumber, episode.IndexNumber, episode.IndexNumberEnd, seriesDataPath);

                return(files.Any(i => _fileSystem.GetLastWriteTimeUtc(i) > date));
            }

            return(false);
        }
        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 result = new MetadataResult <Episode>();

            if (identity != null)
            {
                var seriesDataPath = TvdbSeriesProvider.GetSeriesDataPath(_config.ApplicationPaths, identity.SeriesId);

                try
                {
                    result.Item        = FetchEpisodeData(searchInfo, identity, seriesDataPath, searchInfo.SeriesProviderIds, cancellationToken);
                    result.HasMetadata = result.Item != null;
                }
                catch (FileNotFoundException)
                {
                    // Don't fail the provider because this will just keep on going and going.
                }
            }

            return(result);
        }
Exemple #16
0
        public async Task <MetadataResult <Episode> > GetMetadata(EpisodeInfo searchInfo, CancellationToken cancellationToken)
        {
            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.Value.SeriesId);

                try
                {
                    result = FetchEpisodeData(searchInfo, identity.Value, seriesDataPath, searchInfo.SeriesProviderIds, cancellationToken);
                }
                catch (FileNotFoundException)
                {
                    // Don't fail the provider because this will just keep on going and going.
                }
                catch (DirectoryNotFoundException)
                {
                    // Don't fail the provider because this will just keep on going and going.
                }
            }
            else
            {
                _logger.Debug("No series identity found for {0}", searchInfo.Name);
            }

            return(result);
        }
Exemple #17
0
        private async Task Run(IGrouping <string, Series> group, CancellationToken cancellationToken)
        {
            var tvdbId = group.Key;

            // Todo: Support series by imdb id
            var seriesProviderIds = new Dictionary <string, string>(StringComparer.OrdinalIgnoreCase);

            seriesProviderIds[MetadataProviders.Tvdb.ToString()] = tvdbId;

            var seriesDataPath = TvdbSeriesProvider.GetSeriesDataPath(_config.ApplicationPaths, seriesProviderIds);

            var episodeFiles = Directory.EnumerateFiles(seriesDataPath, "*.xml", SearchOption.TopDirectoryOnly)
                               .Select(Path.GetFileNameWithoutExtension)
                               .Where(i => i.StartsWith("episode-", StringComparison.OrdinalIgnoreCase))
                               .ToList();

            var episodeLookup = episodeFiles
                                .Select(i =>
            {
                var parts = i.Split('-');

                if (parts.Length == 3)
                {
                    int seasonNumber;

                    if (int.TryParse(parts[1], NumberStyles.Integer, _usCulture, out seasonNumber))
                    {
                        int episodeNumber;

                        if (int.TryParse(parts[2], NumberStyles.Integer, _usCulture, out episodeNumber))
                        {
                            return(new Tuple <int, int>(seasonNumber, episodeNumber));
                        }
                    }
                }

                return(new Tuple <int, int>(-1, -1));
            })
                                .Where(i => i.Item1 != -1 && i.Item2 != -1)
                                .ToList();

            var hasBadData = HasInvalidContent(group);

            var anySeasonsRemoved = await RemoveObsoleteOrMissingSeasons(group, episodeLookup)
                                    .ConfigureAwait(false);

            var anyEpisodesRemoved = await RemoveObsoleteOrMissingEpisodes(group, episodeLookup)
                                     .ConfigureAwait(false);

            var hasNewEpisodes = false;

            if (_config.Configuration.EnableInternetProviders)
            {
                var seriesConfig = _config.Configuration.MetadataOptions.FirstOrDefault(i => string.Equals(i.ItemType, typeof(Series).Name, StringComparison.OrdinalIgnoreCase));

                if (seriesConfig == null || !seriesConfig.DisabledMetadataFetchers.Contains(TvdbSeriesProvider.Current.Name, StringComparer.OrdinalIgnoreCase))
                {
                    hasNewEpisodes = await AddMissingEpisodes(group.ToList(), hasBadData, seriesDataPath, episodeLookup, cancellationToken)
                                     .ConfigureAwait(false);
                }
            }

            if (hasNewEpisodes || anySeasonsRemoved || anyEpisodesRemoved)
            {
                foreach (var series in group)
                {
                    var directoryService = new DirectoryService(_fileSystem);

                    await series.RefreshMetadata(new MetadataRefreshOptions(directoryService)
                    {
                    }, cancellationToken).ConfigureAwait(false);

                    await series.ValidateChildren(new Progress <double>(), cancellationToken, new MetadataRefreshOptions(directoryService), true)
                    .ConfigureAwait(false);
                }
            }
        }
Exemple #18
0
        private async Task Run(IGrouping <string, Series> group, bool addNewItems, CancellationToken cancellationToken)
        {
            var seriesList = group.ToList();
            var tvdbId     = seriesList
                             .Select(i => i.GetProviderId(MetadataProviders.Tvdb))
                             .FirstOrDefault(i => !string.IsNullOrWhiteSpace(i));

            // Todo: Support series by imdb id
            var seriesProviderIds = new Dictionary <string, string>(StringComparer.OrdinalIgnoreCase);

            seriesProviderIds[MetadataProviders.Tvdb.ToString()] = tvdbId;

            var seriesDataPath = TvdbSeriesProvider.GetSeriesDataPath(_config.ApplicationPaths, seriesProviderIds);

            // Doesn't have required provider id's
            if (string.IsNullOrWhiteSpace(seriesDataPath))
            {
                return;
            }

            var episodeFiles = _fileSystem.GetFilePaths(seriesDataPath)
                               .Where(i => string.Equals(Path.GetExtension(i), ".xml", StringComparison.OrdinalIgnoreCase))
                               .Select(Path.GetFileNameWithoutExtension)
                               .Where(i => i.StartsWith("episode-", StringComparison.OrdinalIgnoreCase))
                               .ToList();

            var episodeLookup = episodeFiles
                                .Select(i =>
            {
                var parts = i.Split('-');

                if (parts.Length == 3)
                {
                    int seasonNumber;

                    if (int.TryParse(parts[1], NumberStyles.Integer, _usCulture, out seasonNumber))
                    {
                        int episodeNumber;

                        if (int.TryParse(parts[2], NumberStyles.Integer, _usCulture, out episodeNumber))
                        {
                            return(new Tuple <int, int>(seasonNumber, episodeNumber));
                        }
                    }
                }

                return(new Tuple <int, int>(-1, -1));
            })
                                .Where(i => i.Item1 != -1 && i.Item2 != -1)
                                .ToList();

            var hasBadData = HasInvalidContent(seriesList);

            // Be conservative here to avoid creating missing episodes for ones they already have
            var addMissingEpisodes = !hasBadData && seriesList.All(i => _libraryManager.GetLibraryOptions(i).ImportMissingEpisodes);

            var anySeasonsRemoved = await RemoveObsoleteOrMissingSeasons(seriesList, episodeLookup)
                                    .ConfigureAwait(false);

            var anyEpisodesRemoved = await RemoveObsoleteOrMissingEpisodes(seriesList, episodeLookup, addMissingEpisodes)
                                     .ConfigureAwait(false);

            var hasNewEpisodes = false;

            if (addNewItems && seriesList.All(i => i.IsInternetMetadataEnabled()))
            {
                var seriesConfig = _config.Configuration.MetadataOptions.FirstOrDefault(i => string.Equals(i.ItemType, typeof(Series).Name, StringComparison.OrdinalIgnoreCase));

                if (seriesConfig == null || !seriesConfig.DisabledMetadataFetchers.Contains(TvdbSeriesProvider.Current.Name, StringComparer.OrdinalIgnoreCase))
                {
                    hasNewEpisodes = await AddMissingEpisodes(seriesList, addMissingEpisodes, seriesDataPath, episodeLookup, cancellationToken)
                                     .ConfigureAwait(false);
                }
            }

            if (hasNewEpisodes || anySeasonsRemoved || anyEpisodesRemoved)
            {
                foreach (var series in seriesList)
                {
                    var directoryService = new DirectoryService(_logger, _fileSystem);

                    await series.RefreshMetadata(new MetadataRefreshOptions(directoryService), cancellationToken).ConfigureAwait(false);

                    await series.ValidateChildren(new Progress <double>(), cancellationToken, new MetadataRefreshOptions(directoryService), true)
                    .ConfigureAwait(false);
                }
            }
        }
Exemple #19
0
        public async Task <bool> Run(Series series, bool addNewItems, CancellationToken cancellationToken)
        {
            var tvdbId = series.GetProviderId(MetadataProviders.Tvdb);

            // Todo: Support series by imdb id
            var seriesProviderIds = new Dictionary <string, string>(StringComparer.OrdinalIgnoreCase);

            seriesProviderIds[MetadataProviders.Tvdb.ToString()] = tvdbId;

            var seriesDataPath = TvdbSeriesProvider.GetSeriesDataPath(_config.ApplicationPaths, seriesProviderIds);

            // Doesn't have required provider id's
            if (string.IsNullOrWhiteSpace(seriesDataPath))
            {
                return(false);
            }

            // Check this in order to avoid logging an exception due to directory not existing
            if (!_fileSystem.DirectoryExists(seriesDataPath))
            {
                return(false);
            }

            var episodeFiles = _fileSystem.GetFilePaths(seriesDataPath)
                               .Where(i => string.Equals(Path.GetExtension(i), ".xml", StringComparison.OrdinalIgnoreCase))
                               .Select(Path.GetFileNameWithoutExtension)
                               .Where(i => i.StartsWith("episode-", StringComparison.OrdinalIgnoreCase))
                               .ToList();

            var episodeLookup = episodeFiles
                                .Select(i =>
            {
                var parts = i.Split('-');

                if (parts.Length == 3)
                {
                    int seasonNumber;

                    if (int.TryParse(parts[1], NumberStyles.Integer, _usCulture, out seasonNumber))
                    {
                        int episodeNumber;

                        if (int.TryParse(parts[2], NumberStyles.Integer, _usCulture, out episodeNumber))
                        {
                            return(new Tuple <int, int>(seasonNumber, episodeNumber));
                        }
                    }
                }

                return(new Tuple <int, int>(-1, -1));
            })
                                .Where(i => i.Item1 != -1 && i.Item2 != -1)
                                .ToList();

            var allRecursiveChildren = series.GetRecursiveChildren();

            var hasBadData = HasInvalidContent(series, allRecursiveChildren);

            // Be conservative here to avoid creating missing episodes for ones they already have
            var addMissingEpisodes = !hasBadData && _libraryManager.GetLibraryOptions(series).ImportMissingEpisodes;

            var anySeasonsRemoved = RemoveObsoleteOrMissingSeasons(series, allRecursiveChildren, episodeLookup);

            if (anySeasonsRemoved)
            {
                // refresh this
                allRecursiveChildren = series.GetRecursiveChildren();
            }

            var anyEpisodesRemoved = RemoveObsoleteOrMissingEpisodes(series, allRecursiveChildren, episodeLookup, addMissingEpisodes);

            if (anyEpisodesRemoved)
            {
                // refresh this
                allRecursiveChildren = series.GetRecursiveChildren();
            }

            var hasNewEpisodes = false;

            if (addNewItems && series.IsMetadataFetcherEnabled(_libraryManager.GetLibraryOptions(series), TvdbSeriesProvider.Current.Name))
            {
                hasNewEpisodes = await AddMissingEpisodes(series, allRecursiveChildren, addMissingEpisodes, seriesDataPath, episodeLookup, cancellationToken)
                                 .ConfigureAwait(false);
            }

            if (hasNewEpisodes || anySeasonsRemoved || anyEpisodesRemoved)
            {
                return(true);
            }

            return(false);
        }
Exemple #20
0
        /// <summary>
        /// Runs the specified progress.
        /// </summary>
        /// <param name="progress">The progress.</param>
        /// <param name="cancellationToken">The cancellation token.</param>
        /// <returns>Task.</returns>
        public async Task Run(IProgress <double> progress, CancellationToken cancellationToken)
        {
            if (!_config.Configuration.EnableInternetProviders ||
                _config.Configuration.InternetProviderExcludeTypes.Contains(typeof(Series).Name, StringComparer.OrdinalIgnoreCase))
            {
                progress.Report(100);
                return;
            }

            var path = TvdbSeriesProvider.GetSeriesDataPath(_config.CommonApplicationPaths);

            Directory.CreateDirectory(path);

            var timestampFile = Path.Combine(path, "time.txt");

            var timestampFileInfo = new FileInfo(timestampFile);

            // Don't check for tvdb updates anymore frequently than 24 hours
            if (timestampFileInfo.Exists && (DateTime.UtcNow - _fileSystem.GetLastWriteTimeUtc(timestampFileInfo)).TotalDays < 1)
            {
                return;
            }

            // Find out the last time we queried tvdb for updates
            var lastUpdateTime = timestampFileInfo.Exists ? File.ReadAllText(timestampFile, Encoding.UTF8) : string.Empty;

            string newUpdateTime;

            var existingDirectories = Directory.EnumerateDirectories(path).Select(Path.GetFileName).ToList();

            // If this is our first time, update all series
            if (string.IsNullOrEmpty(lastUpdateTime))
            {
                // First get tvdb server time
                using (var stream = await _httpClient.Get(new HttpRequestOptions
                {
                    Url = ServerTimeUrl,
                    CancellationToken = cancellationToken,
                    EnableHttpCompression = true,
                    ResourcePool = TvdbSeriesProvider.Current.TvDbResourcePool
                }).ConfigureAwait(false))
                {
                    newUpdateTime = GetUpdateTime(stream);
                }

                await UpdateSeries(existingDirectories, path, null, progress, cancellationToken).ConfigureAwait(false);
            }
            else
            {
                var seriesToUpdate = await GetSeriesIdsToUpdate(existingDirectories, lastUpdateTime, cancellationToken).ConfigureAwait(false);

                newUpdateTime = seriesToUpdate.Item2;

                long lastUpdateValue;

                long.TryParse(lastUpdateTime, NumberStyles.Any, UsCulture, out lastUpdateValue);

                var nullableUpdateValue = lastUpdateValue == 0 ? (long?)null : lastUpdateValue;

                await UpdateSeries(seriesToUpdate.Item1, path, nullableUpdateValue, progress, cancellationToken).ConfigureAwait(false);
            }

            File.WriteAllText(timestampFile, newUpdateTime, Encoding.UTF8);
            progress.Report(100);
        }
Exemple #21
0
        public async Task <MetadataResult <Episode> > GetMetadata(EpisodeInfo searchInfo, CancellationToken cancellationToken)
        {
            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 seriesProviderIds = new Dictionary <string, string>(StringComparer.OrdinalIgnoreCase);
                seriesProviderIds[MetadataProviders.Tvdb.ToString()] = identity.Value.SeriesId;
                var seriesDataPath = TvdbSeriesProvider.GetSeriesDataPath(_config.ApplicationPaths, seriesProviderIds);

                var searchNumbers = new EpisodeNumbers();
                searchNumbers.EpisodeNumber = identity.Value.EpisodeNumber;
                var seasonOffset = TvdbSeriesProvider.GetSeriesOffset(searchInfo.SeriesProviderIds) ?? 0;
                searchNumbers.SeasonNumber     = identity.Value.SeasonIndex + seasonOffset;
                searchNumbers.EpisodeNumberEnd = identity.Value.EpisodeNumberEnd ?? searchNumbers.EpisodeNumber;

                try
                {
                    result = FetchEpisodeData(searchInfo, searchNumbers, seriesDataPath, cancellationToken);
                }
                catch (FileNotFoundException)
                {
                    // Don't fail the provider because this will just keep on going and going.
                }
                catch (DirectoryNotFoundException)
                {
                    // Don't fail the provider because this will just keep on going and going.
                }
            }
            else if (TvdbSeriesProvider.IsValidSeries(searchInfo.SeriesProviderIds) && searchInfo.IndexNumber.HasValue)
            {
                var seriesDataPath = TvdbSeriesProvider.GetSeriesDataPath(_config.ApplicationPaths, searchInfo.SeriesProviderIds);

                var searchNumbers = new EpisodeNumbers();
                searchNumbers.EpisodeNumber    = searchInfo.IndexNumber.Value;
                searchNumbers.SeasonNumber     = searchInfo.ParentIndexNumber;
                searchNumbers.EpisodeNumberEnd = searchInfo.IndexNumberEnd ?? searchNumbers.EpisodeNumber;

                try
                {
                    result = FetchEpisodeData(searchInfo, searchNumbers, seriesDataPath, cancellationToken);
                }
                catch (FileNotFoundException)
                {
                    // Don't fail the provider because this will just keep on going and going.
                }
                catch (DirectoryNotFoundException)
                {
                    // Don't fail the provider because this will just keep on going and going.
                }
            }
            else
            {
                _logger.Debug("No series identity found for {0}", searchInfo.Name);
            }

            return(result);
        }
Exemple #22
0
        /// <summary>
        /// Runs the specified progress.
        /// </summary>
        /// <param name="progress">The progress.</param>
        /// <param name="cancellationToken">The cancellation token.</param>
        /// <returns>Task.</returns>
        public async Task Run(IProgress <double> progress, CancellationToken cancellationToken)
        {
            var seriesConfig = _config.Configuration.MetadataOptions.FirstOrDefault(i => string.Equals(i.ItemType, typeof(Series).Name, StringComparison.OrdinalIgnoreCase));

            if (seriesConfig != null && seriesConfig.DisabledMetadataFetchers.Contains(TvdbSeriesProvider.Current.Name, StringComparer.OrdinalIgnoreCase))
            {
                progress.Report(100);
                return;
            }

            var path = TvdbSeriesProvider.GetSeriesDataPath(_config.CommonApplicationPaths);

            _fileSystem.CreateDirectory(path);

            var timestampFile = Path.Combine(path, "time.txt");

            var timestampFileInfo = _fileSystem.GetFileInfo(timestampFile);

            // Don't check for tvdb updates anymore frequently than 24 hours
            if (timestampFileInfo.Exists && (DateTime.UtcNow - _fileSystem.GetLastWriteTimeUtc(timestampFileInfo)).TotalDays < 1)
            {
                return;
            }

            // Find out the last time we queried tvdb for updates
            var lastUpdateTime = timestampFileInfo.Exists ? _fileSystem.ReadAllText(timestampFile, Encoding.UTF8) : string.Empty;

            string newUpdateTime;

            var existingDirectories = _fileSystem.GetDirectoryPaths(path)
                                      .Select(Path.GetFileName)
                                      .ToList();

            var seriesList = _libraryManager.GetItemList(new InternalItemsQuery()
            {
                IncludeItemTypes             = new[] { typeof(Series).Name },
                Recursive                    = true,
                GroupByPresentationUniqueKey = false,
                DtoOptions                   = new DtoOptions(false)
                {
                    EnableImages = false
                }
            }).Cast <Series>()
                             .ToList();

            var seriesIdsInLibrary = seriesList
                                     .Where(i => !string.IsNullOrEmpty(i.GetProviderId(MetadataProviders.Tvdb)))
                                     .Select(i => i.GetProviderId(MetadataProviders.Tvdb))
                                     .ToList();

            var missingSeries = seriesIdsInLibrary.Except(existingDirectories, StringComparer.OrdinalIgnoreCase)
                                .ToList();

            var enableInternetProviders = seriesList.Count == 0 ? false : seriesList[0].IsInternetMetadataEnabled();

            if (!enableInternetProviders)
            {
                progress.Report(100);
                return;
            }

            // If this is our first time, update all series
            if (string.IsNullOrEmpty(lastUpdateTime))
            {
                // First get tvdb server time
                using (var stream = await _httpClient.Get(new HttpRequestOptions
                {
                    Url = ServerTimeUrl,
                    CancellationToken = cancellationToken,
                    EnableHttpCompression = true,
                    BufferContent = false
                }).ConfigureAwait(false))
                {
                    newUpdateTime = GetUpdateTime(stream);
                }

                existingDirectories.AddRange(missingSeries);

                await UpdateSeries(existingDirectories, path, null, progress, cancellationToken).ConfigureAwait(false);
            }
            else
            {
                var seriesToUpdate = await GetSeriesIdsToUpdate(existingDirectories, lastUpdateTime, cancellationToken).ConfigureAwait(false);

                newUpdateTime = seriesToUpdate.Item2;

                long lastUpdateValue;

                long.TryParse(lastUpdateTime, NumberStyles.Any, UsCulture, out lastUpdateValue);

                var nullableUpdateValue = lastUpdateValue == 0 ? (long?)null : lastUpdateValue;

                var listToUpdate = seriesToUpdate.Item1.ToList();
                listToUpdate.AddRange(missingSeries);

                await UpdateSeries(listToUpdate, path, nullableUpdateValue, progress, cancellationToken).ConfigureAwait(false);
            }

            _fileSystem.WriteAllText(timestampFile, newUpdateTime, Encoding.UTF8);
            progress.Report(100);
        }
Exemple #23
0
        public async Task Run(Series series, CancellationToken cancellationToken)
        {
            var tvdbId = series.GetProviderId(MetadataProviders.Tvdb);

            // Can't proceed without a tvdb id
            if (string.IsNullOrEmpty(tvdbId))
            {
                return;
            }

            var seriesDataPath = TvdbSeriesProvider.GetSeriesDataPath(_config.ApplicationPaths, tvdbId);

            var episodeFiles = Directory.EnumerateFiles(seriesDataPath, "*.xml", SearchOption.TopDirectoryOnly)
                               .Select(Path.GetFileNameWithoutExtension)
                               .Where(i => i.StartsWith("episode-", StringComparison.OrdinalIgnoreCase))
                               .ToList();

            var episodeLookup = episodeFiles
                                .Select(i =>
            {
                var parts = i.Split('-');

                if (parts.Length == 3)
                {
                    int seasonNumber;

                    if (int.TryParse(parts[1], NumberStyles.Integer, UsCulture, out seasonNumber))
                    {
                        int episodeNumber;

                        if (int.TryParse(parts[2], NumberStyles.Integer, UsCulture, out episodeNumber))
                        {
                            return(new Tuple <int, int>(seasonNumber, episodeNumber));
                        }
                    }
                }

                return(new Tuple <int, int>(-1, -1));
            })
                                .Where(i => i.Item1 != -1 && i.Item2 != -1)
                                .ToList();

            var anySeasonsRemoved = await RemoveObsoleteOrMissingSeasons(series, episodeLookup, cancellationToken)
                                    .ConfigureAwait(false);

            var anyEpisodesRemoved = await RemoveObsoleteOrMissingEpisodes(series, episodeLookup, cancellationToken)
                                     .ConfigureAwait(false);

            var hasNewEpisodes = false;

            if (_config.Configuration.EnableInternetProviders)
            {
                hasNewEpisodes = await AddMissingEpisodes(series, seriesDataPath, episodeLookup, cancellationToken)
                                 .ConfigureAwait(false);
            }

            if (hasNewEpisodes || anySeasonsRemoved || anyEpisodesRemoved)
            {
                await series.RefreshMetadata(cancellationToken, true)
                .ConfigureAwait(false);

                await series.ValidateChildren(new Progress <double>(), cancellationToken, true)
                .ConfigureAwait(false);
            }
        }