diff --git a/MediaBrowser.Controller/Entities/UserViewBuilder.cs b/MediaBrowser.Controller/Entities/UserViewBuilder.cs index b2d3592776..0733b65b15 100644 --- a/MediaBrowser.Controller/Entities/UserViewBuilder.cs +++ b/MediaBrowser.Controller/Entities/UserViewBuilder.cs @@ -66,7 +66,7 @@ namespace MediaBrowser.Controller.Entities { var result = await _channelManager.GetChannelsInternal(new ChannelQuery { - UserId = user.Id.ToString("N"), + UserId = user == null ? null : user.Id.ToString("N"), Limit = query.Limit, StartIndex = query.StartIndex diff --git a/MediaBrowser.Providers/Folders/UserViewMetadataService.cs b/MediaBrowser.Providers/Folders/UserViewMetadataService.cs index 1dc09e01d3..70b86830fd 100644 --- a/MediaBrowser.Providers/Folders/UserViewMetadataService.cs +++ b/MediaBrowser.Providers/Folders/UserViewMetadataService.cs @@ -21,4 +21,17 @@ namespace MediaBrowser.Providers.Folders ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings); } } + + public class CollectionFolderMetadataService : MetadataService + { + public CollectionFolderMetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, IProviderRepository providerRepo, IFileSystem fileSystem, IUserDataManager userDataManager, ILibraryManager libraryManager) + : base(serverConfigurationManager, logger, providerManager, providerRepo, fileSystem, userDataManager, libraryManager) + { + } + + protected override void MergeData(MetadataResult source, MetadataResult target, List lockedFields, bool replaceData, bool mergeMetadataSettings) + { + ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings); + } + } } diff --git a/MediaBrowser.Server.Implementations/Dto/DtoService.cs b/MediaBrowser.Server.Implementations/Dto/DtoService.cs index 257e0feb1a..aade00aa4f 100644 --- a/MediaBrowser.Server.Implementations/Dto/DtoService.cs +++ b/MediaBrowser.Server.Implementations/Dto/DtoService.cs @@ -187,7 +187,7 @@ namespace MediaBrowser.Server.Implementations.Dto { if (!options.Fields.Contains(ItemFields.SyncInfo)) { - return new SyncedItemProgress[]{}; + return new SyncedItemProgress[] { }; } var deviceId = options.DeviceId; @@ -281,7 +281,7 @@ namespace MediaBrowser.Server.Implementations.Dto } } - private BaseItemDto GetBaseItemDtoInternal(BaseItem item, DtoOptions options, Dictionary syncProgress, User user = null, BaseItem owner = null) + private BaseItemDto GetBaseItemDtoInternal(BaseItem item, DtoOptions options, Dictionary syncProgress, User user = null, BaseItem owner = null) { var fields = options.Fields; @@ -1629,7 +1629,7 @@ namespace MediaBrowser.Server.Implementations.Dto /// The fields. /// The synchronize progress. /// Task. - private void SetSpecialCounts(Folder folder, User user, BaseItemDto dto, List fields, Dictionary syncProgress) + private void SetSpecialCounts(Folder folder, User user, BaseItemDto dto, List fields, Dictionary syncProgress) { var recursiveItemCount = 0; var unplayed = 0; @@ -1640,21 +1640,14 @@ namespace MediaBrowser.Server.Implementations.Dto double totalSyncPercent = 0; var addSyncInfo = fields.Contains(ItemFields.SyncInfo); - IEnumerable children; - - var season = folder as Season; - - if (season != null) + var children = folder.GetItems(new InternalItemsQuery { - children = season - .GetEpisodes(user) - .Where(i => i.LocationType != LocationType.Virtual); - } - else - { - children = folder - .GetRecursiveChildren(user, i => !i.IsFolder && i.LocationType != LocationType.Virtual); - } + IsFolder = false, + Recursive = true, + IsVirtualUnaired = false, + IsMissing = false + + }).Result.Items; // Loop through each recursive child foreach (var child in children) diff --git a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs index bdc94b88b9..8d51e3e92a 100644 --- a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs +++ b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs @@ -1615,7 +1615,7 @@ namespace MediaBrowser.Server.Implementations.Library .FirstOrDefault(i => !string.IsNullOrWhiteSpace(i)); } - private readonly TimeSpan _viewRefreshInterval = TimeSpan.FromHours(24); + private readonly TimeSpan _viewRefreshInterval = TimeSpan.FromHours(.01); public async Task GetNamedView(User user, string name, @@ -1666,7 +1666,7 @@ namespace MediaBrowser.Server.Implementations.Library await item.UpdateToRepository(ItemUpdateType.MetadataEdit, cancellationToken).ConfigureAwait(false); } - if (!refresh && item != null) + if (!refresh) { refresh = (DateTime.UtcNow - item.DateLastSaved) >= _viewRefreshInterval; } diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/javascript.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/javascript.json index 55236c2c6e..acd54cb0fa 100644 --- a/MediaBrowser.Server.Implementations/Localization/JavaScript/javascript.json +++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/javascript.json @@ -825,5 +825,10 @@ "ErrorSavingTvProvider": "There was an error saving the TV provider. Please ensure it is accessible and try again.", "ErrorGettingTvLineups": "There was an error downloading tv lineups. Please ensure your username and password are correct and try again.", "MessageCreateAccountAt": "Create an account at {0}", - "ErrorPleaseSelectLineup": "Please select a lineup and try again. If no lineups are available, then please check that your username, password, and postal code is correct." + "ErrorPleaseSelectLineup": "Please select a lineup and try again. If no lineups are available, then please check that your username, password, and postal code is correct.", + "HeaderTryCinemaMode": "Try Cinema Mode", + "ButtonBecomeSupporter": "Become an Emby Supporter", + "ButtonClosePlayVideo": "Close and play my video", + "MessageDidYouKnowCinemaMode": "Did you know that by becoming an Emby Supporter, you can enhance your experience with features like Cinema Mode?", + "MessageDidYouKnowCinemaMode2": "Cinema Mode gives you the true cinema experience with trailers and custom intros before the main feature." } diff --git a/MediaBrowser.Server.Implementations/Localization/Server/server.json b/MediaBrowser.Server.Implementations/Localization/Server/server.json index e06bcea34f..1b1b3e0e2f 100644 --- a/MediaBrowser.Server.Implementations/Localization/Server/server.json +++ b/MediaBrowser.Server.Implementations/Localization/Server/server.json @@ -1486,8 +1486,8 @@ "HeaderGuideProviders": "Guide Providers", "AddGuideProviderHelp": "Add a source for TV Guide information", "LabelZipCode": "Zip Code:", - "GuideProviderListingsStep": "Step 2: Select Listings", - "GuideProviderLoginStep": "Step 1: Login", + "GuideProviderSelectListings": "Select Listings", + "GuideProviderLogin": "Login", "LabelLineup": "Lineup:", "MessageTunerDeviceNotListed": "Is your tuner device not listed? Try installing an external service provider for more Live TV options.", "LabelImportOnlyFavoriteChannels": "Restrict to channels marked as favorite", diff --git a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj index 0d8b748737..03becc81d0 100644 --- a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj +++ b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj @@ -242,6 +242,7 @@ + diff --git a/MediaBrowser.Server.Implementations/Photos/BaseDynamicImageProvider.cs b/MediaBrowser.Server.Implementations/Photos/BaseDynamicImageProvider.cs index ef12544bac..eb25c7d796 100644 --- a/MediaBrowser.Server.Implementations/Photos/BaseDynamicImageProvider.cs +++ b/MediaBrowser.Server.Implementations/Photos/BaseDynamicImageProvider.cs @@ -53,10 +53,23 @@ namespace MediaBrowser.Server.Implementations.Photos return ItemUpdateType.None; } - var primaryResult = await FetchAsync(item, ImageType.Primary, options, cancellationToken).ConfigureAwait(false); - var thumbResult = await FetchAsync(item, ImageType.Thumb, options, cancellationToken).ConfigureAwait(false); + var updateType = ItemUpdateType.None; + var supportedImages = GetSupportedImages(item).ToList(); - return primaryResult | thumbResult; + if (supportedImages.Contains(ImageType.Primary)) + { + var primaryResult = await FetchAsync(item, ImageType.Primary, options, cancellationToken).ConfigureAwait(false); + updateType = updateType | primaryResult; + } + + if (supportedImages.Contains(ImageType.Thumb)) + { + var thumbResult = await FetchAsync(item, ImageType.Thumb, options, cancellationToken).ConfigureAwait(false); + updateType = updateType | thumbResult; + } + + + return updateType; } protected async Task FetchAsync(IHasImages item, ImageType imageType, MetadataRefreshOptions options, CancellationToken cancellationToken) @@ -168,7 +181,7 @@ namespace MediaBrowser.Server.Implementations.Photos return false; } - var drawText = !(item is UserView); + var drawText = !(item is UserView) && !(item is ICollectionFolder); if (imageType == ImageType.Thumb) { @@ -181,14 +194,11 @@ namespace MediaBrowser.Server.Implementations.Photos { return await CreateSquareCollage(item, itemsWithImages, outputPath, drawText).ConfigureAwait(false); } - else if (item is PhotoAlbum || item is Playlist) + if (item is PhotoAlbum || item is Playlist) { return await CreateSquareCollage(item, itemsWithImages, outputPath, drawText).ConfigureAwait(false); } - else - { - return await CreatePosterCollage(item, itemsWithImages, outputPath).ConfigureAwait(false); - } + return await CreatePosterCollage(item, itemsWithImages, outputPath).ConfigureAwait(false); } throw new ArgumentException("Unexpected image type"); @@ -203,15 +213,35 @@ namespace MediaBrowser.Server.Implementations.Photos return false; } - if (item is UserView) + var supportedImages = GetSupportedImages(item).ToList(); + + if (item is UserView || item is ICollectionFolder) { - return HasChanged(item, ImageType.Primary); + if (supportedImages.Contains(ImageType.Primary) && HasChanged(item, ImageType.Primary)) + { + return true; + } + if (supportedImages.Contains(ImageType.Thumb) && HasChanged(item, ImageType.Thumb)) + { + return true; + } + + return false; } var items = GetItemsWithImages(item).Result; var cacheKey = GetConfigurationCacheKey(items, item.Name); - return HasChanged(item, ImageType.Primary, cacheKey) || HasChanged(item, ImageType.Thumb, cacheKey); + if (supportedImages.Contains(ImageType.Primary) && HasChanged(item, ImageType.Primary, cacheKey)) + { + return true; + } + if (supportedImages.Contains(ImageType.Thumb) && HasChanged(item, ImageType.Thumb, cacheKey)) + { + return true; + } + + return false; } protected bool HasChanged(IHasImages item, ImageType type, string cacheKey) diff --git a/MediaBrowser.Server.Implementations/UserViews/CollectionFolderImageProvider.cs b/MediaBrowser.Server.Implementations/UserViews/CollectionFolderImageProvider.cs new file mode 100644 index 0000000000..39dbcf226b --- /dev/null +++ b/MediaBrowser.Server.Implementations/UserViews/CollectionFolderImageProvider.cs @@ -0,0 +1,114 @@ +using MediaBrowser.Common.Configuration; +using MediaBrowser.Common.IO; +using MediaBrowser.Controller.Drawing; +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Entities.Audio; +using MediaBrowser.Controller.Entities.TV; +using MediaBrowser.Controller.Providers; +using MediaBrowser.Model.Entities; +using MediaBrowser.Server.Implementations.Photos; +using MoreLinq; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace MediaBrowser.Server.Implementations.UserViews +{ + public class CollectionFolderImageProvider : BaseDynamicImageProvider + { + public CollectionFolderImageProvider(IFileSystem fileSystem, IProviderManager providerManager, IApplicationPaths applicationPaths, IImageProcessor imageProcessor) : base(fileSystem, providerManager, applicationPaths, imageProcessor) + { + } + + public override IEnumerable GetSupportedImages(IHasImages item) + { + return new List + { + ImageType.Primary + }; + } + + protected override async Task> GetItemsWithImages(IHasImages item) + { + var view = (CollectionFolder)item; + + var recursive = !new[] { CollectionType.Playlists, CollectionType.Channels }.Contains(view.CollectionType ?? string.Empty, StringComparer.OrdinalIgnoreCase); + + var result = await view.GetItems(new InternalItemsQuery + { + CollapseBoxSetItems = false, + Recursive = recursive, + ExcludeItemTypes = new[] { "UserView", "CollectionFolder", "Playlist" } + + }).ConfigureAwait(false); + + var items = result.Items.Select(i => + { + var episode = i as Episode; + if (episode != null) + { + var series = episode.Series; + if (series != null) + { + return series; + } + var episodeSeason = episode.Season; + if (episodeSeason != null) + { + return episodeSeason; + } + + return episode; + } + + var season = i as Season; + if (season != null) + { + var series = season.Series; + if (series != null) + { + return series; + } + + return season; + } + + var audio = i as Audio; + if (audio != null) + { + var album = audio.AlbumEntity; + if (album != null && album.HasImage(ImageType.Primary)) + { + return album; + } + } + + return i; + + }).DistinctBy(i => i.Id); + + return GetFinalItems(items.Where(i => i.HasImage(ImageType.Primary) || i.HasImage(ImageType.Thumb)).ToList(), 8); + } + + public override bool Supports(IHasImages item) + { + return item is CollectionFolder; + } + + protected override async Task CreateImage(IHasImages item, List itemsWithImages, string outputPath, ImageType imageType, int imageIndex) + { + if (imageType == ImageType.Primary) + { + if (itemsWithImages.Count == 0) + { + return false; + } + + return await CreateThumbCollage(item, itemsWithImages, outputPath, 960, 540, false, item.Name).ConfigureAwait(false); + } + + return await base.CreateImage(item, itemsWithImages, outputPath, imageType, imageIndex).ConfigureAwait(false); + } + } +} diff --git a/MediaBrowser.Server.Implementations/UserViews/DynamicImageProvider.cs b/MediaBrowser.Server.Implementations/UserViews/DynamicImageProvider.cs index 918d07f973..3d77f831ed 100644 --- a/MediaBrowser.Server.Implementations/UserViews/DynamicImageProvider.cs +++ b/MediaBrowser.Server.Implementations/UserViews/DynamicImageProvider.cs @@ -49,11 +49,6 @@ namespace MediaBrowser.Server.Implementations.UserViews { var view = (UserView)item; - if (!view.UserId.HasValue) - { - return new List(); - } - if (string.Equals(view.ViewType, CollectionType.LiveTv, StringComparison.OrdinalIgnoreCase)) { return new List(); @@ -66,7 +61,7 @@ namespace MediaBrowser.Server.Implementations.UserViews { var userItemsResult = await view.GetItems(new InternalItemsQuery { - User = _userManager.GetUserById(view.UserId.Value), + User = view.UserId.HasValue ? _userManager.GetUserById(view.UserId.Value) : null, CollapseBoxSetItems = false }); @@ -78,7 +73,7 @@ namespace MediaBrowser.Server.Implementations.UserViews var result = await view.GetItems(new InternalItemsQuery { - User = _userManager.GetUserById(view.UserId.Value), + User = view.UserId.HasValue ? _userManager.GetUserById(view.UserId.Value) : null, CollapseBoxSetItems = false, Recursive = recursive, ExcludeItemTypes = new[] { "UserView", "CollectionFolder", "Playlist" } @@ -141,8 +136,7 @@ namespace MediaBrowser.Server.Implementations.UserViews public override bool Supports(IHasImages item) { var view = item as UserView; - - if (view != null && view.UserId.HasValue) + if (view != null) { var supported = new[] { @@ -182,10 +176,10 @@ namespace MediaBrowser.Server.Implementations.UserViews SpecialFolder.MusicFavoriteArtists, SpecialFolder.MusicFavoriteAlbums, SpecialFolder.MusicFavoriteSongs + }; - return (IsUsingCollectionStrip(view) || supported.Contains(view.ViewType, StringComparer.OrdinalIgnoreCase)) && - _userManager.GetUserById(view.UserId.Value) != null; + return (IsUsingCollectionStrip(view) || supported.Contains(view.ViewType, StringComparer.OrdinalIgnoreCase)); } return false;