Luke Pulverenti пре 10 година
родитељ
комит
0708dc953e
22 измењених фајлова са 164 додато и 240 уклоњено
  1. 5 14
      MediaBrowser.Api/ItemLookupService.cs
  2. 5 99
      MediaBrowser.Api/ItemRefreshService.cs
  3. 1 1
      MediaBrowser.Controller/Entities/BaseItem.cs
  4. 1 1
      MediaBrowser.Controller/Entities/TV/Series.cs
  5. 10 1
      MediaBrowser.Controller/Providers/IProviderManager.cs
  6. 0 3
      MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj
  7. 0 100
      MediaBrowser.Model/Dlna/DefaultLocalPlayer.cs
  8. 0 1
      MediaBrowser.Model/MediaBrowser.Model.csproj
  9. 85 8
      MediaBrowser.Providers/Manager/ProviderManager.cs
  10. 1 1
      MediaBrowser.Server.Implementations/Library/LibraryManager.cs
  11. 2 1
      MediaBrowser.Server.Implementations/Library/UserViewManager.cs
  12. 10 2
      MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj
  13. 42 7
      MediaBrowser.Server.Implementations/UserViews/DynamicImageProvider.cs
  14. 2 1
      MediaBrowser.Server.Implementations/UserViews/StripCollageBuilder.cs
  15. BIN
      MediaBrowser.Server.Implementations/UserViews/livetv/1.jpg
  16. BIN
      MediaBrowser.Server.Implementations/UserViews/livetv/2.jpg
  17. BIN
      MediaBrowser.Server.Implementations/UserViews/livetv/3.jpg
  18. BIN
      MediaBrowser.Server.Implementations/UserViews/livetv/4.jpg
  19. BIN
      MediaBrowser.Server.Implementations/UserViews/livetv/5.jpg
  20. BIN
      MediaBrowser.Server.Implementations/UserViews/livetv/6.jpg
  21. BIN
      MediaBrowser.Server.Implementations/UserViews/livetv/7.jpg
  22. BIN
      MediaBrowser.Server.Implementations/UserViews/livetv/8.jpg

+ 5 - 14
MediaBrowser.Api/ItemLookupService.cs

@@ -200,24 +200,15 @@ namespace MediaBrowser.Api
             //}
             item.ProviderIds = request.ProviderIds;
 
-            var service = new ItemRefreshService(_libraryManager)
+            var task = _providerManager.RefreshFullItem(item, new MetadataRefreshOptions
             {
-                Logger = Logger,
-                Request = Request,
-                ResultFactory = ResultFactory,
-                SessionContext = SessionContext,
-                AuthorizationContext = AuthorizationContext
-            };
-
-            service.Post(new RefreshItem
-            {
-                Id = request.Id,
                 MetadataRefreshMode = MetadataRefreshMode.FullRefresh,
                 ImageRefreshMode = ImageRefreshMode.FullRefresh,
                 ReplaceAllMetadata = true,
-                ReplaceAllImages = request.ReplaceAllImages,
-                Recursive = true
-            });
+                ReplaceAllImages = request.ReplaceAllImages
+
+            }, CancellationToken.None);
+            Task.WaitAll(task);
         }
 
         /// <summary>

+ 5 - 99
MediaBrowser.Api/ItemRefreshService.cs

@@ -1,13 +1,7 @@
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Entities.Audio;
-using MediaBrowser.Controller.Library;
+using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.Net;
 using MediaBrowser.Controller.Providers;
 using ServiceStack;
