From db1bf5b1b55c8012e9ca3393fd59b9469ee5aeaf Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Sat, 19 Mar 2016 15:32:37 -0400 Subject: [PATCH] audio podcast --- .../Channels/ChannelAudioItem.cs | 102 ++++++++++++++ .../Channels/ChannelFolderItem.cs | 90 ++++++++++++ .../Channels/ChannelVideoItem.cs | 128 ++++++++++++++++++ .../Entities/Audio/AudioPodcast.cs | 12 ++ .../Entities/InternalItemsQuery.cs | 4 + .../Entities/SourceType.cs | 6 +- MediaBrowser.Controller/Entities/Trailer.cs | 19 +-- .../MediaBrowser.Controller.csproj | 4 + .../Providers/TrailerInfo.cs | 2 + MediaBrowser.Model/Dto/BaseItemDto.cs | 6 + MediaBrowser.Model/Entities/TrailerType.cs | 3 +- .../Movies/MovieMetadataService.cs | 5 + .../Channels/ChannelManager.cs | 40 +++++- .../Dto/DtoService.cs | 5 + .../Intros/DefaultIntroProvider.cs | 94 ++++--------- .../Library/LibraryManager.cs | 41 ++++-- .../Library/LocalTrailerPostScanTask.cs | 5 +- .../Library/Resolvers/VideoResolver.cs | 8 ++ .../Persistence/SqliteItemRepository.cs | 56 +++++++- 19 files changed, 523 insertions(+), 107 deletions(-) create mode 100644 MediaBrowser.Controller/Channels/ChannelAudioItem.cs create mode 100644 MediaBrowser.Controller/Channels/ChannelFolderItem.cs create mode 100644 MediaBrowser.Controller/Channels/ChannelVideoItem.cs create mode 100644 MediaBrowser.Controller/Entities/Audio/AudioPodcast.cs diff --git a/MediaBrowser.Controller/Channels/ChannelAudioItem.cs b/MediaBrowser.Controller/Channels/ChannelAudioItem.cs new file mode 100644 index 0000000000..bcb2dc2347 --- /dev/null +++ b/MediaBrowser.Controller/Channels/ChannelAudioItem.cs @@ -0,0 +1,102 @@ +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Entities.Audio; +using MediaBrowser.Model.Channels; +using MediaBrowser.Model.Configuration; +using MediaBrowser.Model.Dto; +using MediaBrowser.Model.Entities; +using MediaBrowser.Model.Users; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.Serialization; +using System.Threading; + +namespace MediaBrowser.Controller.Channels +{ + public class ChannelAudioItem : Audio + { + public ChannelMediaContentType ContentType { get; set; } + + public List ChannelMediaSources { get; set; } + + public override UnratedItem GetBlockUnratedType() + { + return UnratedItem.ChannelContent; + } + + protected override string CreateUserDataKey() + { + return ExternalId; + } + + [IgnoreDataMember] + public override bool SupportsLocalMetadata + { + get + { + return false; + } + } + + public override bool IsSaveLocalMetadataEnabled() + { + return false; + } + + public ChannelAudioItem() + { + ChannelMediaSources = new List(); + } + + [IgnoreDataMember] + public override LocationType LocationType + { + get + { + if (string.IsNullOrEmpty(Path)) + { + return LocationType.Remote; + } + + return base.LocationType; + } + } + + protected override string GetInternalMetadataPath(string basePath) + { + return System.IO.Path.Combine(basePath, "channels", ChannelId, Id.ToString("N")); + } + + public override IEnumerable GetMediaSources(bool enablePathSubstitution) + { + var sources = ChannelManager.GetStaticMediaSources(this, false, CancellationToken.None) + .Result.ToList(); + + if (sources.Count > 0) + { + return sources; + } + + var list = base.GetMediaSources(enablePathSubstitution).ToList(); + + foreach (var mediaSource in list) + { + if (string.IsNullOrWhiteSpace(mediaSource.Path)) + { + mediaSource.Type = MediaSourceType.Placeholder; + } + } + + return list; + } + + public override bool CanDelete() + { + return false; + } + + public override bool IsVisibleStandalone(User user) + { + return IsVisibleStandaloneInternal(user, false) && ChannelVideoItem.IsChannelVisible(this, user); + } + } +} diff --git a/MediaBrowser.Controller/Channels/ChannelFolderItem.cs b/MediaBrowser.Controller/Channels/ChannelFolderItem.cs new file mode 100644 index 0000000000..174cd282af --- /dev/null +++ b/MediaBrowser.Controller/Channels/ChannelFolderItem.cs @@ -0,0 +1,90 @@ +using MediaBrowser.Controller.Entities; +using MediaBrowser.Model.Channels; +using MediaBrowser.Model.Querying; +using MediaBrowser.Model.Users; +using System; +using System.Runtime.Serialization; +using System.Threading; +using System.Threading.Tasks; +using MediaBrowser.Model.Configuration; +using MediaBrowser.Model.Entities; + +namespace MediaBrowser.Controller.Channels +{ + public class ChannelFolderItem : Folder + { + public ChannelFolderType ChannelFolderType { get; set; } + + protected override bool GetBlockUnratedValue(UserPolicy config) + { + // Don't block. + return false; + } + + public override UnratedItem GetBlockUnratedType() + { + return UnratedItem.ChannelContent; + } + + [IgnoreDataMember] + public override bool SupportsLocalMetadata + { + get + { + return false; + } + } + + public override bool IsSaveLocalMetadataEnabled() + { + return false; + } + + protected override string CreateUserDataKey() + { + return ExternalId; + } + + public override async Task> GetItems(InternalItemsQuery query) + { + try + { + // Don't blow up here because it could cause parent screens with other content to fail + return await ChannelManager.GetChannelItemsInternal(new ChannelItemQuery + { + ChannelId = ChannelId, + FolderId = Id.ToString("N"), + Limit = query.Limit, + StartIndex = query.StartIndex, + UserId = query.User.Id.ToString("N"), + SortBy = query.SortBy, + SortOrder = query.SortOrder + + }, new Progress(), CancellationToken.None); + } + catch + { + // Already logged at lower levels + return new QueryResult + { + + }; + } + } + + protected override string GetInternalMetadataPath(string basePath) + { + return System.IO.Path.Combine(basePath, "channels", ChannelId, Id.ToString("N")); + } + + public override bool CanDelete() + { + return false; + } + + public override bool IsVisibleStandalone(User user) + { + return IsVisibleStandaloneInternal(user, false) && ChannelVideoItem.IsChannelVisible(this, user); + } + } +} diff --git a/MediaBrowser.Controller/Channels/ChannelVideoItem.cs b/MediaBrowser.Controller/Channels/ChannelVideoItem.cs new file mode 100644 index 0000000000..e12a84ba27 --- /dev/null +++ b/MediaBrowser.Controller/Channels/ChannelVideoItem.cs @@ -0,0 +1,128 @@ +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Providers; +using MediaBrowser.Model.Channels; +using MediaBrowser.Model.Configuration; +using MediaBrowser.Model.Dto; +using MediaBrowser.Model.Entities; +using MediaBrowser.Model.Users; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Runtime.Serialization; +using System.Threading; + +namespace MediaBrowser.Controller.Channels +{ + public class ChannelVideoItem : Video + { + public ChannelMediaContentType ContentType { get; set; } + + public List ChannelMediaSources { get; set; } + + protected override string CreateUserDataKey() + { + if (ContentType == ChannelMediaContentType.MovieExtra) + { + var key = this.GetProviderId(MetadataProviders.Imdb) ?? this.GetProviderId(MetadataProviders.Tmdb); + + if (!string.IsNullOrWhiteSpace(key)) + { + key = key + "-" + ExtraType.ToString().ToLower(); + + // Make sure different trailers have their own data. + if (RunTimeTicks.HasValue) + { + key += "-" + RunTimeTicks.Value.ToString(CultureInfo.InvariantCulture); + } + + return key; + } + } + + return ExternalId; + } + + public override UnratedItem GetBlockUnratedType() + { + return UnratedItem.ChannelContent; + } + + [IgnoreDataMember] + public override bool SupportsLocalMetadata + { + get + { + return false; + } + } + + public override bool IsSaveLocalMetadataEnabled() + { + return false; + } + + public ChannelVideoItem() + { + ChannelMediaSources = new List(); + } + + [IgnoreDataMember] + public override LocationType LocationType + { + get + { + if (string.IsNullOrEmpty(Path)) + { + return LocationType.Remote; + } + + return base.LocationType; + } + } + + public override IEnumerable GetMediaSources(bool enablePathSubstitution) + { + var sources = ChannelManager.GetStaticMediaSources(this, false, CancellationToken.None) + .Result.ToList(); + + if (sources.Count > 0) + { + return sources; + } + + var list = base.GetMediaSources(enablePathSubstitution).ToList(); + + foreach (var mediaSource in list) + { + if (string.IsNullOrWhiteSpace(mediaSource.Path)) + { + mediaSource.Type = MediaSourceType.Placeholder; + } + } + + return list; + } + + protected override string GetInternalMetadataPath(string basePath) + { + return System.IO.Path.Combine(basePath, "channels", ChannelId, Id.ToString("N")); + } + + public override bool CanDelete() + { + return false; + } + + public override bool IsVisibleStandalone(User user) + { + return IsVisibleStandaloneInternal(user, false) && IsChannelVisible(this, user); + } + + internal static bool IsChannelVisible(BaseItem item, User user) + { + var channel = ChannelManager.GetChannel(item.ChannelId); + + return channel.IsVisible(user); + } + } +} diff --git a/MediaBrowser.Controller/Entities/Audio/AudioPodcast.cs b/MediaBrowser.Controller/Entities/Audio/AudioPodcast.cs new file mode 100644 index 0000000000..983cc0100f --- /dev/null +++ b/MediaBrowser.Controller/Entities/Audio/AudioPodcast.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace MediaBrowser.Controller.Entities.Audio +{ + public class AudioPodcast : Audio + { + } +} diff --git a/MediaBrowser.Controller/Entities/InternalItemsQuery.cs b/MediaBrowser.Controller/Entities/InternalItemsQuery.cs index cedc9591d5..7b3e51cadd 100644 --- a/MediaBrowser.Controller/Entities/InternalItemsQuery.cs +++ b/MediaBrowser.Controller/Entities/InternalItemsQuery.cs @@ -117,6 +117,8 @@ namespace MediaBrowser.Controller.Entities public string[] PresetViews { get; set; } public SourceType[] SourceTypes { get; set; } public SourceType[] ExcludeSourceTypes { get; set; } + public TrailerType[] TrailerTypes { get; set; } + public TrailerType[] ExcludeTrailerTypes { get; set; } public InternalItemsQuery() { @@ -145,6 +147,8 @@ namespace MediaBrowser.Controller.Entities PresetViews = new string[] { }; SourceTypes = new SourceType[] { }; ExcludeSourceTypes = new SourceType[] { }; + TrailerTypes = new TrailerType[] { }; + ExcludeTrailerTypes = new TrailerType[] { }; } public InternalItemsQuery(User user) diff --git a/MediaBrowser.Controller/Entities/SourceType.cs b/MediaBrowser.Controller/Entities/SourceType.cs index 9c307b4e6e..92976344c5 100644 --- a/MediaBrowser.Controller/Entities/SourceType.cs +++ b/MediaBrowser.Controller/Entities/SourceType.cs @@ -3,8 +3,8 @@ namespace MediaBrowser.Controller.Entities { public enum SourceType { - Library = 0, - Channel = 1, - LiveTV = 2 + Library = 1, + Channel = 2, + LiveTV = 3 } } diff --git a/MediaBrowser.Controller/Entities/Trailer.cs b/MediaBrowser.Controller/Entities/Trailer.cs index cefc1dabe9..a4ac345453 100644 --- a/MediaBrowser.Controller/Entities/Trailer.cs +++ b/MediaBrowser.Controller/Entities/Trailer.cs @@ -24,8 +24,11 @@ namespace MediaBrowser.Controller.Entities Taglines = new List(); Keywords = new List(); ProductionLocations = new List(); + TrailerTypes = new List(); } + public List TrailerTypes { get; set; } + public float? Metascore { get; set; } public List RemoteTrailers { get; set; } @@ -62,20 +65,6 @@ namespace MediaBrowser.Controller.Entities /// The critic rating summary. public string CriticRatingSummary { get; set; } - /// - /// Gets a value indicating whether this instance is local trailer. - /// - /// true if this instance is local trailer; otherwise, false. - [IgnoreDataMember] - public bool IsLocalTrailer - { - get - { - // Local trailers are not part of children - return GetParent() == null; - } - } - protected override string CreateUserDataKey() { var key = Movie.GetMovieUserDataKey(this); @@ -105,7 +94,7 @@ namespace MediaBrowser.Controller.Entities { var info = GetItemLookupInfo(); - info.IsLocalTrailer = IsLocalTrailer; + info.IsLocalTrailer = TrailerTypes.Contains(TrailerType.LocalTrailer); if (!IsInMixedFolder) { diff --git a/MediaBrowser.Controller/MediaBrowser.Controller.csproj b/MediaBrowser.Controller/MediaBrowser.Controller.csproj index 572f45b361..be041281ff 100644 --- a/MediaBrowser.Controller/MediaBrowser.Controller.csproj +++ b/MediaBrowser.Controller/MediaBrowser.Controller.csproj @@ -75,12 +75,15 @@ + + + @@ -123,6 +126,7 @@ + diff --git a/MediaBrowser.Controller/Providers/TrailerInfo.cs b/MediaBrowser.Controller/Providers/TrailerInfo.cs index fe26ec43ec..65ddc2d1e6 100644 --- a/MediaBrowser.Controller/Providers/TrailerInfo.cs +++ b/MediaBrowser.Controller/Providers/TrailerInfo.cs @@ -1,3 +1,5 @@ +using MediaBrowser.Model.Entities; + namespace MediaBrowser.Controller.Providers { public class TrailerInfo : ItemLookupInfo diff --git a/MediaBrowser.Model/Dto/BaseItemDto.cs b/MediaBrowser.Model/Dto/BaseItemDto.cs index 8e3284152b..d9b06dcfd3 100644 --- a/MediaBrowser.Model/Dto/BaseItemDto.cs +++ b/MediaBrowser.Model/Dto/BaseItemDto.cs @@ -43,6 +43,12 @@ namespace MediaBrowser.Model.Dto /// /// The etag. public string Etag { get; set; } + + /// + /// Gets or sets the type of the source. + /// + /// The type of the source. + public string SourceType { get; set; } /// /// Gets or sets the playlist item identifier. diff --git a/MediaBrowser.Model/Entities/TrailerType.cs b/MediaBrowser.Model/Entities/TrailerType.cs index c96a05bcd6..085f461cfb 100644 --- a/MediaBrowser.Model/Entities/TrailerType.cs +++ b/MediaBrowser.Model/Entities/TrailerType.cs @@ -5,6 +5,7 @@ namespace MediaBrowser.Model.Entities ComingSoonToTheaters = 1, ComingSoonToDvd = 2, ComingSoonToStreaming = 3, - Archive = 4 + Archive = 4, + LocalTrailer = 5 } } \ No newline at end of file diff --git a/MediaBrowser.Providers/Movies/MovieMetadataService.cs b/MediaBrowser.Providers/Movies/MovieMetadataService.cs index 1e55dce760..e70ec00576 100644 --- a/MediaBrowser.Providers/Movies/MovieMetadataService.cs +++ b/MediaBrowser.Providers/Movies/MovieMetadataService.cs @@ -67,6 +67,11 @@ namespace MediaBrowser.Providers.Movies protected override void MergeData(MetadataResult source, MetadataResult target, List lockedFields, bool replaceData, bool mergeMetadataSettings) { ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings); + + if (replaceData || target.Item.TrailerTypes.Count == 0) + { + target.Item.TrailerTypes = source.Item.TrailerTypes; + } } } diff --git a/MediaBrowser.Server.Implementations/Channels/ChannelManager.cs b/MediaBrowser.Server.Implementations/Channels/ChannelManager.cs index ee49a7005c..e957b9889a 100644 --- a/MediaBrowser.Server.Implementations/Channels/ChannelManager.cs +++ b/MediaBrowser.Server.Implementations/Channels/ChannelManager.cs @@ -424,6 +424,7 @@ namespace MediaBrowser.Server.Implementations.Channels var parentFolderId = parentFolder.Id; var id = GetInternalChannelId(channelInfo.Name); + var idString = id.ToString("N"); var path = Channel.GetInternalMetadataPath(_config.ApplicationPaths.InternalMetadataPath, id); @@ -431,7 +432,6 @@ namespace MediaBrowser.Server.Implementations.Channels var forceUpdate = false; var item = _libraryManager.GetItemById(id) as Channel; - var channelId = channelInfo.Name.GetMD5().ToString("N"); if (item == null) { @@ -452,11 +452,11 @@ namespace MediaBrowser.Server.Implementations.Channels } item.Path = path; - if (!string.Equals(item.ChannelId, channelId, StringComparison.OrdinalIgnoreCase)) + if (!string.Equals(item.ChannelId, idString, StringComparison.OrdinalIgnoreCase)) { forceUpdate = true; } - item.ChannelId = channelId; + item.ChannelId = idString; if (item.ParentId != parentFolderId) { @@ -505,7 +505,7 @@ namespace MediaBrowser.Server.Implementations.Channels public Channel GetChannel(string id) { - return _libraryManager.GetItemById(new Guid(id)) as Channel; + return _libraryManager.GetItemById(id) as Channel; } public IEnumerable GetAllChannelFeatures() @@ -523,6 +523,11 @@ namespace MediaBrowser.Server.Implementations.Channels public ChannelFeatures GetChannelFeatures(string id) { + if (string.IsNullOrWhiteSpace(id)) + { + throw new ArgumentNullException("id"); + } + var channel = GetChannel(id); var channelProvider = GetChannelProvider(channel); @@ -1261,7 +1266,14 @@ namespace MediaBrowser.Server.Implementations.Channels } else if (info.MediaType == ChannelMediaType.Audio) { - item = GetItemById /// The args. + /// The resolvers. /// BaseItem. - private BaseItem ResolveItem(ItemResolveArgs args) + private BaseItem ResolveItem(ItemResolveArgs args, IItemResolver[] resolvers) { - var item = EntityResolvers.Select(r => Resolve(args, r)) + var item = (resolvers ?? EntityResolvers).Select(r => Resolve(args, r)) .FirstOrDefault(i => i != null); if (item != null) @@ -556,10 +559,10 @@ namespace MediaBrowser.Server.Implementations.Library public BaseItem ResolvePath(FileSystemMetadata fileInfo, Folder parent = null) { - return ResolvePath(fileInfo, new DirectoryService(_logger, _fileSystem), parent); + return ResolvePath(fileInfo, new DirectoryService(_logger, _fileSystem), null, parent); } - private BaseItem ResolvePath(FileSystemMetadata fileInfo, IDirectoryService directoryService, Folder parent = null, string collectionType = null) + private BaseItem ResolvePath(FileSystemMetadata fileInfo, IDirectoryService directoryService, IItemResolver[] resolvers, Folder parent = null, string collectionType = null) { if (fileInfo == null) { @@ -615,7 +618,7 @@ namespace MediaBrowser.Server.Implementations.Library return null; } - return ResolveItem(args); + return ResolveItem(args, resolvers); } public bool IgnoreFile(FileSystemMetadata file, BaseItem parent) @@ -657,12 +660,19 @@ namespace MediaBrowser.Server.Implementations.Library } public IEnumerable ResolvePaths(IEnumerable files, IDirectoryService directoryService, Folder parent, string collectionType) + { + return ResolvePaths(files, directoryService, parent, collectionType, EntityResolvers); + } + + public IEnumerable ResolvePaths(IEnumerable files, IDirectoryService directoryService, Folder parent, string collectionType, IItemResolver[] resolvers) { var fileList = files.Where(i => !IgnoreFile(i, parent)).ToList(); if (parent != null) { - foreach (var resolver in MultiItemResolvers) + var multiItemResolvers = resolvers == null ? MultiItemResolvers : resolvers.OfType().ToArray(); + + foreach (var resolver in multiItemResolvers) { var result = resolver.ResolveMultiple(parent, fileList, collectionType, directoryService); @@ -675,22 +685,22 @@ namespace MediaBrowser.Server.Implementations.Library { ResolverHelper.SetInitialItemValues(item, parent, _fileSystem, this, directoryService); } - items.AddRange(ResolveFileList(result.ExtraFiles, directoryService, parent, collectionType)); + items.AddRange(ResolveFileList(result.ExtraFiles, directoryService, parent, collectionType, resolvers)); return items; } } } - return ResolveFileList(fileList, directoryService, parent, collectionType); + return ResolveFileList(fileList, directoryService, parent, collectionType, resolvers); } - private IEnumerable ResolveFileList(IEnumerable fileList, IDirectoryService directoryService, Folder parent, string collectionType) + private IEnumerable ResolveFileList(IEnumerable fileList, IDirectoryService directoryService, Folder parent, string collectionType, IItemResolver[] resolvers) { return fileList.Select(f => { try { - return ResolvePath(f, directoryService, parent, collectionType); + return ResolvePath(f, directoryService, resolvers, parent, collectionType); } catch (Exception ex) { @@ -2306,12 +2316,17 @@ namespace MediaBrowser.Server.Implementations.Library files.AddRange(currentVideo.Extras.Where(i => string.Equals(i.ExtraType, "trailer", StringComparison.OrdinalIgnoreCase)).Select(i => _fileSystem.GetFileInfo(i.Path))); } - return ResolvePaths(files, directoryService, null, null) - .OfType