Luke Pulverenti 9 лет назад
Родитель
Сommit
db1bf5b1b5

+ 102 - 0
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<ChannelMediaInfo> 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<ChannelMediaInfo>();
+        }
+
+        [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<MediaSourceInfo> 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);
+        }
+    }
+}

+ 90 - 0
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<QueryResult<BaseItem>> 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<double>(), CancellationToken.None);
+            }
+            catch
+            {
+                // Already logged at lower levels
+                return new QueryResult<BaseItem>
+                {
+
+                };
+            }
+        }
+
+        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);
+        }
+    }
+}

+ 128 - 0
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<ChannelMediaInfo> 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<ChannelMediaInfo>();
+        }
+
+        [IgnoreDataMember]
+        public override LocationType LocationType
+        {
+            get
+            {
+                if (string.IsNullOrEmpty(Path))
+                {
+                    return LocationType.Remote;
+                }
+
+                return base.LocationType;
+            }
+        }
+
+        public override IEnumerable<MediaSourceInfo> 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);
+        }
+    }
+}

+ 12 - 0
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
+    {
+    }
+}

+ 4 - 0
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)

+ 3 - 3
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
     }
 }

+ 4 - 15
MediaBrowser.Controller/Entities/Trailer.cs

@@ -24,8 +24,11 @@ namespace MediaBrowser.Controller.Entities
             Taglines = new List<string>();
             Keywords = new List<string>();
             ProductionLocations = new List<string>();
+            TrailerTypes = new List<TrailerType>();
         }
 
+        public List<TrailerType> TrailerTypes { get; set; }
+        
         public float? Metascore { get; set; }
 
         public List<MediaUrl> RemoteTrailers { get; set; }
@@ -62,20 +65,6 @@ namespace MediaBrowser.Controller.Entities
         /// <value>The critic rating summary.</value>
         public string CriticRatingSummary { get; set; }
 
-        /// <summary>
-        /// Gets a value indicating whether this instance is local trailer.
-        /// </summary>
-        /// <value><c>true</c> if this instance is local trailer; otherwise, <c>false</c>.</value>
-        [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<TrailerInfo>();
 
-            info.IsLocalTrailer = IsLocalTrailer;
+            info.IsLocalTrailer = TrailerTypes.Contains(TrailerType.LocalTrailer);
             
             if (!IsInMixedFolder)
             {

+ 4 - 0
MediaBrowser.Controller/MediaBrowser.Controller.csproj

@@ -75,12 +75,15 @@
     </Compile>
     <Compile Include="Activity\IActivityManager.cs" />
     <Compile Include="Activity\IActivityRepository.cs" />
+    <Compile Include="Channels\ChannelAudioItem.cs" />
+    <Compile Include="Channels\ChannelFolderItem.cs" />
     <Compile Include="Channels\ChannelItemInfo.cs" />
     <Compile Include="Channels\ChannelItemResult.cs" />
     <Compile Include="Channels\ChannelItemType.cs" />
     <Compile Include="Channels\ChannelMediaInfo.cs" />
     <Compile Include="Channels\ChannelParentalRating.cs" />
     <Compile Include="Channels\ChannelSearchInfo.cs" />
+    <Compile Include="Channels\ChannelVideoItem.cs" />
     <Compile Include="Channels\IChannel.cs" />
     <Compile Include="Channels\IChannelManager.cs" />
     <Compile Include="Channels\Channel.cs" />
@@ -123,6 +126,7 @@
     <Compile Include="Drawing\ImageStream.cs" />
     <Compile Include="Dto\DtoOptions.cs" />
     <Compile Include="Dto\IDtoService.cs" />
+    <Compile Include="Entities\Audio\AudioPodcast.cs" />
     <Compile Include="Entities\Audio\IHasAlbumArtist.cs" />
     <Compile Include="Entities\Audio\IHasMusicGenres.cs" />
     <Compile Include="Entities\Book.cs" />

+ 2 - 0
MediaBrowser.Controller/Providers/TrailerInfo.cs

@@ -1,3 +1,5 @@
+using MediaBrowser.Model.Entities;
+
 namespace MediaBrowser.Controller.Providers
 {
     public class TrailerInfo : ItemLookupInfo

+ 6 - 0
MediaBrowser.Model/Dto/BaseItemDto.cs

@@ -43,6 +43,12 @@ namespace MediaBrowser.Model.Dto
         /// </summary>
         /// <value>The etag.</value>
         public string Etag { get; set; }
+
+        /// <summary>
+        /// Gets or sets the type of the source.
+        /// </summary>
+        /// <value>The type of the source.</value>
+        public string SourceType { get; set; }
         
         /// <summary>
         /// Gets or sets the playlist item identifier.

+ 2 - 1
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
     }
 }

+ 5 - 0
MediaBrowser.Providers/Movies/MovieMetadataService.cs

@@ -67,6 +67,11 @@ namespace MediaBrowser.Providers.Movies
         protected override void MergeData(MetadataResult<Trailer> source, MetadataResult<Trailer> target, List<MetadataFields> 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;
+            }
         }
     }
 