-using System;
-using System.Linq;
-using System.Threading;
-using System.Threading.Tasks;
 
 namespace MediaBrowser.Api
 {
@@ -40,41 +34,12 @@ namespace MediaBrowser.Api
     public class ItemRefreshService : BaseApiService
     {
         private readonly ILibraryManager _libraryManager;
+        private readonly IProviderManager _providerManager;
 
-        public ItemRefreshService(ILibraryManager libraryManager)
+        public ItemRefreshService(ILibraryManager libraryManager, IProviderManager providerManager)
         {
             _libraryManager = libraryManager;
-        }
-
-        private async Task RefreshArtist(RefreshItem request, MusicArtist item)
-        {
-            var cancellationToken = CancellationToken.None;
-
-            var albums = _libraryManager.RootFolder
-                                        .GetRecursiveChildren()
-                                        .OfType<MusicAlbum>()
-                                        .Where(i => i.HasAnyArtist(item.Name))
-                                        .ToList();
-
-            var musicArtists = albums
-                .Select(i => i.Parent)
-                .OfType<MusicArtist>()
-                .ToList();
-
-            var options = GetRefreshOptions(request);
-
-            var musicArtistRefreshTasks = musicArtists.Select(i => i.ValidateChildren(new Progress<double>(), cancellationToken, options, true));
-
-            await Task.WhenAll(musicArtistRefreshTasks).ConfigureAwait(false);
-
-            try
-            {
-                await item.RefreshMetadata(options, CancellationToken.None).ConfigureAwait(false);
-            }
-            catch (Exception ex)
-            {
-                Logger.ErrorException("Error refreshing library", ex);
-            }
+            _providerManager = providerManager;
         }
 
         /// <summary>
@@ -85,68 +50,9 @@ namespace MediaBrowser.Api
         {
             var item = _libraryManager.GetItemById(request.Id);
 
-            var task = item is MusicArtist ? RefreshArtist(request, (MusicArtist)item) : RefreshItem(request, item);
-
-            Task.WaitAll(task);
-        }
-
-        /// <summary>
-        /// Refreshes the item.
-        /// </summary>
-        /// <param name="request">The request.</param>
-        /// <returns>Task.</returns>
-        private async Task RefreshItem(RefreshItem request, BaseItem item)
-        {
             var options = GetRefreshOptions(request);
 
-            try
-            {
-                await item.RefreshMetadata(options, CancellationToken.None).ConfigureAwait(false);
-
-                if (item.IsFolder)
-                {
-                    // Collection folders don't validate their children so we'll have to simulate that here
-                    var collectionFolder = item as CollectionFolder;
-
-                    if (collectionFolder != null)
-                    {
-                        await RefreshCollectionFolderChildren(request, collectionFolder).ConfigureAwait(false);
-                    }
-                    else
-                    {
-                        var folder = (Folder)item;
-
-                        await folder.ValidateChildren(new Progress<double>(), CancellationToken.None, options, request.Recursive).ConfigureAwait(false);
-                    }
-                }
-            }
-            catch (Exception ex)
-            {
-                Logger.ErrorException("Error refreshing library", ex);
-            }
-        }
-
-        /// <summary>
-        /// Refreshes the collection folder children.
-        /// </summary>
-        /// <param name="request">The request.</param>
-        /// <param name="collectionFolder">The collection folder.</param>
-        /// <returns>Task.</returns>
-        private async Task RefreshCollectionFolderChildren(RefreshItem request, CollectionFolder collectionFolder)
-        {
-            var options = GetRefreshOptions(request);
-
-            foreach (var child in collectionFolder.Children.ToList())
-            {
-                await child.RefreshMetadata(options, CancellationToken.None).ConfigureAwait(false);
-
-                if (child.IsFolder)
-                {
-                    var folder = (Folder)child;
-
-                    await folder.ValidateChildren(new Progress<double>(), CancellationToken.None, options, request.Recursive).ConfigureAwait(false);
-                }
-            }
+            _providerManager.QueueRefresh(item.Id, options);
         }
 
         private MetadataRefreshOptions GetRefreshOptions(BaseRefreshRequest request)

+ 1 - 1
MediaBrowser.Controller/Entities/BaseItem.cs

@@ -751,7 +751,7 @@ namespace MediaBrowser.Controller.Entities
                 }
                 : options;
 
-            var result = await ProviderManager.RefreshMetadata(this, refreshOptions, cancellationToken).ConfigureAwait(false);
+            var result = await ProviderManager.RefreshSingleItem(this, refreshOptions, cancellationToken).ConfigureAwait(false);
 
             return result;
         }

