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; var hasNewSeasons = false; if (series.ContainsEpisodesWithoutSeasonFolders) { hasNewSeasons = await AddDummySeasonFolders(series, cancellationToken).ConfigureAwait(false); } if (_config.Configuration.EnableInternetProviders) { hasNewEpisodes = await AddMissingEpisodes(series, seriesDataPath, episodeLookup, cancellationToken) .ConfigureAwait(false); } if (hasNewSeasons || hasNewEpisodes || anySeasonsRemoved || anyEpisodesRemoved) { await series.RefreshMetadata(cancellationToken, true) .ConfigureAwait(false); await series.ValidateChildren(new Progress<double>(), cancellationToken, true) .ConfigureAwait(false); } }