+ 33 - 7
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<ChannelFeatures> 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<Audio>(info.Id, channelProvider.Name, channelProvider.DataVersion, out isNew);
+                if (info.ContentType == ChannelMediaContentType.Podcast)
+                {
+                    item = GetItemById<AudioPodcast>(info.Id, channelProvider.Name, channelProvider.DataVersion, out isNew);
+                }
+                else
+                {
+                    item = GetItemById<Audio>(info.Id, channelProvider.Name, channelProvider.DataVersion, out isNew);
+                }
             }
             else
             {
@@ -1302,6 +1314,16 @@ namespace MediaBrowser.Server.Implementations.Channels
                 item.Tags = info.Tags;
             }
 
+            var trailer = item as Trailer;
+            if (trailer != null)
+            {
+                if (!info.TrailerTypes.SequenceEqual(trailer.TrailerTypes))
+                {
+                    forceUpdate = true;
+                }
+                trailer.TrailerTypes = info.TrailerTypes;
+            }
+
             item.ChannelId = internalChannelId.ToString("N");
 
             if (item.ParentId != internalChannelId)
@@ -1384,7 +1406,12 @@ namespace MediaBrowser.Server.Implementations.Channels
 
         internal IChannel GetChannelProvider(Channel channel)
         {
-            var result = GetAllChannels().FirstOrDefault(i => string.Equals(i.Name.GetMD5().ToString("N"), channel.ChannelId, StringComparison.OrdinalIgnoreCase) || string.Equals(i.Name, channel.Name, StringComparison.OrdinalIgnoreCase));
+            if (channel == null)
+            {
+                throw new ArgumentNullException("channel");
+            }
+
+            var result = GetAllChannels().FirstOrDefault(i => string.Equals(GetInternalChannelId(i.Name).ToString("N"), channel.ChannelId, StringComparison.OrdinalIgnoreCase) || string.Equals(i.Name, channel.Name, StringComparison.OrdinalIgnoreCase));
 
             if (result == null)
             {
@@ -1519,7 +1546,6 @@ namespace MediaBrowser.Server.Implementations.Channels
                 Progress = new Progress<double>()
             };
 
-            var host = new Uri(source.Path).Host.ToLower();
             var channel = GetChannel(item.ChannelId);
             var channelProvider = GetChannelProvider(channel);
             var features = channelProvider.GetChannelFeatures();

+ 5 - 0
MediaBrowser.Server.Implementations/Dto/DtoService.cs

@@ -316,6 +316,11 @@ namespace MediaBrowser.Server.Implementations.Dto
                 ServerId = _appHost.SystemId
             };
 