+ 1 - 1
MediaBrowser.Controller/Entities/TV/Series.cs

@@ -261,7 +261,7 @@ namespace MediaBrowser.Controller.Entities.TV
                 progress.Report(percent * 100);
             }
 
-            await ProviderManager.RefreshMetadata(this, refreshOptions, cancellationToken).ConfigureAwait(false);
+            await ProviderManager.RefreshSingleItem(this, refreshOptions, cancellationToken).ConfigureAwait(false);
 
             progress.Report(100);
         }

+ 10 - 1
MediaBrowser.Controller/Providers/IProviderManager.cs

@@ -24,6 +24,15 @@ namespace MediaBrowser.Controller.Providers
         /// <param name="options">The options.</param>
         void QueueRefresh(Guid itemId, MetadataRefreshOptions options);
 
+        /// <summary>
+        /// Refreshes the full item.
+        /// </summary>
+        /// <param name="item">The item.</param>
+        /// <param name="options">The options.</param>
+        /// <param name="cancellationToken">The cancellation token.</param>
+        /// <returns>Task.</returns>
+        Task RefreshFullItem(IHasMetadata item, MetadataRefreshOptions options, CancellationToken cancellationToken);
+        
         /// <summary>
         /// Refreshes the metadata.
         /// </summary>
@@ -31,7 +40,7 @@ namespace MediaBrowser.Controller.Providers
         /// <param name="options">The options.</param>
         /// <param name="cancellationToken">The cancellation token.</param>
         /// <returns>Task.</returns>
-        Task<ItemUpdateType> RefreshMetadata(IHasMetadata item, MetadataRefreshOptions options, CancellationToken cancellationToken);
+        Task<ItemUpdateType> RefreshSingleItem(IHasMetadata item, MetadataRefreshOptions options, CancellationToken cancellationToken);
 
         /// <summary>
         /// Saves the image.

+ 0 - 3
MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj

@@ -288,9 +288,6 @@
     <Compile Include="..\MediaBrowser.Model\Dlna\ContentFeatureBuilder.cs">
       <Link>Dlna\ContentFeatureBuilder.cs</Link>
     </Compile>
-    <Compile Include="..\MediaBrowser.Model\Dlna\DefaultLocalPlayer.cs">
-      <Link>Dlna\DefaultLocalPlayer.cs</Link>
-    </Compile>
     <Compile Include="..\MediaBrowser.Model\Dlna\DeviceIdentification.cs">
       <Link>Dlna\DeviceIdentification.cs</Link>
     </Compile>

+ 0 - 100
MediaBrowser.Model/Dlna/DefaultLocalPlayer.cs

@@ -1,100 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Net;
-
-namespace MediaBrowser.Model.Dlna
-{
-    public class DefaultLocalPlayer : ILocalPlayer
-    {
-        public bool CanAccessFile(string path)
-        {
-            return File.Exists(path);
-        }
-
-        public bool CanAccessDirectory(string path)
-        {
-            return Directory.Exists(path);
-        }
-
-        public virtual bool CanAccessUrl(string url, bool requiresCustomRequestHeaders)
-        {
-            if (requiresCustomRequestHeaders)
-            {
-                return false;
-            }
-
-            return CanAccessUrl(url);
-        }
-
-        private readonly Dictionary<string, TestResult> _results = new Dictionary<string, TestResult>(StringComparer.OrdinalIgnoreCase);
-        private readonly object _resultLock = new object();
-
-        private bool CanAccessUrl(string url)
-        {
-            var key = GetHostFromUrl(url);
-            lock (_resultLock)
-            {
-                TestResult result;
-                if (_results.TryGetValue(url, out result))
-                {
-                    var timespan = DateTime.UtcNow - result.Date;
-                    if (timespan <= TimeSpan.FromMinutes(3))
-                    {
-                        return result.Success;
-                    }
-                }
-            }
-
-            var canAccess = CanAccessUrlInternal(url);
-            lock (_resultLock)
-            {
-                _results[key] = new TestResult
-                {
-                    Success = canAccess,
-                    Date = DateTime.UtcNow
-                };
-            }
-            return canAccess;
-        }
-        
-        private bool CanAccessUrlInternal(string url)
-        {
-            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
-            request.Timeout = 5000;
-            request.Method = "HEAD"; 
-            try
-            {
-                using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
-                {
-                    return response.StatusCode == HttpStatusCode.OK;
-                }
-            }
-            catch (WebException)
-            {
-                return false;
-            }
-        }
-
-        protected void ClearUrlTestResultCache()
-        {
-            lock (_resultLock)
-            {
-                _results.Clear();
-            }
-        }
-
-        private string GetHostFromUrl(string url)
-        {
-            var start = url.IndexOf("://", StringComparison.OrdinalIgnoreCase) + 3;
-            var len = url.IndexOf('/', start) - start;
-            return url.Substring(start, len);
-        }
-
-        private class TestResult
-        {
-            public bool Success;
-            public DateTime Date;
-        }
-    }
-}

