rework stub seasons
This commit is contained in:
parent
7771b89c6a
commit
a2bb9ca624
|
@ -162,6 +162,7 @@
|
||||||
<Compile Include="Subtitles\ConfigurationExtension.cs" />
|
<Compile Include="Subtitles\ConfigurationExtension.cs" />
|
||||||
<Compile Include="Subtitles\OpenSubtitleDownloader.cs" />
|
<Compile Include="Subtitles\OpenSubtitleDownloader.cs" />
|
||||||
<Compile Include="Subtitles\SubtitleManager.cs" />
|
<Compile Include="Subtitles\SubtitleManager.cs" />
|
||||||
|
<Compile Include="TV\DummySeasonProvider.cs" />
|
||||||
<Compile Include="TV\EpisodeMetadataService.cs" />
|
<Compile Include="TV\EpisodeMetadataService.cs" />
|
||||||
<Compile Include="TV\FanArtTvUpdatesPostScanTask.cs" />
|
<Compile Include="TV\FanArtTvUpdatesPostScanTask.cs" />
|
||||||
<Compile Include="TV\FanArtSeasonProvider.cs" />
|
<Compile Include="TV\FanArtSeasonProvider.cs" />
|
||||||
|
|
121
MediaBrowser.Providers/TV/DummySeasonProvider.cs
Normal file
121
MediaBrowser.Providers/TV/DummySeasonProvider.cs
Normal file
|
@ -0,0 +1,121 @@
|
||||||
|
using MediaBrowser.Common.Extensions;
|
||||||
|
using MediaBrowser.Controller.Configuration;
|
||||||
|
using MediaBrowser.Controller.Entities.TV;
|
||||||
|
using MediaBrowser.Controller.Localization;
|
||||||
|
using MediaBrowser.Controller.Providers;
|
||||||
|
using MediaBrowser.Model.Logging;
|
||||||
|
using System;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace MediaBrowser.Providers.TV
|
||||||
|
{
|
||||||
|
public class DummySeasonProvider
|
||||||
|
{
|
||||||
|
private readonly IServerConfigurationManager _config;
|
||||||
|
private readonly ILogger _logger;
|
||||||
|
private readonly ILocalizationManager _localization;
|
||||||
|
|
||||||
|
private readonly CultureInfo _usCulture = new CultureInfo("en-US");
|
||||||
|
|
||||||
|
public DummySeasonProvider(IServerConfigurationManager config, ILogger logger, ILocalizationManager localization)
|
||||||
|
{
|
||||||
|
_config = config;
|
||||||
|
_logger = logger;
|
||||||
|
_localization = localization;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task Run(Series series, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var hasNewSeasons = await AddDummySeasonFolders(series, cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
|
if (hasNewSeasons)
|
||||||
|
{
|
||||||
|
var directoryService = new DirectoryService();
|
||||||
|
|
||||||
|
//await series.RefreshMetadata(new MetadataRefreshOptions(directoryService), cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
|
//await series.ValidateChildren(new Progress<double>(), cancellationToken, new MetadataRefreshOptions(directoryService))
|
||||||
|
// .ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<bool> AddDummySeasonFolders(Series series, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var episodesInSeriesFolder = series.RecursiveChildren
|
||||||
|
.OfType<Episode>()
|
||||||
|
.Where(i => !i.IsInSeasonFolder)
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
var hasChanges = false;
|
||||||
|
|
||||||
|
// Loop through the unique season numbers
|
||||||
|
foreach (var seasonNumber in episodesInSeriesFolder.Select(i => i.ParentIndexNumber ?? -1)
|
||||||
|
.Where(i => i >= 0)
|
||||||
|
.Distinct()
|
||||||
|
.ToList())
|
||||||
|
{
|
||||||
|
var hasSeason = series.Children.OfType<Season>()
|
||||||
|
.Any(i => i.IndexNumber.HasValue && i.IndexNumber.Value == seasonNumber);
|
||||||
|
|
||||||
|
if (!hasSeason)
|
||||||
|
{
|
||||||
|
await AddSeason(series, seasonNumber, cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
|
hasChanges = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unknown season - create a dummy season to put these under
|
||||||
|
if (episodesInSeriesFolder.Any(i => !i.ParentIndexNumber.HasValue))
|
||||||
|
{
|
||||||
|
var hasSeason = series.Children.OfType<Season>()
|
||||||
|
.Any(i => !i.IndexNumber.HasValue);
|
||||||
|
|
||||||
|
if (!hasSeason)
|
||||||
|
{
|
||||||
|
await AddSeason(series, null, cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
|
hasChanges = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return hasChanges;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds the season.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="series">The series.</param>
|
||||||
|
/// <param name="seasonNumber">The season number.</param>
|
||||||
|
/// <param name="cancellationToken">The cancellation token.</param>
|
||||||
|
/// <returns>Task{Season}.</returns>
|
||||||
|
public async Task<Season> AddSeason(Series series,
|
||||||
|
int? seasonNumber,
|
||||||
|
CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var seasonName = seasonNumber == 0 ?
|
||||||
|
_config.Configuration.SeasonZeroDisplayName :
|
||||||
|
(seasonNumber.HasValue ? string.Format(_localization.GetLocalizedString("NameSeasonNumber"), seasonNumber.Value.ToString(_usCulture)) : _localization.GetLocalizedString("NameSeasonUnknown"));
|
||||||
|
|
||||||
|
_logger.Info("Creating Season {0} entry for {1}", seasonName, series.Name);
|
||||||
|
|
||||||
|
var season = new Season
|
||||||
|
{
|
||||||
|
Name = seasonName,
|
||||||
|
IndexNumber = seasonNumber,
|
||||||
|
Parent = series,
|
||||||
|
DisplayMediaType = typeof(Season).Name,
|
||||||
|
Id = (series.Id + (seasonNumber ?? -1).ToString(_usCulture) + seasonName).GetMBId(typeof(Season))
|
||||||
|
};
|
||||||
|
|
||||||
|
await series.AddChild(season, cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
|
await season.RefreshMetadata(new MetadataRefreshOptions(), cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
|
return season;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -25,7 +25,7 @@ namespace MediaBrowser.Providers.TV
|
||||||
private readonly ILibraryManager _libraryManager;
|
private readonly ILibraryManager _libraryManager;
|
||||||
private readonly ILocalizationManager _localization;
|
private readonly ILocalizationManager _localization;
|
||||||
|
|
||||||
private static readonly CultureInfo UsCulture = new CultureInfo("en-US");
|
private readonly CultureInfo _usCulture = new CultureInfo("en-US");
|
||||||
|
|
||||||
public MissingEpisodeProvider(ILogger logger, IServerConfigurationManager config, ILibraryManager libraryManager, ILocalizationManager localization)
|
public MissingEpisodeProvider(ILogger logger, IServerConfigurationManager config, ILibraryManager libraryManager, ILocalizationManager localization)
|
||||||
{
|
{
|
||||||
|
@ -78,11 +78,11 @@ namespace MediaBrowser.Providers.TV
|
||||||
{
|
{
|
||||||
int seasonNumber;
|
int seasonNumber;
|
||||||
|
|
||||||
if (int.TryParse(parts[1], NumberStyles.Integer, UsCulture, out seasonNumber))
|
if (int.TryParse(parts[1], NumberStyles.Integer, _usCulture, out seasonNumber))
|
||||||
{
|
{
|
||||||
int episodeNumber;
|
int episodeNumber;
|
||||||
|
|
||||||
if (int.TryParse(parts[2], NumberStyles.Integer, UsCulture, out episodeNumber))
|
if (int.TryParse(parts[2], NumberStyles.Integer, _usCulture, out episodeNumber))
|
||||||
{
|
{
|
||||||
return new Tuple<int, int>(seasonNumber, episodeNumber);
|
return new Tuple<int, int>(seasonNumber, episodeNumber);
|
||||||
}
|
}
|
||||||
|
@ -103,12 +103,6 @@ namespace MediaBrowser.Providers.TV
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
|
|
||||||
var hasNewEpisodes = false;
|
var hasNewEpisodes = false;
|
||||||
var hasNewSeasons = false;
|
|
||||||
|
|
||||||
foreach (var series in group)
|
|
||||||
{
|
|
||||||
hasNewSeasons = await AddDummySeasonFolders(series, cancellationToken).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_config.Configuration.EnableInternetProviders)
|
if (_config.Configuration.EnableInternetProviders)
|
||||||
{
|
{
|
||||||
|
@ -121,7 +115,7 @@ namespace MediaBrowser.Providers.TV
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hasNewSeasons || hasNewEpisodes || anySeasonsRemoved || anyEpisodesRemoved)
|
if (hasNewEpisodes || anySeasonsRemoved || anyEpisodesRemoved)
|
||||||
{
|
{
|
||||||
foreach (var series in group)
|
foreach (var series in group)
|
||||||
{
|
{
|
||||||
|
@ -160,55 +154,6 @@ namespace MediaBrowser.Providers.TV
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// For series with episodes directly under the series folder, this adds dummy seasons to enable regular browsing and metadata
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="series"></param>
|
|
||||||
/// <param name="cancellationToken"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
private async Task<bool> AddDummySeasonFolders(Series series, CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
var episodesInSeriesFolder = series.RecursiveChildren
|
|
||||||
.OfType<Episode>()
|
|
||||||
.Where(i => !i.IsInSeasonFolder)
|
|
||||||
.ToList();
|
|
||||||
|
|
||||||
var hasChanges = false;
|
|
||||||
|
|
||||||
// Loop through the unique season numbers
|
|
||||||
foreach (var seasonNumber in episodesInSeriesFolder.Select(i => i.ParentIndexNumber ?? -1)
|
|
||||||
.Where(i => i >= 0)
|
|
||||||
.Distinct()
|
|
||||||
.ToList())
|
|
||||||
{
|
|
||||||
var hasSeason = series.Children.OfType<Season>()
|
|
||||||
.Any(i => i.IndexNumber.HasValue && i.IndexNumber.Value == seasonNumber);
|
|
||||||
|
|
||||||
if (!hasSeason)
|
|
||||||
{
|
|
||||||
await AddSeason(series, seasonNumber, cancellationToken).ConfigureAwait(false);
|
|
||||||
|
|
||||||
hasChanges = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Unknown season - create a dummy season to put these under
|
|
||||||
if (episodesInSeriesFolder.Any(i => !i.ParentIndexNumber.HasValue))
|
|
||||||
{
|
|
||||||
var hasSeason = series.Children.OfType<Season>()
|
|
||||||
.Any(i => !i.IndexNumber.HasValue);
|
|
||||||
|
|
||||||
if (!hasSeason)
|
|
||||||
{
|
|
||||||
await AddSeason(series, null, cancellationToken).ConfigureAwait(false);
|
|
||||||
|
|
||||||
hasChanges = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return hasChanges;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Adds the missing episodes.
|
/// Adds the missing episodes.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -449,10 +394,11 @@ namespace MediaBrowser.Providers.TV
|
||||||
|
|
||||||
if (season == null)
|
if (season == null)
|
||||||
{
|
{
|
||||||
season = await AddSeason(series, seasonNumber, cancellationToken).ConfigureAwait(false);
|
var provider = new DummySeasonProvider(_config, _logger, _localization);
|
||||||
|
season = await provider.AddSeason(series, seasonNumber, cancellationToken).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
var name = string.Format("Episode {0}", episodeNumber.ToString(UsCulture));
|
var name = string.Format("Episode {0}", episodeNumber.ToString(_usCulture));
|
||||||
|
|
||||||
var episode = new Episode
|
var episode = new Episode
|
||||||
{
|
{
|
||||||
|
@ -461,7 +407,7 @@ namespace MediaBrowser.Providers.TV
|
||||||
ParentIndexNumber = seasonNumber,
|
ParentIndexNumber = seasonNumber,
|
||||||
Parent = season,
|
Parent = season,
|
||||||
DisplayMediaType = typeof(Episode).Name,
|
DisplayMediaType = typeof(Episode).Name,
|
||||||
Id = (series.Id + seasonNumber.ToString(UsCulture) + name).GetMBId(typeof(Episode))
|
Id = (series.Id + seasonNumber.ToString(_usCulture) + name).GetMBId(typeof(Episode))
|
||||||
};
|
};
|
||||||
|
|
||||||
await season.AddChild(episode, cancellationToken).ConfigureAwait(false);
|
await season.AddChild(episode, cancellationToken).ConfigureAwait(false);
|
||||||
|
@ -471,39 +417,6 @@ namespace MediaBrowser.Providers.TV
|
||||||
}, cancellationToken).ConfigureAwait(false);
|
}, cancellationToken).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Adds the season.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="series">The series.</param>
|
|
||||||
/// <param name="seasonNumber">The season number.</param>
|
|
||||||
/// <param name="cancellationToken">The cancellation token.</param>
|
|
||||||
/// <returns>Task{Season}.</returns>
|
|
||||||
private async Task<Season> AddSeason(Series series,
|
|
||||||
int? seasonNumber,
|
|
||||||
CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
var seasonName = seasonNumber == 0 ?
|
|
||||||
_config.Configuration.SeasonZeroDisplayName :
|
|
||||||
(seasonNumber.HasValue ? string.Format(_localization.GetLocalizedString("NameSeasonNumber"), seasonNumber.Value.ToString(UsCulture)) : _localization.GetLocalizedString("NameSeasonUnknown"));
|
|
||||||
|
|
||||||
_logger.Info("Creating Season {0} entry for {1}", seasonName, series.Name);
|
|
||||||
|
|
||||||
var season = new Season
|
|
||||||
{
|
|
||||||
Name = seasonName,
|
|
||||||
IndexNumber = seasonNumber,
|
|
||||||
Parent = series,
|
|
||||||
DisplayMediaType = typeof(Season).Name,
|
|
||||||
Id = (series.Id + (seasonNumber ?? -1).ToString(UsCulture) + seasonName).GetMBId(typeof(Season))
|
|
||||||
};
|
|
||||||
|
|
||||||
await series.AddChild(season, cancellationToken).ConfigureAwait(false);
|
|
||||||
|
|
||||||
await season.RefreshMetadata(new MetadataRefreshOptions(), cancellationToken).ConfigureAwait(false);
|
|
||||||
|
|
||||||
return season;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the existing episode.
|
/// Gets the existing episode.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -551,7 +464,7 @@ namespace MediaBrowser.Providers.TV
|
||||||
private DateTime? GetAirDate(string seriesDataPath, int seasonNumber, int episodeNumber)
|
private DateTime? GetAirDate(string seriesDataPath, int seasonNumber, int episodeNumber)
|
||||||
{
|
{
|
||||||
// First open up the tvdb xml file and make sure it has valid data
|
// First open up the tvdb xml file and make sure it has valid data
|
||||||
var filename = string.Format("episode-{0}-{1}.xml", seasonNumber.ToString(UsCulture), episodeNumber.ToString(UsCulture));
|
var filename = string.Format("episode-{0}-{1}.xml", seasonNumber.ToString(_usCulture), episodeNumber.ToString(_usCulture));
|
||||||
|
|
||||||
var xmlPath = Path.Combine(seriesDataPath, filename);
|
var xmlPath = Path.Combine(seriesDataPath, filename);
|
||||||
|
|
||||||
|
|
|
@ -48,6 +48,13 @@ namespace MediaBrowser.Providers.TV
|
||||||
.OfType<Series>()
|
.OfType<Series>()
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
|
var provider = new DummySeasonProvider(_config, _logger, _localization);
|
||||||
|
|
||||||
|
foreach (var series in seriesList)
|
||||||
|
{
|
||||||
|
await provider.Run(series, cancellationToken).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
var seriesGroups = FindSeriesGroups(seriesList).Where(g => !string.IsNullOrEmpty(g.Key)).ToList();
|
var seriesGroups = FindSeriesGroups(seriesList).Where(g => !string.IsNullOrEmpty(g.Key)).ToList();
|
||||||
|
|
||||||
await new MissingEpisodeProvider(_logger, _config, _libraryManager, _localization).Run(seriesGroups, cancellationToken).ConfigureAwait(false);
|
await new MissingEpisodeProvider(_logger, _config, _libraryManager, _localization).Run(seriesGroups, cancellationToken).ConfigureAwait(false);
|
||||||
|
|
|
@ -125,7 +125,7 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Movies
|
||||||
Items = videos
|
Items = videos
|
||||||
};
|
};
|
||||||
|
|
||||||
var isInMixedFolder = resolverResult.Count > 0;
|
var isInMixedFolder = resolverResult.Count > 1;
|
||||||
|
|
||||||
foreach (var video in resolverResult)
|
foreach (var video in resolverResult)
|
||||||
{
|
{
|
||||||
|
|
|
@ -300,7 +300,7 @@
|
||||||
"LabelCachePath": "Cache path:",
|
"LabelCachePath": "Cache path:",
|
||||||
"LabelCachePathHelp": "Specify a custom location for server cache files, such as images.",
|
"LabelCachePathHelp": "Specify a custom location for server cache files, such as images.",
|
||||||
"LabelImagesByNamePath": "Images by name path:",
|
"LabelImagesByNamePath": "Images by name path:",
|
||||||
"LabelImagesByNamePathHelp": "Specify a custom location for downloaded actor, artist, genre and studio images.",
|
"LabelImagesByNamePathHelp": "Specify a custom location for downloaded actor, genre and studio images.",
|
||||||
"LabelMetadataPath": "Metadata path:",
|
"LabelMetadataPath": "Metadata path:",
|
||||||
"LabelMetadataPathHelp": "Specify a custom location for downloaded artwork and metadata, if not saving within media folders.",
|
"LabelMetadataPathHelp": "Specify a custom location for downloaded artwork and metadata, if not saving within media folders.",
|
||||||
"LabelTranscodingTempPath": "Transcoding temporary path:",
|
"LabelTranscodingTempPath": "Transcoding temporary path:",
|
||||||
|
|
Loading…
Reference in New Issue
Block a user