+            if (item.SourceType == SourceType.Channel)
+            {
+                dto.SourceType = item.SourceType.ToString();
+            }
+
             if (fields.Contains(ItemFields.People))
             {
                 AttachPeople(dto, item);

+ 28 - 62
MediaBrowser.Server.Implementations/Intros/DefaultIntroProvider.cs

@@ -24,17 +24,15 @@ namespace MediaBrowser.Server.Implementations.Intros
     public class DefaultIntroProvider : IIntroProvider
     {
         private readonly ISecurityManager _security;
-        private readonly IChannelManager _channelManager;
         private readonly ILocalizationManager _localization;
         private readonly IConfigurationManager _serverConfig;
         private readonly ILibraryManager _libraryManager;
         private readonly IFileSystem _fileSystem;
         private readonly IMediaSourceManager _mediaSourceManager;
 
-        public DefaultIntroProvider(ISecurityManager security, IChannelManager channelManager, ILocalizationManager localization, IConfigurationManager serverConfig, ILibraryManager libraryManager, IFileSystem fileSystem, IMediaSourceManager mediaSourceManager)
+        public DefaultIntroProvider(ISecurityManager security, ILocalizationManager localization, IConfigurationManager serverConfig, ILibraryManager libraryManager, IFileSystem fileSystem, IMediaSourceManager mediaSourceManager)
         {
             _security = security;
-            _channelManager = channelManager;
             _localization = localization;
             _serverConfig = serverConfig;
             _libraryManager = libraryManager;
@@ -79,76 +77,45 @@ namespace MediaBrowser.Server.Implementations.Intros
                 AppearsInItemId = item.Id
             });
 
-            if (config.EnableIntrosFromMoviesInLibrary)
-            {
-                var inputItems = _libraryManager.GetItems(new InternalItemsQuery(user)
-                {
-                    IncludeItemTypes = new[] { typeof(Movie).Name }
-
-                }, new string[] { });
-
-                var itemsWithTrailers = inputItems
-                    .Where(i =>
-                    {
-                        var hasTrailers = i as IHasTrailers;
-
-                        if (hasTrailers != null && hasTrailers.LocalTrailerIds.Count > 0)
-                        {
-                            if (i is Movie)
-                            {
-                                return !IsDuplicate(item, i);
-                            }
-                        }
-                        return false;
-                    });
-
-                candidates.AddRange(itemsWithTrailers.Select(i => new ItemWithTrailer
-                {
-                    Item = i,
-                    Type = ItemWithTrailerType.ItemWithTrailer,
-                    User = user,
-                    WatchingItem = item,
-                    WatchingItemPeople = itemPeople,
-                    AllPeople = allPeople,
-                    Random = random,
-                    LibraryManager = _libraryManager
-                }));
-            }
-
             var trailerTypes = new List<TrailerType>();
 
-            if (config.EnableIntrosFromUpcomingTrailers)
-            {
-                trailerTypes.Add(TrailerType.ComingSoonToTheaters);
-            }
-            if (config.EnableIntrosFromUpcomingDvdMovies)
-            {
-                trailerTypes.Add(TrailerType.ComingSoonToDvd);
-            }
-            if (config.EnableIntrosFromUpcomingStreamingMovies)
+            if (config.EnableIntrosFromMoviesInLibrary)
             {
-                trailerTypes.Add(TrailerType.ComingSoonToStreaming);
+                trailerTypes.Add(TrailerType.LocalTrailer);
             }
-            if (config.EnableIntrosFromSimilarMovies)
+
+            if (IsSupporter)
             {
-                trailerTypes.Add(TrailerType.Archive);
+                if (config.EnableIntrosFromUpcomingTrailers)
+                {
+                    trailerTypes.Add(TrailerType.ComingSoonToTheaters);
+                }
+                if (config.EnableIntrosFromUpcomingDvdMovies)
+                {
+                    trailerTypes.Add(TrailerType.ComingSoonToDvd);
+                }
+                if (config.EnableIntrosFromUpcomingStreamingMovies)
+                {
+                    trailerTypes.Add(TrailerType.ComingSoonToStreaming);
+                }
+                if (config.EnableIntrosFromSimilarMovies)
+                {
+                    trailerTypes.Add(TrailerType.Archive);
+                }
             }
 
-            if (trailerTypes.Count > 0 && IsSupporter)
+            if (trailerTypes.Count > 0)
             {
-                var channelTrailers = await _channelManager.GetAllMediaInternal(new AllChannelMediaQuery
+                var trailerResult = _libraryManager.GetItems(new InternalItemsQuery
                 {
-                    ContentTypes = new[] { ChannelMediaContentType.MovieExtra },
-                    ExtraTypes = new[] { ExtraType.Trailer },
-                    UserId = user.Id.ToString("N"),
+                    IncludeItemTypes = new[] { typeof(Trailer).Name },
                     TrailerTypes = trailerTypes.ToArray()
+                });
 
-                }, CancellationToken.None);
-
-                candidates.AddRange(channelTrailers.Items.Select(i => new ItemWithTrailer
+                candidates.AddRange(trailerResult.Items.Select(i => new ItemWithTrailer
                 {
                     Item = i,
-                    Type = ItemWithTrailerType.ChannelTrailer,
+                    Type = i.SourceType == SourceType.Channel ? ItemWithTrailerType.ChannelTrailer : ItemWithTrailerType.ItemWithTrailer,
                     User = user,
                     WatchingItem = item,
                     WatchingItemPeople = itemPeople,
@@ -156,7 +123,7 @@ namespace MediaBrowser.Server.Implementations.Intros
                     Random = random,
                     LibraryManager = _libraryManager
                 }));
-            }
+            } 
 
             return GetResult(item, candidates, config, ratingLevel);
         }