+ 0 - 1
MediaBrowser.Model/MediaBrowser.Model.csproj

@@ -124,7 +124,6 @@
     <Compile Include="Devices\LocalFileInfo.cs" />
     <Compile Include="Devices\DeviceInfo.cs" />
     <Compile Include="Devices\DevicesOptions.cs" />
-    <Compile Include="Dlna\DefaultLocalPlayer.cs" />
     <Compile Include="Dlna\EncodingContext.cs" />
     <Compile Include="Dlna\ILocalPlayer.cs" />
     <Compile Include="Dlna\NullLocalPlayer.cs" />

+ 85 - 8
MediaBrowser.Providers/Manager/ProviderManager.cs

@@ -111,7 +111,7 @@ namespace MediaBrowser.Providers.Manager
             _externalIds = externalIds.OrderBy(i => i.Name).ToArray();
         }
 
-        public Task<ItemUpdateType> RefreshMetadata(IHasMetadata item, MetadataRefreshOptions options, CancellationToken cancellationToken)
+        public Task<ItemUpdateType> RefreshSingleItem(IHasMetadata item, MetadataRefreshOptions options, CancellationToken cancellationToken)
         {
             var service = _metadataServices.FirstOrDefault(i => i.CanRefresh(item));
 
@@ -897,21 +897,98 @@ namespace MediaBrowser.Providers.Manager
                     return;
                 }
 
-                try
+                var item = libraryManager.GetItemById(refreshItem.Item1);
+                if (item != null)
                 {
-                    var item = libraryManager.GetItemById(refreshItem.Item1);
-                    if (item != null)
+                    try
+                    {
+                        var artist = item as MusicArtist;
+                        var task = artist == null
+                            ? RefreshItem(item, refreshItem.Item2, CancellationToken.None)
+                            : RefreshArtist(artist, refreshItem.Item2);
+
+                        await task.ConfigureAwait(false);
+                    }
+                    catch (Exception ex)
                     {
-                        await item.RefreshMetadata(refreshItem.Item2, CancellationToken.None).ConfigureAwait(false);
+                        _logger.ErrorException("Error refreshing item", ex);
                     }
                 }
-                catch (Exception ex)
+            }
+
+            StopRefreshTimer();
+        }
+
+        private async Task RefreshItem(BaseItem item, MetadataRefreshOptions options, CancellationToken cancellationToken)
+        {
+            await item.RefreshMetadata(options, CancellationToken.None).ConfigureAwait(false);
+
+            if (item.IsFolder)
+            {
+                // Collection folders don't validate their children so we'll have to simulate that here
+                var collectionFolder = item as CollectionFolder;
+
+                if (collectionFolder != null)
+                {
+                    await RefreshCollectionFolderChildren(options, collectionFolder).ConfigureAwait(false);
+                }
+                else
                 {
-                    _logger.ErrorException("Error refreshing item", ex);
+                    var folder = (Folder)item;
+
+                    await folder.ValidateChildren(new Progress<double>(), cancellationToken, options).ConfigureAwait(false);
                 }
             }
+        }
 
