rework stub seasons

This commit is contained in:
Luke Pulverenti 2015-01-13 23:20:30 -05:00
parent 7771b89c6a
commit a2bb9ca624
6 changed files with 140 additions and 98 deletions

View File

@ -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" />

View 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;
}
}
}

View File

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

View File

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

View File

@ -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)
{ {

View File

@ -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:",