@@ -556,7 +523,6 @@ namespace MediaBrowser.Server.Implementations.Intros
 
         internal enum ItemWithTrailerType
         {
-            LibraryTrailer,
             ChannelTrailer,
             ItemWithTrailer
         }

+ 28 - 13
MediaBrowser.Server.Implementations/Library/LibraryManager.cs

@@ -40,8 +40,10 @@ using CommonIO;
 using MediaBrowser.Model.Extensions;
 using MediaBrowser.Model.Library;
 using MediaBrowser.Model.Net;
+using MediaBrowser.Server.Implementations.Library.Resolvers;
 using MoreLinq;
 using SortOrder = MediaBrowser.Model.Entities.SortOrder;
+using VideoResolver = MediaBrowser.Naming.Video.VideoResolver;
 
 namespace MediaBrowser.Server.Implementations.Library
 {
@@ -454,10 +456,11 @@ namespace MediaBrowser.Server.Implementations.Library
         /// Resolves the item.
         /// </summary>
         /// <param name="args">The args.</param>
+        /// <param name="resolvers">The resolvers.</param>
         /// <returns>BaseItem.</returns>
-        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<BaseItem> ResolvePaths(IEnumerable<FileSystemMetadata> files, IDirectoryService directoryService, Folder parent, string collectionType)
+        {
+            return ResolvePaths(files, directoryService, parent, collectionType, EntityResolvers);
+        }
+
+        public IEnumerable<BaseItem> ResolvePaths(IEnumerable<FileSystemMetadata> 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<IMultiItemResolver>().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<BaseItem> ResolveFileList(IEnumerable<FileSystemMetadata> fileList, IDirectoryService directoryService, Folder parent, string collectionType)
+        private IEnumerable<BaseItem> ResolveFileList(IEnumerable<FileSystemMetadata> 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<Video>()
+            var resolvers = new IItemResolver[]
+            {
+                new GenericVideoResolver<Trailer>(this)
+            };
+
+            return ResolvePaths(files, directoryService, null, null, resolvers)
+                .OfType<Trailer>()
                 .Select(video =>
                 {
                     // Try to retrieve it from the db. If we don't find it, use the resolved version
-                    var dbItem = GetItemById(video.Id) as Video;
+                    var dbItem = GetItemById(video.Id) as Trailer;
 
                     if (dbItem != null)
                     {

+ 4 - 1
MediaBrowser.Server.Implementations/Library/LocalTrailerPostScanTask.cs

@@ -31,7 +31,10 @@ namespace MediaBrowser.Server.Implementations.Library
             var trailerResult = _libraryManager.GetItems(new InternalItemsQuery
             {
                 IncludeItemTypes = new[] { typeof(Trailer).Name },
-                //IsLocalTrailer = false
+                ExcludeTrailerTypes = new[]
+                {
+                    TrailerType.LocalTrailer
+                }
 
             });
             var trailers = trailerResult.Items;

+ 8 - 0
MediaBrowser.Server.Implementations/Library/Resolvers/VideoResolver.cs

@@ -34,4 +34,12 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers
             get { return ResolverPriority.Last; }
         }
     }
+
+    public class GenericVideoResolver<T> : BaseVideoResolver<T>
+        where T : Video, new ()
+    {
+        public GenericVideoResolver(ILibraryManager libraryManager) : base(libraryManager)
+        {
+        }
+    }
 }

+ 53 - 3
MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs

@@ -224,6 +224,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
             _connection.AddColumn(Logger, "TypedBaseItems", "TopParentId", "Text");
             _connection.AddColumn(Logger, "TypedBaseItems", "IsItemByName", "BIT");
             _connection.AddColumn(Logger, "TypedBaseItems", "SourceType", "Text");
+            _connection.AddColumn(Logger, "TypedBaseItems", "TrailerTypes", "Text");
 
             PrepareStatements();
 
@@ -355,7 +356,8 @@ namespace MediaBrowser.Server.Implementations.Persistence
             "LockedFields",
             "Studios",
             "Tags",
-            "SourceType"
+            "SourceType",
+            "TrailerTypes"
         };
 
         private readonly string[] _mediaStreamSaveColumns =
@@ -456,7 +458,8 @@ namespace MediaBrowser.Server.Implementations.Persistence
                 "UnratedType",
                 "TopParentId",
                 "IsItemByName",
-                "SourceType"
+                "SourceType",
+                "TrailerTypes"
             };
             _saveItemCommand = _connection.CreateCommand();
             _saveItemCommand.CommandText = "replace into TypedBaseItems (" + string.Join(",", saveColumns.ToArray()) + ") values (";
@@ -751,7 +754,17 @@ namespace MediaBrowser.Server.Implementations.Persistence
                     _saveItemCommand.GetParameter(index++).Value = isByName;
 
                     _saveItemCommand.GetParameter(index++).Value = item.SourceType.ToString();
-                    
+
+                    var trailer = item as Trailer;
+                    if (trailer != null)
+                    {
+                        _saveItemCommand.GetParameter(index++).Value = string.Join("|", trailer.TrailerTypes.Select(i => i.ToString()).ToArray());
+                    }
+                    else
+                    {
+                        _saveItemCommand.GetParameter(index++).Value = null;
+                    }
+
                     _saveItemCommand.Transaction = transaction;
 
                     _saveItemCommand.ExecuteNonQuery();
@@ -1119,6 +1132,15 @@ namespace MediaBrowser.Server.Implementations.Persistence
                 item.SourceType = (SourceType)Enum.Parse(typeof(SourceType), reader.GetString(49), true);
             }
 