-            StopRefreshTimer();
+        private async Task RefreshCollectionFolderChildren(MetadataRefreshOptions options, CollectionFolder collectionFolder)
+        {
+            foreach (var child in collectionFolder.Children.ToList())
+            {
+                await child.RefreshMetadata(options, CancellationToken.None).ConfigureAwait(false);
+
+                if (child.IsFolder)
+                {
+                    var folder = (Folder)child;
+
+                    await folder.ValidateChildren(new Progress<double>(), CancellationToken.None).ConfigureAwait(false);
+                }
+            }
+        }
+
+        private async Task RefreshArtist(MusicArtist item, MetadataRefreshOptions options)
+        {
+            var cancellationToken = CancellationToken.None;
+
+            var albums = _libraryManagerFactory().RootFolder
+                                        .GetRecursiveChildren()
+                                        .OfType<MusicAlbum>()
+                                        .Where(i => i.HasAnyArtist(item.Name))
+                                        .ToList();
+
+            var musicArtists = albums
+                .Select(i => i.Parent)
+                .OfType<MusicArtist>()
+                .ToList();
+
+            var musicArtistRefreshTasks = musicArtists.Select(i => i.ValidateChildren(new Progress<double>(), cancellationToken, options, true));
+
+            await Task.WhenAll(musicArtistRefreshTasks).ConfigureAwait(false);
+
+            try
+            {
+                await item.RefreshMetadata(options, CancellationToken.None).ConfigureAwait(false);
+            }
+            catch (Exception ex)
+            {
+                _logger.ErrorException("Error refreshing library", ex);
+            }
+        }
+
+        public Task RefreshFullItem(IHasMetadata item, MetadataRefreshOptions options,
+            CancellationToken cancellationToken)
+        {
+            return RefreshItem((BaseItem)item, options, cancellationToken);
         }
 
         private bool _disposed;

+ 1 - 1
MediaBrowser.Server.Implementations/Library/LibraryManager.cs

@@ -1673,7 +1673,7 @@ namespace MediaBrowser.Server.Implementations.Library
                 throw new ArgumentNullException("viewType");
             }
 
-            var id = GetNewItemId("23_namedview_" + name + user.Id.ToString("N") + (parentId ?? string.Empty), typeof(UserView));
+            var id = GetNewItemId("27_namedview_" + name + user.Id.ToString("N") + (parentId ?? string.Empty), typeof(UserView));
 
             var path = Path.Combine(ConfigurationManager.ApplicationPaths.InternalMetadataPath, "views", id.ToString("N"));
 

+ 2 - 1
MediaBrowser.Server.Implementations/Library/UserViewManager.cs

@@ -130,7 +130,8 @@ namespace MediaBrowser.Server.Implementations.Library
 
                 if (_liveTvManager.GetEnabledUsers().Select(i => i.Id.ToString("N")).Contains(query.UserId))
                 {
-                    list.Add(await _liveTvManager.GetInternalLiveTvFolder(query.UserId, cancellationToken).ConfigureAwait(false));
+                    //list.Add(await _liveTvManager.GetInternalLiveTvFolder(query.UserId, cancellationToken).ConfigureAwait(false));
+                    list.Add(await GetUserView(CollectionType.LiveTv, string.Empty, user, cancellationToken).ConfigureAwait(false));
                 }
             }
 

+ 10 - 2
MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj

@@ -231,7 +231,7 @@
     <Compile Include="Localization\LocalizationManager.cs" />
     <Compile Include="Logging\PatternsLogger.cs" />
     <Compile Include="MediaEncoder\EncodingManager.cs" />
-    <Compile Include="Photos\DynamicImageProvider.cs" />
+    <Compile Include="UserViews\DynamicImageProvider.cs" />
     <Compile Include="News\NewsEntryPoint.cs" />
     <Compile Include="News\NewsService.cs" />
     <Compile Include="Notifications\CoreNotificationTypes.cs" />
