diff --git a/MediaBrowser.Model/Configuration/ServerConfiguration.cs b/MediaBrowser.Model/Configuration/ServerConfiguration.cs index 664fe86da1..72a80ffadc 100644 --- a/MediaBrowser.Model/Configuration/ServerConfiguration.cs +++ b/MediaBrowser.Model/Configuration/ServerConfiguration.cs @@ -44,6 +44,12 @@ namespace MediaBrowser.Model.Configuration /// /// The item by name path. public string ItemsByNamePath { get; set; } + + /// + /// Gets or sets the display name of the season zero. + /// + /// The display name of the season zero. + public string SeasonZeroDisplayName { get; set; } /// /// Gets or sets the weather unit to use when displaying weather @@ -260,6 +266,8 @@ namespace MediaBrowser.Model.Configuration SortReplaceCharacters = new[] { ".", "+", "%" }; SortRemoveCharacters = new[] { ",", "&", "-", "{", "}", "'" }; SortRemoveWords = new[] { "the", "a", "an" }; + + SeasonZeroDisplayName = "Specials"; } } } diff --git a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs index fbf2dfc70b..13857a656e 100644 --- a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs +++ b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs @@ -4,6 +4,7 @@ using MediaBrowser.Common.ScheduledTasks; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Audio; +using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.IO; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Persistence; @@ -159,6 +160,7 @@ namespace MediaBrowser.Server.Implementations.Library /// The resolvers. /// The intro providers. /// The item comparers. + /// The prescan tasks. public void AddParts(IEnumerable rules, IEnumerable pluginFolders, IEnumerable resolvers, @@ -211,9 +213,11 @@ namespace MediaBrowser.Server.Implementations.Library private bool _internetProvidersEnabled; private bool _peopleImageFetchingEnabled; private string _itemsByNamePath; + private string _seasonZeroDisplayName; private void RecordConfigurationValues(ServerConfiguration configuration) { + _seasonZeroDisplayName = ConfigurationManager.Configuration.SeasonZeroDisplayName; _itemsByNamePath = ConfigurationManager.ApplicationPaths.ItemsByNamePath; _internetProvidersEnabled = configuration.EnableInternetProviders; _peopleImageFetchingEnabled = configuration.InternetProviderExcludeTypes == null || !configuration.InternetProviderExcludeTypes.Contains(typeof(Person).Name, StringComparer.OrdinalIgnoreCase); @@ -239,17 +243,25 @@ namespace MediaBrowser.Server.Implementations.Library refreshPeopleAfterUpdate = newConfigurationFetchesPeopleImages && !_peopleImageFetchingEnabled; } - var ibnPathChanged = !string.Equals(_itemsByNamePath, ConfigurationManager.ApplicationPaths.ItemsByNamePath); + var ibnPathChanged = !string.Equals(_itemsByNamePath, ConfigurationManager.ApplicationPaths.ItemsByNamePath, StringComparison.CurrentCulture); if (ibnPathChanged) { _itemsByName.Clear(); } + var newSeasonZeroName = ConfigurationManager.Configuration.SeasonZeroDisplayName; + var seasonZeroNameChanged = !string.Equals(_seasonZeroDisplayName, newSeasonZeroName, StringComparison.CurrentCulture); + RecordConfigurationValues(config); - Task.Run(() => + Task.Run(async () => { + if (seasonZeroNameChanged) + { + await UpdateSeasonZeroNames(newSeasonZeroName, CancellationToken.None).ConfigureAwait(false); + } + // Any number of configuration settings could change the way the library is refreshed, so do that now _taskManager.CancelIfRunningAndQueue(); @@ -260,6 +272,27 @@ namespace MediaBrowser.Server.Implementations.Library }); } + /// + /// Updates the season zero names. + /// + /// The new name. + /// The cancellation token. + /// Task. + private Task UpdateSeasonZeroNames(string newName, CancellationToken cancellationToken) + { + var seasons = RootFolder.RecursiveChildren + .OfType() + .Where(i => i.IndexNumber.HasValue && i.IndexNumber.Value == 0 && !string.Equals(i.Name, newName, StringComparison.CurrentCulture)) + .ToList(); + + foreach (var season in seasons) + { + season.Name = newName; + } + + return UpdateItems(seasons, cancellationToken); + } + /// /// Creates the library items cache. /// @@ -1075,30 +1108,49 @@ namespace MediaBrowser.Server.Implementations.Library } /// - /// Updates the item. + /// Updates the items. /// - /// The item. + /// The items. /// The cancellation token. /// Task. - public async Task UpdateItem(BaseItem item, CancellationToken cancellationToken) + private async Task UpdateItems(IEnumerable items, CancellationToken cancellationToken) { - await ItemRepository.SaveItem(item, cancellationToken).ConfigureAwait(false); + var list = items.ToList(); + + await ItemRepository.SaveItems(list, cancellationToken).ConfigureAwait(false); - UpdateItemInLibraryCache(item); + foreach (var item in list) + { + UpdateItemInLibraryCache(item); + } if (ItemUpdated != null) { - try - { - ItemUpdated(this, new ItemChangeEventArgs { Item = item }); - } - catch (Exception ex) + foreach (var item in list) { - _logger.ErrorException("Error in ItemUpdated event handler", ex); + try + { + ItemUpdated(this, new ItemChangeEventArgs { Item = item }); + } + catch (Exception ex) + { + _logger.ErrorException("Error in ItemUpdated event handler", ex); + } } } } + /// + /// Updates the item. + /// + /// The item. + /// The cancellation token. + /// Task. + public Task UpdateItem(BaseItem item, CancellationToken cancellationToken) + { + return UpdateItems(new[] { item }, cancellationToken); + } + /// /// Reports the item removed. /// diff --git a/MediaBrowser.Server.Implementations/Library/Resolvers/TV/SeasonResolver.cs b/MediaBrowser.Server.Implementations/Library/Resolvers/TV/SeasonResolver.cs index 07fb2f4864..7ad5d08db6 100644 --- a/MediaBrowser.Server.Implementations/Library/Resolvers/TV/SeasonResolver.cs +++ b/MediaBrowser.Server.Implementations/Library/Resolvers/TV/SeasonResolver.cs @@ -1,4 +1,5 @@ -using MediaBrowser.Controller.Entities.TV; +using MediaBrowser.Controller.Configuration; +using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.Library; using System; @@ -9,6 +10,20 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.TV /// public class SeasonResolver : FolderResolver { + /// + /// The _config + /// + private readonly IServerConfigurationManager _config; + + /// + /// Initializes a new instance of the class. + /// + /// The config. + public SeasonResolver(IServerConfigurationManager config) + { + _config = config; + } + /// /// Resolves the specified args. /// @@ -18,10 +33,17 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.TV { if (args.Parent is Series && args.IsDirectory) { - return new Season + var season = new Season { IndexNumber = TVUtils.GetSeasonNumberFromPath(args.Path) }; + + if (season.IndexNumber.HasValue && season.IndexNumber.Value == 0) + { + season.Name = _config.Configuration.SeasonZeroDisplayName; + } + + return season; } return null;