+            var trailer = item as Trailer;
+            if (trailer != null)
+            {
+                if (!reader.IsDBNull(50))
+                {
+                    trailer.TrailerTypes = reader.GetString(50).Split('|').Where(i => !string.IsNullOrWhiteSpace(i)).Select(i => (TrailerType)Enum.Parse(typeof(TrailerType), i, true)).ToList();
+                }
+            }
+
             return item;
         }
 
@@ -1902,6 +1924,34 @@ namespace MediaBrowser.Server.Implementations.Persistence
                 var inClause = string.Join(",", query.ExcludeSourceTypes.Select(i => "'" + i + "'").ToArray());
                 whereClauses.Add(string.Format("SourceType not in ({0})", inClause));
             }
+
+            if (query.TrailerTypes.Length > 0)
+            {
+                var clauses = new List<string>();
+                var index = 0;
+                foreach (var type in query.TrailerTypes)
+                {
+                    clauses.Add("TrailerTypes like @TrailerTypes" + index);
+                    cmd.Parameters.Add(cmd, "@TrailerTypes" + index, DbType.String).Value = "%" + type + "%";
+                    index++;
+                }
+                var clause = "(" + string.Join(" OR ", clauses.ToArray()) + ")";
+                whereClauses.Add(clause);
+            }
+
+            if (query.ExcludeTrailerTypes.Length > 0)
+            {
+                var clauses = new List<string>();
+                var index = 0;
+                foreach (var type in query.ExcludeTrailerTypes)
+                {
+                    clauses.Add("TrailerTypes not like @TrailerTypes" + index);
+                    cmd.Parameters.Add(cmd, "@TrailerTypes" + index, DbType.String).Value = "%" + type + "%";
+                    index++;
+                }
+                var clause = "(" + string.Join(" AND ", clauses.ToArray()) + ")";
+                whereClauses.Add(clause);
+            }
             
             if (query.IsAiring.HasValue)
             {