@@ -248,7 +248,7 @@
     <Compile Include="Persistence\TypeMapper.cs" />
     <Compile Include="Photos\BaseDynamicImageProvider.cs" />
     <Compile Include="Photos\DynamicImageHelpers.cs" />
-    <Compile Include="Photos\StripCollageBuilder.cs" />
+    <Compile Include="UserViews\StripCollageBuilder.cs" />
     <Compile Include="Playlists\ManualPlaylistsFolder.cs" />
     <Compile Include="Photos\PhotoAlbumImageProvider.cs" />
     <Compile Include="Playlists\PlaylistImageProvider.cs" />
@@ -514,6 +514,14 @@
       <Link>swagger-ui\swagger-ui.min.js</Link>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
+    <EmbeddedResource Include="UserViews\livetv\1.jpg" />
+    <EmbeddedResource Include="UserViews\livetv\2.jpg" />
+    <EmbeddedResource Include="UserViews\livetv\3.jpg" />
+    <EmbeddedResource Include="UserViews\livetv\4.jpg" />
+    <EmbeddedResource Include="UserViews\livetv\5.jpg" />
+    <EmbeddedResource Include="UserViews\livetv\6.jpg" />
+    <EmbeddedResource Include="UserViews\livetv\7.jpg" />
+    <EmbeddedResource Include="UserViews\livetv\8.jpg" />
     <EmbeddedResource Include="Localization\iso6392.txt" />
     <EmbeddedResource Include="Localization\Ratings\be.txt" />
   </ItemGroup>

+ 42 - 7
MediaBrowser.Server.Implementations/Photos/DynamicImageProvider.cs → MediaBrowser.Server.Implementations/UserViews/DynamicImageProvider.cs

@@ -1,4 +1,5 @@
-using MediaBrowser.Common.Configuration;
+using System.Globalization;
+using MediaBrowser.Common.Configuration;
 using MediaBrowser.Common.IO;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Entities.Audio;
@@ -6,6 +7,7 @@ using MediaBrowser.Controller.Entities.TV;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.Providers;
 using MediaBrowser.Model.Entities;
+using MediaBrowser.Server.Implementations.Photos;
 using MoreLinq;
 using System;
 using System.Collections.Generic;
@@ -13,7 +15,7 @@ using System.IO;
 using System.Linq;
 using System.Threading.Tasks;
 
-namespace MediaBrowser.Server.Implementations.Photos
+namespace MediaBrowser.Server.Implementations.UserViews
 {
     public class DynamicImageProvider : BaseDynamicImageProvider<UserView>
     {
@@ -54,6 +56,11 @@ namespace MediaBrowser.Server.Implementations.Photos
                 return new List<BaseItem>();
             }
 
+            if (string.Equals(view.ViewType, CollectionType.LiveTv, StringComparison.OrdinalIgnoreCase))
+            {
+                return new List<BaseItem>();
+            }
+
             if (string.Equals(view.ViewType, SpecialFolder.GameGenre, StringComparison.OrdinalIgnoreCase))
             {
                 var list = new List<BaseItem>();
@@ -93,14 +100,14 @@ namespace MediaBrowser.Server.Implementations.Photos
             }
 
             var isUsingCollectionStrip = IsUsingCollectionStrip(view);
-            var recursive = isUsingCollectionStrip && !new[] {CollectionType.Playlists, CollectionType.Channels}.Contains(view.ViewType ?? string.Empty, StringComparer.OrdinalIgnoreCase);
+            var recursive = isUsingCollectionStrip && !new[] { CollectionType.Playlists, CollectionType.Channels }.Contains(view.ViewType ?? string.Empty, StringComparer.OrdinalIgnoreCase);
 
             var result = await view.GetItems(new InternalItemsQuery
             {
                 User = _userManager.GetUserById(view.UserId.Value),
                 CollapseBoxSetItems = false,
                 Recursive = recursive,
-                ExcludeItemTypes = new[] { "UserView", "CollectionFolder"}
+                ExcludeItemTypes = new[] { "UserView", "CollectionFolder" }
 
             }).ConfigureAwait(false);
 
@@ -219,7 +226,8 @@ namespace MediaBrowser.Server.Implementations.Photos
                 CollectionType.Music,
                 CollectionType.BoxSets,
                 CollectionType.Playlists,
-                CollectionType.Channels
+                CollectionType.Channels,
+                CollectionType.LiveTv
             };
 
             return collectionStripViewTypes.Contains(view.ViewType ?? string.Empty);
@@ -230,18 +238,45 @@ namespace MediaBrowser.Server.Implementations.Photos
             var view = (UserView)item;
             if (imageType == ImageType.Primary && IsUsingCollectionStrip(view))
             {
-                var stream = new StripCollageBuilder(ApplicationPaths).BuildThumbCollage(GetStripCollageImagePaths(itemsWithImages), item.Name, 960, 540);
+                var stream = new StripCollageBuilder(ApplicationPaths).BuildThumbCollage(GetStripCollageImagePaths(itemsWithImages, view.ViewType), item.Name, 960, 540);
                 return Task.FromResult(stream);
             }
 
             return base.CreateImageAsync(item, itemsWithImages, imageType, imageIndex);
         }
 
-        private IEnumerable<String> GetStripCollageImagePaths(IEnumerable<BaseItem> items)
+        private IEnumerable<String> GetStripCollageImagePaths(IEnumerable<BaseItem> items, string viewType)
         {
+            if (string.Equals(viewType, CollectionType.LiveTv, StringComparison.OrdinalIgnoreCase))
+            {
+                var list = new List<string>();
+                for (int i = 1; i <= 8; i++)
+                {
+                    list.Add(ExtractLiveTvResource(i.ToString(CultureInfo.InvariantCulture), ApplicationPaths));
+                }
+                return list;
+            }
+
             return items
                 .Select(i => i.GetImagePath(ImageType.Primary) ?? i.GetImagePath(ImageType.Thumb))
                 .Where(i => !string.IsNullOrWhiteSpace(i));
         }
+
+        private string ExtractLiveTvResource(string name, IApplicationPaths paths)
+        {
+            var namespacePath = GetType().Namespace + ".livetv." + name + ".jpg";
+            var tempPath = Path.Combine(paths.TempDirectory, Guid.NewGuid().ToString("N") + ".jpg");
+            Directory.CreateDirectory(Path.GetDirectoryName(tempPath));
+
+            using (var stream = GetType().Assembly.GetManifestResourceStream(namespacePath))
+            {
+                using (var fileStream = new FileStream(tempPath, FileMode.Create, FileAccess.Write, FileShare.Read))
+                {
+                    stream.CopyTo(fileStream);
+                }
+            }
+
+            return tempPath;
+        }
     }
 }

+ 2 - 1
MediaBrowser.Server.Implementations/Photos/StripCollageBuilder.cs → MediaBrowser.Server.Implementations/UserViews/StripCollageBuilder.cs

@@ -1,12 +1,13 @@
 using ImageMagickSharp;
 using MediaBrowser.Common.Configuration;
 using MediaBrowser.Server.Implementations.Drawing;
+using MediaBrowser.Server.Implementations.Photos;
 using System;
 using System.Collections.Generic;
 using System.IO;
 using System.Linq;
 
-namespace MediaBrowser.Server.Implementations.Photos
+namespace MediaBrowser.Server.Implementations.UserViews
 {
     public class StripCollageBuilder
     {

BIN
MediaBrowser.Server.Implementations/UserViews/livetv/1.jpg


BIN
MediaBrowser.Server.Implementations/UserViews/livetv/2.jpg


BIN
MediaBrowser.Server.Implementations/UserViews/livetv/3.jpg


BIN
MediaBrowser.Server.Implementations/UserViews/livetv/4.jpg


BIN
MediaBrowser.Server.Implementations/UserViews/livetv/5.jpg


BIN
MediaBrowser.Server.Implementations/UserViews/livetv/6.jpg


BIN
MediaBrowser.Server.Implementations/UserViews/livetv/7.jpg


BIN
MediaBrowser.Server.Implementations/UserViews/livetv/8.jpg