瀏覽代碼

Merge branch 'master' of https://github.com/MediaBrowser/MediaBrowser

Conflicts:
	MediaBrowser.WebDashboard/dashboard-ui/scripts/mediaplayer.js
Tim Hobbs 11 年之前
父節點
當前提交
482fde6587
共有 73 個文件被更改,包括 1443 次插入525 次删除
  1. 2 2
      MediaBrowser.Api/GamesService.cs
  2. 289 0
      MediaBrowser.Api/ItemLookupService.cs
  3. 1 26
      MediaBrowser.Api/Library/LibraryService.cs
  4. 1 0
      MediaBrowser.Api/MediaBrowser.Api.csproj
  5. 15 2
      MediaBrowser.Api/Playback/BaseStreamingService.cs
  6. 4 2
      MediaBrowser.Api/Playback/Hls/BaseHlsService.cs
  7. 3 1
      MediaBrowser.Api/Playback/Hls/VideoHlsService.cs
  8. 1 0
      MediaBrowser.Api/Playback/StreamState.cs
  9. 56 1
      MediaBrowser.Api/UserLibrary/ItemsService.cs
  10. 4 4
      MediaBrowser.Common.Implementations/MediaBrowser.Common.Implementations.csproj
  11. 1 1
      MediaBrowser.Common.Implementations/packages.config
  12. 2 0
      MediaBrowser.Controller/Entities/BaseItem.cs
  13. 2 2
      MediaBrowser.Controller/Entities/CollectionFolder.cs
  14. 21 1
      MediaBrowser.Controller/Entities/Folder.cs
  15. 4 4
      MediaBrowser.Controller/Entities/Game.cs
  16. 6 6
      MediaBrowser.Controller/Entities/IHasMetadata.cs
  17. 12 0
      MediaBrowser.Controller/Entities/ISupportsPlaceHolders.cs
  18. 1 1
      MediaBrowser.Controller/Entities/TV/Episode.cs
  19. 10 8
      MediaBrowser.Controller/Entities/Video.cs
  20. 5 2
      MediaBrowser.Controller/Library/TVUtils.cs
  21. 1 0
      MediaBrowser.Controller/MediaBrowser.Controller.csproj
  22. 10 7
      MediaBrowser.Controller/MediaEncoding/MediaEncoderHelpers.cs
  23. 0 1
      MediaBrowser.Controller/Providers/BaseItemXmlParser.cs
  24. 5 0
      MediaBrowser.Controller/Providers/ICustomMetadataProvider.cs
  25. 11 1
      MediaBrowser.Controller/Providers/IProviderManager.cs
  26. 7 4
      MediaBrowser.Controller/Providers/IRemoteMetadataProvider.cs
  27. 28 3
      MediaBrowser.Controller/Resolvers/BaseVideoResolver.cs
  28. 18 0
      MediaBrowser.Controller/Resolvers/EntityResolutionHelper.cs
  29. 1 1
      MediaBrowser.Dlna/PlayTo/PlayToServerEntryPoint.cs
  30. 3 0
      MediaBrowser.Model/Configuration/ServerConfiguration.cs
  31. 10 0
      MediaBrowser.Model/Dto/BaseItemDto.cs
  32. 2 0
      MediaBrowser.Model/Providers/RemoteSearchResult.cs
  33. 6 0
      MediaBrowser.Model/System/SystemInfo.cs
  34. 52 8
      MediaBrowser.Providers/BoxSets/MovieDbBoxSetProvider.cs
  35. 6 7
      MediaBrowser.Providers/Games/GameMetadataService.cs
  36. 23 1
      MediaBrowser.Providers/Manager/MetadataService.cs
  37. 40 3
      MediaBrowser.Providers/Manager/ProviderManager.cs
  38. 5 0
      MediaBrowser.Providers/Manager/ProviderUtils.cs
  39. 6 1
      MediaBrowser.Providers/MediaInfo/FFProbeProvider.cs
  40. 51 41
      MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs
  41. 1 1
      MediaBrowser.Providers/MediaInfo/VideoImageProvider.cs
  42. 1 1
      MediaBrowser.Providers/Movies/FanartMovieImageProvider.cs
  43. 13 6
      MediaBrowser.Providers/Movies/GenericMovieDbInfo.cs
  44. 65 7
      MediaBrowser.Providers/Movies/MovieDbProvider.cs
  45. 88 78
      MediaBrowser.Providers/Movies/MovieDbSearch.cs
  46. 15 3
      MediaBrowser.Providers/Movies/MovieDbTrailerProvider.cs
  47. 1 1
      MediaBrowser.Providers/Music/FanArtArtistProvider.cs
  48. 14 3
      MediaBrowser.Providers/People/MovieDbPersonProvider.cs
  49. 11 2
      MediaBrowser.Providers/Savers/SeriesXmlSaver.cs
  50. 1 1
      MediaBrowser.Providers/TV/FanartSeriesProvider.cs
  51. 8 5
      MediaBrowser.Providers/TV/MissingEpisodeProvider.cs
  52. 106 18
      MediaBrowser.Providers/TV/MovieDbSeriesProvider.cs
  53. 15 0
      MediaBrowser.Providers/TV/SeriesXmlParser.cs
  54. 3 0
      MediaBrowser.Providers/TV/TvdbEpisodeProvider.cs
  55. 6 0
      MediaBrowser.Providers/TV/TvdbPrescanTask.cs
  56. 13 2
      MediaBrowser.Providers/TV/TvdbSeriesProvider.cs
  57. 9 0
      MediaBrowser.Server.Implementations/Dto/DtoService.cs
  58. 14 14
      MediaBrowser.Server.Implementations/EntryPoints/ExternalPortForwarding.cs
  59. 19 1
      MediaBrowser.Server.Implementations/Library/LibraryManager.cs
  60. 1 0
      MediaBrowser.Server.Implementations/Library/Resolvers/Audio/MusicAlbumResolver.cs
  61. 1 2
      MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs
  62. 5 0
      MediaBrowser.Server.Implementations/MediaEncoder/EncodingManager.cs
  63. 1 3
      MediaBrowser.Server.Implementations/MediaEncoder/MediaEncoder.cs
  64. 1 3
      MediaBrowser.Server.Implementations/ScheduledTasks/PeopleValidationTask.cs
  65. 1 1
      MediaBrowser.Server.Implementations/ScheduledTasks/RefreshMediaLibraryTask.cs
  66. 60 3
      MediaBrowser.ServerApplication/ApplicationHost.cs
  67. 13 11
      MediaBrowser.ServerApplication/FFMpeg/FFMpegDownloadInfo.cs
  68. 8 5
      MediaBrowser.ServerApplication/LibraryViewer.cs
  69. 4 4
      MediaBrowser.WebDashboard/Api/DashboardService.cs
  70. 215 204
      MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj
  71. 2 2
      Nuget/MediaBrowser.Common.Internal.nuspec
  72. 1 1
      Nuget/MediaBrowser.Common.nuspec
  73. 2 2
      Nuget/MediaBrowser.Server.Core.nuspec

+ 2 - 2
MediaBrowser.Api/GamesService.cs

@@ -155,11 +155,11 @@ namespace MediaBrowser.Api
 
 
             var games = items.OfType<Game>().ToList();
             var games = items.OfType<Game>().ToList();
 
 
-            summary.ClientInstalledGameCount = games.Count(i => !i.IsInstalledOnClient);
+            summary.ClientInstalledGameCount = games.Count(i => !i.IsPlaceHolder);
 
 
             summary.GameCount = games.Count;
             summary.GameCount = games.Count;
 
 
-            summary.GameFileExtensions = games.Where(i => !i.IsInstalledOnClient).Select(i => Path.GetExtension(i.Path))
+            summary.GameFileExtensions = games.Where(i => !i.IsPlaceHolder).Select(i => Path.GetExtension(i.Path))
                 .Distinct(StringComparer.OrdinalIgnoreCase)
                 .Distinct(StringComparer.OrdinalIgnoreCase)
                 .ToList();
                 .ToList();
 
 

+ 289 - 0
MediaBrowser.Api/ItemLookupService.cs

@@ -0,0 +1,289 @@
+using MediaBrowser.Common.Extensions;
+using MediaBrowser.Common.IO;
+using MediaBrowser.Controller;
+using MediaBrowser.Controller.Dto;
+using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Entities.Movies;
+using MediaBrowser.Controller.Entities.TV;
+using MediaBrowser.Controller.Library;
+using MediaBrowser.Controller.Providers;
+using MediaBrowser.Model.Entities;
+using MediaBrowser.Model.Providers;
+using ServiceStack;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace MediaBrowser.Api
+{
+    [Route("/Items/{Id}/ExternalIdInfos", "GET")]
+    [Api(Description = "Gets external id infos for an item")]
+    public class GetExternalIdInfos : IReturn<List<ExternalIdInfo>>
+    {
+        /// <summary>
+        /// Gets or sets the id.
+        /// </summary>
+        /// <value>The id.</value>
+        [ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
+        public string Id { get; set; }
+    }
+
+    [Route("/Items/RemoteSearch/Movie", "POST")]
+    [Api(Description = "Gets external id infos for an item")]
+    public class GetMovieRemoteSearchResults : RemoteSearchQuery<MovieInfo>, IReturn<List<RemoteSearchResult>>
+    {
+    }
+
+    [Route("/Items/RemoteSearch/Trailer", "POST")]
+    [Api(Description = "Gets external id infos for an item")]
+    public class GetTrailerRemoteSearchResults : RemoteSearchQuery<TrailerInfo>, IReturn<List<RemoteSearchResult>>
+    {
+    }
+
+    [Route("/Items/RemoteSearch/AdultVideo", "POST")]
+    [Api(Description = "Gets external id infos for an item")]
+    public class GetAdultVideoRemoteSearchResults : RemoteSearchQuery<ItemLookupInfo>, IReturn<List<RemoteSearchResult>>
+    {
+    }
+
+    [Route("/Items/RemoteSearch/Series", "POST")]
+    [Api(Description = "Gets external id infos for an item")]
+    public class GetSeriesRemoteSearchResults : RemoteSearchQuery<SeriesInfo>, IReturn<List<RemoteSearchResult>>
+    {
+    }
+
+    [Route("/Items/RemoteSearch/Game", "POST")]
+    [Api(Description = "Gets external id infos for an item")]
+    public class GetGameRemoteSearchResults : RemoteSearchQuery<GameInfo>, IReturn<List<RemoteSearchResult>>
+    {
+    }
+
+    [Route("/Items/RemoteSearch/BoxSet", "POST")]
+    [Api(Description = "Gets external id infos for an item")]
+    public class GetBoxSetRemoteSearchResults : RemoteSearchQuery<BoxSetInfo>, IReturn<List<RemoteSearchResult>>
+    {
+    }
+
+    [Route("/Items/RemoteSearch/Person", "POST")]
+    [Api(Description = "Gets external id infos for an item")]
+    public class GetPersonRemoteSearchResults : RemoteSearchQuery<PersonLookupInfo>, IReturn<List<RemoteSearchResult>>
+    {
+    }
+
+    [Route("/Items/RemoteSearch/Image", "GET")]
+    [Api(Description = "Gets a remote image")]
+    public class GetRemoteSearchImage
+    {
+        [ApiMember(Name = "ImageUrl", Description = "The image url", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")]
+        public string ImageUrl { get; set; }
+
+        [ApiMember(Name = "ProviderName", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")]
+        public string ProviderName { get; set; }
+    }
+
+    [Route("/Items/RemoteSearch/Apply/{Id}", "POST")]
+    [Api(Description = "Applies search criteria to an item and refreshes metadata")]
+    public class ApplySearchCriteria : RemoteSearchResult, IReturnVoid
+    {
+        [ApiMember(Name = "Id", Description = "The item id", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")]
+        public string Id { get; set; }
+    }
+
+    public class ItemLookupService : BaseApiService
+    {
+        private readonly IDtoService _dtoService;
+        private readonly IProviderManager _providerManager;
+        private readonly IServerApplicationPaths _appPaths;
+        private readonly IFileSystem _fileSystem;
+        private readonly ILibraryManager _libraryManager;
+
+        public ItemLookupService(IDtoService dtoService, IProviderManager providerManager, IServerApplicationPaths appPaths, IFileSystem fileSystem, ILibraryManager libraryManager)
+        {
+            _dtoService = dtoService;
+            _providerManager = providerManager;
+            _appPaths = appPaths;
+            _fileSystem = fileSystem;
+            _libraryManager = libraryManager;
+        }
+
+        public object Get(GetExternalIdInfos request)
+        {
+            var item = _dtoService.GetItemByDtoId(request.Id);
+
+            var infos = _providerManager.GetExternalIdInfos(item).ToList();
+
+            return ToOptimizedResult(infos);
+        }
+
+        public object Post(GetMovieRemoteSearchResults request)
+        {
+            var result = _providerManager.GetRemoteSearchResults<Movie, MovieInfo>(request, CancellationToken.None).Result;
+
+            return ToOptimizedResult(result);
+        }
+
+        public object Post(GetAdultVideoRemoteSearchResults request)
+        {
+            var result = _providerManager.GetRemoteSearchResults<AdultVideo, ItemLookupInfo>(request, CancellationToken.None).Result;
+
+            return ToOptimizedResult(result);
+        }
+
+        public object Post(GetSeriesRemoteSearchResults request)
+        {
+            var result = _providerManager.GetRemoteSearchResults<Series, SeriesInfo>(request, CancellationToken.None).Result;
+
+            return ToOptimizedResult(result);
+        }
+
+        public object Post(GetGameRemoteSearchResults request)
+        {
+            var result = _providerManager.GetRemoteSearchResults<Game, GameInfo>(request, CancellationToken.None).Result;
+
+            return ToOptimizedResult(result);
+        }
+
+        public object Post(GetBoxSetRemoteSearchResults request)
+        {
+            var result = _providerManager.GetRemoteSearchResults<BoxSet, BoxSetInfo>(request, CancellationToken.None).Result;
+
+            return ToOptimizedResult(result);
+        }
+
+        public object Post(GetPersonRemoteSearchResults request)
+        {
+            var result = _providerManager.GetRemoteSearchResults<Person, PersonLookupInfo>(request, CancellationToken.None).Result;
+
+            return ToOptimizedResult(result);
+        }
+
+        public object Post(GetTrailerRemoteSearchResults request)
+        {
+            var result = _providerManager.GetRemoteSearchResults<Trailer, TrailerInfo>(request, CancellationToken.None).Result;
+
+            return ToOptimizedResult(result);
+        }
+
+        public object Get(GetRemoteSearchImage request)
+        {
+            var result = GetRemoteImage(request).Result;
+
+            return result;
+        }
+
+        public void Post(ApplySearchCriteria request)
+        {
+            var item = _libraryManager.GetItemById(new Guid(request.Id));
+
+            foreach (var key in request.ProviderIds)
+            {
+                var value = key.Value;
+
+                if (!string.IsNullOrWhiteSpace(value))
+                {
+                    item.SetProviderId(key.Key, value);
+                }
+            }
+
+            var task = item.RefreshMetadata(new MetadataRefreshOptions
+            {
+                MetadataRefreshMode = MetadataRefreshMode.FullRefresh,
+                ImageRefreshMode = ImageRefreshMode.FullRefresh,
+                ReplaceAllMetadata = true
+
+            }, CancellationToken.None);
+
+            Task.WaitAll(task);
+        }
+
+        /// <summary>
+        /// Gets the remote image.
+        /// </summary>
+        /// <param name="request">The request.</param>
+        /// <returns>Task{System.Object}.</returns>
+        private async Task<object> GetRemoteImage(GetRemoteSearchImage request)
+        {
+            var urlHash = request.ImageUrl.GetMD5();
+            var pointerCachePath = GetFullCachePath(urlHash.ToString());
+
+            string contentPath;
+
+            try
+            {
+                using (var reader = new StreamReader(pointerCachePath))
+                {
+                    contentPath = await reader.ReadToEndAsync().ConfigureAwait(false);
+                }
+
+                if (File.Exists(contentPath))
+                {
+                    return ToStaticFileResult(contentPath);
+                }
+            }
+            catch (DirectoryNotFoundException)
+            {
+                // Means the file isn't cached yet
+            }
+            catch (FileNotFoundException)
+            {
+                // Means the file isn't cached yet
+            }
+
+            await DownloadImage(request.ProviderName, request.ImageUrl, urlHash, pointerCachePath).ConfigureAwait(false);
+
+            // Read the pointer file again
+            using (var reader = new StreamReader(pointerCachePath))
+            {
+                contentPath = await reader.ReadToEndAsync().ConfigureAwait(false);
+            }
+
+            return ToStaticFileResult(contentPath);
+        }
+
+        /// <summary>
+        /// Downloads the image.
+        /// </summary>
+        /// <param name="providerName">Name of the provider.</param>
+        /// <param name="url">The URL.</param>
+        /// <param name="urlHash">The URL hash.</param>
+        /// <param name="pointerCachePath">The pointer cache path.</param>
+        /// <returns>Task.</returns>
+        private async Task DownloadImage(string providerName, string url, Guid urlHash, string pointerCachePath)
+        {
+            var result = await _providerManager.GetSearchImage(providerName, url, CancellationToken.None).ConfigureAwait(false);
+
+            var ext = result.ContentType.Split('/').Last();
+
+            var fullCachePath = GetFullCachePath(urlHash + "." + ext);
+
+            Directory.CreateDirectory(Path.GetDirectoryName(fullCachePath));
+            using (var stream = result.Content)
+            {
+                using (var filestream = _fileSystem.GetFileStream(fullCachePath, FileMode.Create, FileAccess.Write, FileShare.Read, true))
+                {
+                    await stream.CopyToAsync(filestream).ConfigureAwait(false);
+                }
+            }
+
+            Directory.CreateDirectory(Path.GetDirectoryName(pointerCachePath));
+            using (var writer = new StreamWriter(pointerCachePath))
+            {
+                await writer.WriteAsync(fullCachePath).ConfigureAwait(false);
+            }
+        }
+
+        /// <summary>
+        /// Gets the full cache path.
+        /// </summary>
+        /// <param name="filename">The filename.</param>
+        /// <returns>System.String.</returns>
+        private string GetFullCachePath(string filename)
+        {
+            return Path.Combine(_appPaths.CachePath, "remote-images", filename.Substring(0, 1), filename);
+        }
+
+    }
+}

+ 1 - 26
MediaBrowser.Api/Library/LibraryService.cs

@@ -6,10 +6,8 @@ using MediaBrowser.Controller.Entities.Movies;
 using MediaBrowser.Controller.Entities.TV;
 using MediaBrowser.Controller.Entities.TV;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.Persistence;
 using MediaBrowser.Controller.Persistence;
-using MediaBrowser.Controller.Providers;
 using MediaBrowser.Model.Dto;
 using MediaBrowser.Model.Dto;
 using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.Entities;
-using MediaBrowser.Model.Providers;
 using MediaBrowser.Model.Querying;
 using MediaBrowser.Model.Querying;
 using ServiceStack;
 using ServiceStack;
 using System;
 using System;
@@ -50,18 +48,6 @@ namespace MediaBrowser.Api.Library
         public int Index { get; set; }
         public int Index { get; set; }
     }
     }
 
 
-    [Route("/Items/{Id}/ExternalIdInfos", "GET")]
-    [Api(Description = "Gets external id infos for an item")]
-    public class GetExternalIdInfos : IReturn<List<ExternalIdInfo>>
-    {
-        /// <summary>
-        /// Gets or sets the id.
-        /// </summary>
-        /// <value>The id.</value>
-        [ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
-        public string Id { get; set; }
-    }
-    
     /// <summary>
     /// <summary>
     /// Class GetCriticReviews
     /// Class GetCriticReviews
     /// </summary>
     /// </summary>
@@ -256,29 +242,18 @@ namespace MediaBrowser.Api.Library
         private readonly IUserDataManager _userDataManager;
         private readonly IUserDataManager _userDataManager;
 
 
         private readonly IDtoService _dtoService;
         private readonly IDtoService _dtoService;
-        private readonly IProviderManager _providerManager;
 
 
         /// <summary>
         /// <summary>
         /// Initializes a new instance of the <see cref="LibraryService" /> class.
         /// Initializes a new instance of the <see cref="LibraryService" /> class.
         /// </summary>
         /// </summary>
         public LibraryService(IItemRepository itemRepo, ILibraryManager libraryManager, IUserManager userManager,
         public LibraryService(IItemRepository itemRepo, ILibraryManager libraryManager, IUserManager userManager,
-                              IDtoService dtoService, IUserDataManager userDataManager, IProviderManager providerManager)
+                              IDtoService dtoService, IUserDataManager userDataManager)
         {
         {
             _itemRepo = itemRepo;
             _itemRepo = itemRepo;
             _libraryManager = libraryManager;
             _libraryManager = libraryManager;
             _userManager = userManager;
             _userManager = userManager;
             _dtoService = dtoService;
             _dtoService = dtoService;
             _userDataManager = userDataManager;
             _userDataManager = userDataManager;
-            _providerManager = providerManager;
-        }
-
-        public object Get(GetExternalIdInfos request)
-        {
-            var item = _dtoService.GetItemByDtoId(request.Id);
-
-            var infos = _providerManager.GetExternalIdInfos(item).ToList();
-
-            return ToOptimizedResult(infos);
         }
         }
 
 
         public object Get(GetMediaFolders request)
         public object Get(GetMediaFolders request)

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

@@ -82,6 +82,7 @@
     <Compile Include="Images\ImageService.cs" />
     <Compile Include="Images\ImageService.cs" />
     <Compile Include="Images\ImageWriter.cs" />
     <Compile Include="Images\ImageWriter.cs" />
     <Compile Include="InstantMixService.cs" />
     <Compile Include="InstantMixService.cs" />
+    <Compile Include="ItemLookupService.cs" />
     <Compile Include="ItemRefreshService.cs" />
     <Compile Include="ItemRefreshService.cs" />
     <Compile Include="ItemUpdateService.cs" />
     <Compile Include="ItemUpdateService.cs" />
     <Compile Include="Library\LibraryService.cs" />
     <Compile Include="Library\LibraryService.cs" />

+ 15 - 2
MediaBrowser.Api/Playback/BaseStreamingService.cs

@@ -265,7 +265,7 @@ namespace MediaBrowser.Api.Playback
 
 
                 if (cpuCount >= 4)
                 if (cpuCount >= 4)
                 {
                 {
-                    return EncodingQuality.HighQuality;
+                    //return EncodingQuality.HighQuality;
                 }
                 }
 
 
                 return EncodingQuality.HighSpeed;
                 return EncodingQuality.HighSpeed;
@@ -491,6 +491,16 @@ namespace MediaBrowser.Api.Playback
 
 
                 return string.Format("{4} -vf \"{0}scale=trunc({1}/2)*2:trunc({2}/2)*2{3}\"", yadifParam, widthParam, heightParam, assSubtitleParam, copyTsParam);
                 return string.Format("{4} -vf \"{0}scale=trunc({1}/2)*2:trunc({2}/2)*2{3}\"", yadifParam, widthParam, heightParam, assSubtitleParam, copyTsParam);
             }
             }
+            
+              // If Max dimensions were supplied
+              //this makes my brain hurt. For width selects lowest even number between input width and width req size and selects lowest even number from in width*display aspect and requested size
+             if (request.MaxWidth.HasValue && request.MaxHeight.HasValue)
+             {
+                 var MaxwidthParam = request.MaxWidth.Value.ToString(UsCulture);
+                 var MaxheightParam = request.MaxHeight.Value.ToString(UsCulture);
+ 
+                 return string.Format("{4} -vf \"{0}scale=trunc(min(iw\\,{1})/2)*2:trunc(min((iw/dar)\\,{2})/2)*2{3}\"", yadifParam, MaxwidthParam, MaxheightParam, assSubtitleParam, copyTsParam);
+             }
 
 
             var isH264Output = outputVideoCodec.Equals("libx264", StringComparison.OrdinalIgnoreCase);
             var isH264Output = outputVideoCodec.Equals("libx264", StringComparison.OrdinalIgnoreCase);
 
 
@@ -608,7 +618,7 @@ namespace MediaBrowser.Api.Playback
 
 
                     // Don't re-encode ass/ssa to ass because ffmpeg ass encoder fails if there's more than one ass rectangle. Affect Anime mostly.
                     // Don't re-encode ass/ssa to ass because ffmpeg ass encoder fails if there's more than one ass rectangle. Affect Anime mostly.
                     // See https://lists.ffmpeg.org/pipermail/ffmpeg-cvslog/2013-April/063616.html
                     // See https://lists.ffmpeg.org/pipermail/ffmpeg-cvslog/2013-April/063616.html
-                    bool isAssSubtitle = string.Equals(state.SubtitleStream.Codec, "ass", StringComparison.OrdinalIgnoreCase) || string.Equals(state.SubtitleStream.Codec, "ssa", StringComparison.OrdinalIgnoreCase);
+                    var isAssSubtitle = string.Equals(state.SubtitleStream.Codec, "ass", StringComparison.OrdinalIgnoreCase) || string.Equals(state.SubtitleStream.Codec, "ssa", StringComparison.OrdinalIgnoreCase);
 
 
                     var task = MediaEncoder.ExtractTextSubtitle(inputPath, type, state.SubtitleStream.Index, isAssSubtitle, path, CancellationToken.None);
                     var task = MediaEncoder.ExtractTextSubtitle(inputPath, type, state.SubtitleStream.Index, isAssSubtitle, path, CancellationToken.None);
 
 
@@ -1408,6 +1418,9 @@ namespace MediaBrowser.Api.Playback
 
 
             state.HasMediaStreams = mediaStreams.Count > 0;
             state.HasMediaStreams = mediaStreams.Count > 0;
 
 
+            state.SegmentLength = state.ReadInputAtNativeFramerate ? 3 : 10;
+            state.HlsListSize = state.ReadInputAtNativeFramerate ? 20 : 1440;
+
             return state;
             return state;
         }
         }
 
 

+ 4 - 2
MediaBrowser.Api/Playback/Hls/BaseHlsService.cs

@@ -285,7 +285,7 @@ namespace MediaBrowser.Api.Playback.Hls
             // If performSubtitleConversions is true we're actually starting ffmpeg
             // If performSubtitleConversions is true we're actually starting ffmpeg
             var startNumberParam = performSubtitleConversions ? GetStartNumber(state).ToString(UsCulture) : "0";
             var startNumberParam = performSubtitleConversions ? GetStartNumber(state).ToString(UsCulture) : "0";
             
             
-            var args = string.Format("{0} {1} -i {2}{3} -map_metadata -1 -threads {4} {5} {6} -sc_threshold 0 {7} -hls_time {8} -start_number {9} -hls_list_size 1440 \"{10}\"",
+            var args = string.Format("{0} {1} -i {2}{3} -map_metadata -1 -threads {4} {5} {6} -sc_threshold 0 {7} -hls_time {8} -start_number {9} -hls_list_size {10} \"{11}\"",
                 itsOffset,
                 itsOffset,
                 inputModifier,
                 inputModifier,
                 GetInputArgument(state),
                 GetInputArgument(state),
@@ -296,6 +296,7 @@ namespace MediaBrowser.Api.Playback.Hls
                 GetAudioArguments(state),
                 GetAudioArguments(state),
                 state.SegmentLength.ToString(UsCulture),
                 state.SegmentLength.ToString(UsCulture),
                 startNumberParam,
                 startNumberParam,
+                state.HlsListSize.ToString(UsCulture),
                 outputPath
                 outputPath
                 ).Trim();
                 ).Trim();
 
 
@@ -307,11 +308,12 @@ namespace MediaBrowser.Api.Playback.Hls
 
 
                     var bitrate = hlsVideoRequest.BaselineStreamAudioBitRate ?? 64000;
                     var bitrate = hlsVideoRequest.BaselineStreamAudioBitRate ?? 64000;
 
 
-                    var lowBitrateParams = string.Format(" -threads {0} -vn -codec:a:0 libmp3lame -ac 2 -ab {1} -hls_time {2} -start_number {3} -hls_list_size 1440 \"{4}\"",
+                    var lowBitrateParams = string.Format(" -threads {0} -vn -codec:a:0 libmp3lame -ac 2 -ab {1} -hls_time {2} -start_number {3} -hls_list_size {4} \"{5}\"",
                         threads,
                         threads,
                         bitrate / 2,
                         bitrate / 2,
                         state.SegmentLength.ToString(UsCulture),
                         state.SegmentLength.ToString(UsCulture),
                         startNumberParam,
                         startNumberParam,
+                        state.HlsListSize.ToString(UsCulture),
                         lowBitratePath);
                         lowBitratePath);
 
 
                     args += " " + lowBitrateParams;
                     args += " " + lowBitrateParams;

+ 3 - 1
MediaBrowser.Api/Playback/Hls/VideoHlsService.cs

@@ -163,7 +163,9 @@ namespace MediaBrowser.Api.Playback.Hls
                 return IsH264(state.VideoStream) ? "-codec:v:0 copy -bsf h264_mp4toannexb" : "-codec:v:0 copy";
                 return IsH264(state.VideoStream) ? "-codec:v:0 copy -bsf h264_mp4toannexb" : "-codec:v:0 copy";
             }
             }
 
 
-            const string keyFrameArg = " -force_key_frames expr:if(isnan(prev_forced_t),gte(t,.1),gte(t,prev_forced_t+5))";
+            var keyFrameArg = state.ReadInputAtNativeFramerate ?
+                " -force_key_frames expr:if(isnan(prev_forced_t),gte(t,.1),gte(t,prev_forced_t+1))" : 
+                " -force_key_frames expr:if(isnan(prev_forced_t),gte(t,.1),gte(t,prev_forced_t+5))";
 
 
             var hasGraphicalSubs = state.SubtitleStream != null && !state.SubtitleStream.IsExternal &&
             var hasGraphicalSubs = state.SubtitleStream != null && !state.SubtitleStream.IsExternal &&
                                  (state.SubtitleStream.Codec.IndexOf("pgs", StringComparison.OrdinalIgnoreCase) != -1 ||
                                  (state.SubtitleStream.Codec.IndexOf("pgs", StringComparison.OrdinalIgnoreCase) != -1 ||

+ 1 - 0
MediaBrowser.Api/Playback/StreamState.cs

@@ -56,6 +56,7 @@ namespace MediaBrowser.Api.Playback
         public string LiveTvStreamId { get; set; }
         public string LiveTvStreamId { get; set; }
 
 
         public int SegmentLength = 10;
         public int SegmentLength = 10;
+        public int HlsListSize;
 
 
         public long? RunTimeTicks;
         public long? RunTimeTicks;
 
 

+ 56 - 1
MediaBrowser.Api/UserLibrary/ItemsService.cs

@@ -220,6 +220,18 @@ namespace MediaBrowser.Api.UserLibrary
 
 
         [ApiMember(Name = "IsInBoxSet", Description = "Optional filter by items that are in boxsets, or not.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
         [ApiMember(Name = "IsInBoxSet", Description = "Optional filter by items that are in boxsets, or not.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
         public bool? IsInBoxSet { get; set; }
         public bool? IsInBoxSet { get; set; }
+
+        [ApiMember(Name = "IsLocked", Description = "Optional filter by items that are locked.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
+        public bool? IsLocked { get; set; }
+
+        [ApiMember(Name = "IsUnidentified", Description = "Optional filter by items that are unidentified by internet metadata providers.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
+        public bool? IsUnidentified { get; set; }
+
+        [ApiMember(Name = "IsPlaceHolder", Description = "Optional filter by items that are placeholders", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
+        public bool? IsPlaceHolder { get; set; }
+
+        [ApiMember(Name = "HasOfficialRating", Description = "Optional filter by items that have official ratings", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
+        public bool? HasOfficialRating { get; set; }
     }
     }
 
 
     /// <summary>
     /// <summary>
@@ -332,7 +344,7 @@ namespace MediaBrowser.Api.UserLibrary
             var userId = user == null ? (Guid?)null : user.Id;
             var userId = user == null ? (Guid?)null : user.Id;
 
 
             var item = string.IsNullOrEmpty(request.ParentId) ?
             var item = string.IsNullOrEmpty(request.ParentId) ?
-                user == null ? (BaseItem)_libraryManager.RootFolder : user.RootFolder :
+                user == null ? _libraryManager.RootFolder : user.RootFolder :
                 _dtoService.GetItemByDtoId(request.ParentId, userId);
                 _dtoService.GetItemByDtoId(request.ParentId, userId);
 
 
             // Default list type = children
             // Default list type = children
@@ -1019,6 +1031,18 @@ namespace MediaBrowser.Api.UserLibrary
                 items = items.Where(i => i.IsPlayed(user) == val);
                 items = items.Where(i => i.IsPlayed(user) == val);
             }
             }
 
 
+            if (request.IsUnidentified.HasValue)
+            {
+                var val = request.IsUnidentified.Value;
+                items = items.Where(i => i.IsUnidentified == val);
+            }
+
+            if (request.IsLocked.HasValue)
+            {
+                var val = request.IsLocked.Value;
+                items = items.Where(i => i.IsLocked == val);
+            }
+
             if (request.ParentIndexNumber.HasValue)
             if (request.ParentIndexNumber.HasValue)
             {
             {
                 var filterValue = request.ParentIndexNumber.Value;
                 var filterValue = request.ParentIndexNumber.Value;
@@ -1117,6 +1141,37 @@ namespace MediaBrowser.Api.UserLibrary
                 items = items.Where(i => IsYearMismatched(i) == filterValue);
                 items = items.Where(i => IsYearMismatched(i) == filterValue);
             }
             }
 
 
+            if (request.HasOfficialRating.HasValue)
+            {
+                var filterValue = request.HasOfficialRating.Value;
+
+                items = items.Where(i =>
+                {
+                    var hasValue = !string.IsNullOrEmpty(i.OfficialRating);
+
+                    return hasValue == filterValue;
+                });
+            }
+
+            if (request.IsPlaceHolder.HasValue)
+            {
+                var filterValue = request.IsPlaceHolder.Value;
+
+                items = items.Where(i =>
+                {
+                    var isPlaceHolder = false;
+
+                    var hasPlaceHolder = i as ISupportsPlaceHolders;
+
+                    if (hasPlaceHolder != null)
+                    {
+                        isPlaceHolder = hasPlaceHolder.IsPlaceHolder;
+                    }
+
+                    return isPlaceHolder == filterValue;
+                });
+            }
+
             return items;
             return items;
         }
         }
 
 

+ 4 - 4
MediaBrowser.Common.Implementations/MediaBrowser.Common.Implementations.csproj

@@ -48,13 +48,13 @@
     <RunPostBuildEvent>Always</RunPostBuildEvent>
     <RunPostBuildEvent>Always</RunPostBuildEvent>
   </PropertyGroup>
   </PropertyGroup>
   <ItemGroup>
   <ItemGroup>
-    <Reference Include="SimpleInjector, Version=2.4.1.0, Culture=neutral, PublicKeyToken=984cb50dea722e99, processorArchitecture=MSIL">
+    <Reference Include="SimpleInjector, Version=2.5.0.0, Culture=neutral, PublicKeyToken=984cb50dea722e99, processorArchitecture=MSIL">
       <SpecificVersion>False</SpecificVersion>
       <SpecificVersion>False</SpecificVersion>
-      <HintPath>..\packages\SimpleInjector.2.4.1\lib\net45\SimpleInjector.dll</HintPath>
+      <HintPath>..\packages\SimpleInjector.2.5.0\lib\net45\SimpleInjector.dll</HintPath>
     </Reference>
     </Reference>
-    <Reference Include="SimpleInjector.Diagnostics, Version=2.4.1.0, Culture=neutral, PublicKeyToken=984cb50dea722e99, processorArchitecture=MSIL">
+    <Reference Include="SimpleInjector.Diagnostics, Version=2.5.0.0, Culture=neutral, PublicKeyToken=984cb50dea722e99, processorArchitecture=MSIL">
       <SpecificVersion>False</SpecificVersion>
       <SpecificVersion>False</SpecificVersion>
-      <HintPath>..\packages\SimpleInjector.2.4.1\lib\net45\SimpleInjector.Diagnostics.dll</HintPath>
+      <HintPath>..\packages\SimpleInjector.2.5.0\lib\net45\SimpleInjector.Diagnostics.dll</HintPath>
     </Reference>
     </Reference>
     <Reference Include="System" />
     <Reference Include="System" />
     <Reference Include="System.Configuration" />
     <Reference Include="System.Configuration" />

+ 1 - 1
MediaBrowser.Common.Implementations/packages.config

@@ -2,5 +2,5 @@
 <packages>
 <packages>
   <package id="NLog" version="2.1.0" targetFramework="net45" />
   <package id="NLog" version="2.1.0" targetFramework="net45" />
   <package id="sharpcompress" version="0.10.2" targetFramework="net45" />
   <package id="sharpcompress" version="0.10.2" targetFramework="net45" />
-  <package id="SimpleInjector" version="2.4.1" targetFramework="net45" />
+  <package id="SimpleInjector" version="2.5.0" targetFramework="net45" />
 </packages>
 </packages>

+ 2 - 0
MediaBrowser.Controller/Entities/BaseItem.cs

@@ -229,6 +229,8 @@ namespace MediaBrowser.Controller.Entities
             }
             }
         }
         }
 
 
+        public bool IsUnidentified { get; set; }
+
         /// <summary>
         /// <summary>
         /// Gets or sets the locked fields.
         /// Gets or sets the locked fields.
         /// </summary>
         /// </summary>

+ 2 - 2
MediaBrowser.Controller/Entities/CollectionFolder.cs

@@ -149,7 +149,7 @@ namespace MediaBrowser.Controller.Entities
 
 
             try
             try
             {
             {
-                locationsDicionary = PhysicalLocations.Distinct().ToDictionary(i => i, StringComparer.OrdinalIgnoreCase);
+                locationsDicionary = PhysicalLocations.Distinct(StringComparer.OrdinalIgnoreCase).ToDictionary(i => i, StringComparer.OrdinalIgnoreCase);
             }
             }
             catch (IOException ex)
             catch (IOException ex)
             {
             {
@@ -181,7 +181,7 @@ namespace MediaBrowser.Controller.Entities
 
 
             try
             try
             {
             {
-                locationsDicionary = PhysicalLocations.Distinct().ToDictionary(i => i, StringComparer.OrdinalIgnoreCase);
+                locationsDicionary = PhysicalLocations.Distinct(StringComparer.OrdinalIgnoreCase).ToDictionary(i => i, StringComparer.OrdinalIgnoreCase);
             }
             }
             catch (IOException ex)
             catch (IOException ex)
             {
             {

+ 21 - 1
MediaBrowser.Controller/Entities/Folder.cs

@@ -352,6 +352,26 @@ namespace MediaBrowser.Controller.Entities
             return dictionary;
             return dictionary;
         }
         }
 
 
+        private bool IsValidFromResolver(BaseItem current, BaseItem newItem)
+        {
+            var currentAsPlaceHolder = current as ISupportsPlaceHolders;
+
+            if (currentAsPlaceHolder != null)
+            {
+                var newHasPlaceHolder = newItem as ISupportsPlaceHolders;
+
+                if (newHasPlaceHolder != null)
+                {
+                    if (currentAsPlaceHolder.IsPlaceHolder != newHasPlaceHolder.IsPlaceHolder)
+                    {
+                        return false;
+                    }
+                }
+            }
+
+            return current.IsInMixedFolder == newItem.IsInMixedFolder;
+        }
+
         /// <summary>
         /// <summary>
         /// Validates the children internal.
         /// Validates the children internal.
         /// </summary>
         /// </summary>
@@ -401,7 +421,7 @@ namespace MediaBrowser.Controller.Entities
                 {
                 {
                     BaseItem currentChild;
                     BaseItem currentChild;
 
 
-                    if (currentChildren.TryGetValue(child.Id, out currentChild) && child.IsInMixedFolder == currentChild.IsInMixedFolder)
+                    if (currentChildren.TryGetValue(child.Id, out currentChild) && IsValidFromResolver(currentChild, child))
                     {
                     {
                         var currentChildLocationType = currentChild.LocationType;
                         var currentChildLocationType = currentChild.LocationType;
                         if (currentChildLocationType != LocationType.Remote &&
                         if (currentChildLocationType != LocationType.Remote &&

+ 4 - 4
MediaBrowser.Controller/Entities/Game.cs

@@ -7,7 +7,7 @@ using System.Linq;
 
 
 namespace MediaBrowser.Controller.Entities
 namespace MediaBrowser.Controller.Entities
 {
 {
-    public class Game : BaseItem, IHasSoundtracks, IHasTrailers, IHasThemeMedia, IHasTags, IHasScreenshots, IHasPreferredMetadataLanguage, IHasLookupInfo<GameInfo>
+    public class Game : BaseItem, IHasSoundtracks, IHasTrailers, IHasThemeMedia, IHasTags, IHasScreenshots, ISupportsPlaceHolders, IHasPreferredMetadataLanguage, IHasLookupInfo<GameInfo>
     {
     {
         public List<Guid> SoundtrackIds { get; set; }
         public List<Guid> SoundtrackIds { get; set; }
 
 
@@ -63,10 +63,10 @@ namespace MediaBrowser.Controller.Entities
         public int? PlayersSupported { get; set; }
         public int? PlayersSupported { get; set; }
 
 
         /// <summary>
         /// <summary>
-        /// Gets or sets a value indicating whether this instance is installed on client.
+        /// Gets a value indicating whether this instance is place holder.
         /// </summary>
         /// </summary>
-        /// <value><c>true</c> if this instance is installed on client; otherwise, <c>false</c>.</value>
-        public bool IsInstalledOnClient { get; set; }
+        /// <value><c>true</c> if this instance is place holder; otherwise, <c>false</c>.</value>
+        public bool IsPlaceHolder { get; set; }
 
 
         /// <summary>
         /// <summary>
         /// Gets or sets the game system.
         /// Gets or sets the game system.

+ 6 - 6
MediaBrowser.Controller/Entities/IHasMetadata.cs

@@ -36,12 +36,6 @@ namespace MediaBrowser.Controller.Entities
         /// <value>The date last saved.</value>
         /// <value>The date last saved.</value>
         DateTime DateLastSaved { get; set; }
         DateTime DateLastSaved { get; set; }
 
 
-        /// <summary>
-        /// Gets a value indicating whether this instance is in mixed folder.
-        /// </summary>
-        /// <value><c>true</c> if this instance is in mixed folder; otherwise, <c>false</c>.</value>
-        bool IsInMixedFolder { get; }
-
         /// <summary>
         /// <summary>
         /// Updates to repository.
         /// Updates to repository.
         /// </summary>
         /// </summary>
@@ -55,5 +49,11 @@ namespace MediaBrowser.Controller.Entities
         /// </summary>
         /// </summary>
         /// <returns><c>true</c> if XXXX, <c>false</c> otherwise.</returns>
         /// <returns><c>true</c> if XXXX, <c>false</c> otherwise.</returns>
         bool BeforeMetadataRefresh();
         bool BeforeMetadataRefresh();
+
+        /// <summary>
+        /// Gets or sets a value indicating whether this instance is unidentified.
+        /// </summary>
+        /// <value><c>true</c> if this instance is unidentified; otherwise, <c>false</c>.</value>
+        bool IsUnidentified { get; set; }
     }
     }
 }
 }

+ 12 - 0
MediaBrowser.Controller/Entities/ISupportsPlaceHolders.cs

@@ -0,0 +1,12 @@
+
+namespace MediaBrowser.Controller.Entities
+{
+    public interface ISupportsPlaceHolders
+    {
+        /// <summary>
+        /// Gets a value indicating whether this instance is place holder.
+        /// </summary>
+        /// <value><c>true</c> if this instance is place holder; otherwise, <c>false</c>.</value>
+        bool IsPlaceHolder { get; }
+    }
+}

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

@@ -185,7 +185,7 @@ namespace MediaBrowser.Controller.Entities.TV
         {
         {
             get
             get
             {
             {
-                return LocationType == LocationType.Virtual && PremiereDate.HasValue && PremiereDate.Value < DateTime.UtcNow;
+                return LocationType == LocationType.Virtual && !IsUnaired;
             }
             }
         }
         }
 
 

+ 10 - 8
MediaBrowser.Controller/Entities/Video.cs

@@ -16,7 +16,7 @@ namespace MediaBrowser.Controller.Entities
     /// <summary>
     /// <summary>
     /// Class Video
     /// Class Video
     /// </summary>
     /// </summary>
-    public class Video : BaseItem, IHasMediaStreams, IHasAspectRatio, IHasTags
+    public class Video : BaseItem, IHasMediaStreams, IHasAspectRatio, IHasTags, ISupportsPlaceHolders
     {
     {
         public bool IsMultiPart { get; set; }
         public bool IsMultiPart { get; set; }
 
 
@@ -42,6 +42,8 @@ namespace MediaBrowser.Controller.Entities
         /// <value><c>true</c> if this instance has subtitles; otherwise, <c>false</c>.</value>
         /// <value><c>true</c> if this instance has subtitles; otherwise, <c>false</c>.</value>
         public bool HasSubtitles { get; set; }
         public bool HasSubtitles { get; set; }
 
 
+        public bool IsPlaceHolder { get; set; }
+        
         /// <summary>
         /// <summary>
         /// Gets or sets the tags.
         /// Gets or sets the tags.
         /// </summary>
         /// </summary>
@@ -108,10 +110,13 @@ namespace MediaBrowser.Controller.Entities
                     return System.IO.Path.GetDirectoryName(Path);
                     return System.IO.Path.GetDirectoryName(Path);
                 }
                 }
 
 
-                if (VideoType == VideoType.BluRay || VideoType == VideoType.Dvd ||
-                    VideoType == VideoType.HdDvd)
+                if (!IsPlaceHolder)
                 {
                 {
-                    return Path;
+                    if (VideoType == VideoType.BluRay || VideoType == VideoType.Dvd ||
+                        VideoType == VideoType.HdDvd)
+                    {
+                        return Path;
+                    }
                 }
                 }
 
 
                 return base.ContainingFolderPath;
                 return base.ContainingFolderPath;
@@ -257,10 +262,7 @@ namespace MediaBrowser.Controller.Entities
         {
         {
             if (!IsInMixedFolder)
             if (!IsInMixedFolder)
             {
             {
-                if (VideoType == VideoType.VideoFile || VideoType == VideoType.Iso)
-                {
-                    return new[] { System.IO.Path.GetDirectoryName(Path) };
-                }
+                return new[] { ContainingFolderPath };
             }
             }
 
 
             return base.GetDeletePaths();
             return base.GetDeletePaths();

+ 5 - 2
MediaBrowser.Controller/Library/TVUtils.cs

@@ -234,9 +234,12 @@ namespace MediaBrowser.Controller.Library
                 {
                 {
                     var fullName = child.FullName;
                     var fullName = child.FullName;
 
 
-                    if (EntityResolutionHelper.IsVideoFile(fullName) && GetEpisodeNumberFromFile(fullName, false).HasValue)
+                    if (EntityResolutionHelper.IsVideoFile(fullName) || EntityResolutionHelper.IsVideoPlaceHolder(fullName))
                     {
                     {
-                        return true;
+                        if (GetEpisodeNumberFromFile(fullName, false).HasValue)
+                        {
+                            return true;
+                        }
                     }
                     }
                 }
                 }
             }
             }

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

@@ -105,6 +105,7 @@
     <Compile Include="Entities\ILibraryItem.cs" />
     <Compile Include="Entities\ILibraryItem.cs" />
     <Compile Include="Entities\ImageSourceInfo.cs" />
     <Compile Include="Entities\ImageSourceInfo.cs" />
     <Compile Include="Entities\IMetadataContainer.cs" />
     <Compile Include="Entities\IMetadataContainer.cs" />
+    <Compile Include="Entities\ISupportsPlaceHolders.cs" />
     <Compile Include="Entities\ItemImageInfo.cs" />
     <Compile Include="Entities\ItemImageInfo.cs" />
     <Compile Include="Entities\LinkedChild.cs" />
     <Compile Include="Entities\LinkedChild.cs" />
     <Compile Include="Entities\MusicVideo.cs" />
     <Compile Include="Entities\MusicVideo.cs" />

+ 10 - 7
MediaBrowser.Controller/MediaEncoding/MediaEncoderHelpers.cs

@@ -34,6 +34,7 @@ namespace MediaBrowser.Controller.MediaEncoding
             {
             {
                 case VideoType.BluRay:
                 case VideoType.BluRay:
                     type = InputType.Bluray;
                     type = InputType.Bluray;
+                    inputPath = GetPlayableStreamFiles(inputPath[0], playableStreamFileNames).ToArray();
                     break;
                     break;
                 case VideoType.Dvd:
                 case VideoType.Dvd:
                     type = InputType.Dvd;
                     type = InputType.Dvd;
@@ -46,6 +47,7 @@ namespace MediaBrowser.Controller.MediaEncoding
                         {
                         {
                             case IsoType.BluRay:
                             case IsoType.BluRay:
                                 type = InputType.Bluray;
                                 type = InputType.Bluray;
+                                inputPath = GetPlayableStreamFiles(inputPath[0], playableStreamFileNames).ToArray();
                                 break;
                                 break;
                             case IsoType.Dvd:
                             case IsoType.Dvd:
                                 type = InputType.Dvd;
                                 type = InputType.Dvd;
@@ -118,15 +120,16 @@ namespace MediaBrowser.Controller.MediaEncoding
             return type;
             return type;
         }
         }
 
 
-        public static Model.Entities.MediaInfo GetMediaInfo(InternalMediaInfoResult data)
+        public static MediaInfo GetMediaInfo(InternalMediaInfoResult data)
         {
         {
             var internalStreams = data.streams ?? new MediaStreamInfo[] { };
             var internalStreams = data.streams ?? new MediaStreamInfo[] { };
 
 
-            var info = new Model.Entities.MediaInfo();
-
-            info.MediaStreams = internalStreams.Select(s => GetMediaStream(s, data.format))
-                .Where(i => i != null)
-                .ToList();
+            var info = new MediaInfo
+            {
+                MediaStreams = internalStreams.Select(s => GetMediaStream(s, data.format))
+                    .Where(i => i != null)
+                    .ToList()
+            };
 
 
             if (data.format != null)
             if (data.format != null)
             {
             {
@@ -137,7 +140,7 @@ namespace MediaBrowser.Controller.MediaEncoding
         }
         }
 
 
         private static readonly CultureInfo UsCulture = new CultureInfo("en-US");
         private static readonly CultureInfo UsCulture = new CultureInfo("en-US");
-        
+
         /// <summary>
         /// <summary>
         /// Converts ffprobe stream info to our MediaStream class
         /// Converts ffprobe stream info to our MediaStream class
         /// </summary>
         /// </summary>

+ 0 - 1
MediaBrowser.Controller/Providers/BaseItemXmlParser.cs

@@ -779,7 +779,6 @@ namespace MediaBrowser.Controller.Providers
                     break;
                     break;
 
 
                 case "TMDbCollectionId":
                 case "TMDbCollectionId":
-                case "CollectionNumber":
                     var tmdbCollection = reader.ReadElementContentAsString();
                     var tmdbCollection = reader.ReadElementContentAsString();
                     if (!string.IsNullOrWhiteSpace(tmdbCollection))
                     if (!string.IsNullOrWhiteSpace(tmdbCollection))
                     {
                     {

+ 5 - 0
MediaBrowser.Controller/Providers/ICustomMetadataProvider.cs

@@ -14,4 +14,9 @@ namespace MediaBrowser.Controller.Providers
     {
     {
         Task<ItemUpdateType> FetchAsync(TItemType item, IDirectoryService directoryService, CancellationToken cancellationToken);
         Task<ItemUpdateType> FetchAsync(TItemType item, IDirectoryService directoryService, CancellationToken cancellationToken);
     }
     }
+
+    public interface IPreRefreshProvider : ICustomMetadataProvider
+    {
+        
+    }
 }
 }

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

@@ -1,4 +1,5 @@
-using MediaBrowser.Controller.Entities;
+using MediaBrowser.Common.Net;
+using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Model.Configuration;
 using MediaBrowser.Model.Configuration;
 using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.Entities;
@@ -126,5 +127,14 @@ namespace MediaBrowser.Controller.Providers
             CancellationToken cancellationToken)
             CancellationToken cancellationToken)
             where TItemType : BaseItem, new()
             where TItemType : BaseItem, new()
             where TLookupType : ItemLookupInfo;
             where TLookupType : ItemLookupInfo;
+
+        /// <summary>
+        /// Gets the search image.
+        /// </summary>
+        /// <param name="providerName">Name of the provider.</param>
+        /// <param name="url">The URL.</param>
+        /// <param name="cancellationToken">The cancellation token.</param>
+        /// <returns>Task{HttpResponseInfo}.</returns>
+        Task<HttpResponseInfo> GetSearchImage(string providerName, string url, CancellationToken cancellationToken);
     }
     }
 }
 }

+ 7 - 4
MediaBrowser.Controller/Providers/IRemoteMetadataProvider.cs

@@ -18,11 +18,8 @@ namespace MediaBrowser.Controller.Providers
         Task<MetadataResult<TItemType>> GetMetadata(TLookupInfoType info, CancellationToken cancellationToken);
         Task<MetadataResult<TItemType>> GetMetadata(TLookupInfoType info, CancellationToken cancellationToken);
     }
     }
 
 
-    public interface IRemoteSearchProvider<in TLookupInfoType> : IMetadataProvider
-        where TLookupInfoType : ItemLookupInfo
+    public interface IRemoteSearchProvider : IMetadataProvider
     {
     {
-        Task<IEnumerable<RemoteSearchResult>> GetSearchResults(TLookupInfoType searchInfo, CancellationToken cancellationToken);
-
         /// <summary>
         /// <summary>
         /// Gets the image response.
         /// Gets the image response.
         /// </summary>
         /// </summary>
@@ -31,6 +28,12 @@ namespace MediaBrowser.Controller.Providers
         /// <returns>Task{HttpResponseInfo}.</returns>
         /// <returns>Task{HttpResponseInfo}.</returns>
         Task<HttpResponseInfo> GetImageResponse(string url, CancellationToken cancellationToken);
         Task<HttpResponseInfo> GetImageResponse(string url, CancellationToken cancellationToken);
     }
     }
+
+    public interface IRemoteSearchProvider<in TLookupInfoType> : IRemoteSearchProvider
+        where TLookupInfoType : ItemLookupInfo
+    {
+        Task<IEnumerable<RemoteSearchResult>> GetSearchResults(TLookupInfoType searchInfo, CancellationToken cancellationToken);
+    }
     
     
     public class RemoteSearchQuery<T>
     public class RemoteSearchQuery<T>
         where T : ItemLookupInfo
         where T : ItemLookupInfo

+ 28 - 3
MediaBrowser.Controller/Resolvers/BaseVideoResolver.cs

@@ -35,19 +35,44 @@ namespace MediaBrowser.Controller.Resolvers
             // If the path is a file check for a matching extensions
             // If the path is a file check for a matching extensions
             if (!args.IsDirectory)
             if (!args.IsDirectory)
             {
             {
-                if (EntityResolutionHelper.IsVideoFile(args.Path))
+                // http://wiki.xbmc.org/index.php?title=Media_stubs
+                var isPlaceHolder = EntityResolutionHelper.IsVideoPlaceHolder(args.Path);
+
+                if (EntityResolutionHelper.IsVideoFile(args.Path) || isPlaceHolder)
                 {
                 {
                     var extension = Path.GetExtension(args.Path);
                     var extension = Path.GetExtension(args.Path);
 
 
                     var type = string.Equals(extension, ".iso", StringComparison.OrdinalIgnoreCase) || string.Equals(extension, ".img", StringComparison.OrdinalIgnoreCase) ?
                     var type = string.Equals(extension, ".iso", StringComparison.OrdinalIgnoreCase) || string.Equals(extension, ".img", StringComparison.OrdinalIgnoreCase) ?
                         VideoType.Iso : VideoType.VideoFile;
                         VideoType.Iso : VideoType.VideoFile;
 
 
-                    return new TVideoType
+                    var video = new TVideoType
                     {
                     {
                         VideoType = type,
                         VideoType = type,
                         Path = args.Path,
                         Path = args.Path,
-                        IsInMixedFolder = true
+                        IsInMixedFolder = true,
+                        IsPlaceHolder = isPlaceHolder
                     };
                     };
+
+                    if (isPlaceHolder)
+                    {
+                        if (args.Path.EndsWith("dvd.disc", StringComparison.OrdinalIgnoreCase))
+                        {
+                            video.VideoType = VideoType.Dvd;
+                        }
+                        else if (args.Path.EndsWith("hddvd.disc", StringComparison.OrdinalIgnoreCase))
+                        {
+                            video.VideoType = VideoType.HdDvd;
+                        }
+                        else if (args.Path.EndsWith("bluray.disc", StringComparison.OrdinalIgnoreCase) ||
+                            args.Path.EndsWith("brrip.disc", StringComparison.OrdinalIgnoreCase) ||
+                            args.Path.EndsWith("bd25.disc", StringComparison.OrdinalIgnoreCase) ||
+                            args.Path.EndsWith("bd50.disc", StringComparison.OrdinalIgnoreCase))
+                        {
+                            video.VideoType = VideoType.BluRay;
+                        }
+                    }
+
+                    return video;
                 }
                 }
             }
             }
 
 

+ 18 - 0
MediaBrowser.Controller/Resolvers/EntityResolutionHelper.cs

@@ -139,6 +139,24 @@ namespace MediaBrowser.Controller.Resolvers
             return VideoFileExtensionsDictionary.ContainsKey(extension);
             return VideoFileExtensionsDictionary.ContainsKey(extension);
         }
         }
 
 
+        /// <summary>
+        /// Determines whether [is place holder] [the specified path].
+        /// </summary>
+        /// <param name="path">The path.</param>
+        /// <returns><c>true</c> if [is place holder] [the specified path]; otherwise, <c>false</c>.</returns>
+        /// <exception cref="System.ArgumentNullException">path</exception>
+        public static bool IsVideoPlaceHolder(string path)
+        {
+            if (string.IsNullOrEmpty(path))
+            {
+                throw new ArgumentNullException("path");
+            }
+
+            var extension = Path.GetExtension(path);
+
+            return string.Equals(extension, ".disc", StringComparison.OrdinalIgnoreCase);
+        }
+
         /// <summary>
         /// <summary>
         /// Ensures DateCreated and DateModified have values
         /// Ensures DateCreated and DateModified have values
         /// </summary>
         /// </summary>

+ 1 - 1
MediaBrowser.Dlna/PlayTo/PlayToServerEntryPoint.cs

@@ -20,7 +20,7 @@ namespace MediaBrowser.Dlna.PlayTo
 
 
         public void Run()
         public void Run()
         {
         {
-            _manager.Start();
+            //_manager.Start();
         }
         }
 
 
         #region Dispose
         #region Dispose

+ 3 - 0
MediaBrowser.Model/Configuration/ServerConfiguration.cs

@@ -209,6 +209,9 @@ namespace MediaBrowser.Model.Configuration
         public bool EnableRealtimeMonitor { get; set; }
         public bool EnableRealtimeMonitor { get; set; }
         public PathSubstitution[] PathSubstitutions { get; set; }
         public PathSubstitution[] PathSubstitutions { get; set; }
 
 
+        public string ServerName { get; set; }
+        public string WanDdns { get; set; }
+
         /// <summary>
         /// <summary>
         /// Initializes a new instance of the <see cref="ServerConfiguration" /> class.
         /// Initializes a new instance of the <see cref="ServerConfiguration" /> class.
         /// </summary>
         /// </summary>

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

@@ -48,6 +48,10 @@ namespace MediaBrowser.Model.Dto
         public string AwardSummary { get; set; }
         public string AwardSummary { get; set; }
 
 
         public float? Metascore { get; set; }
         public float? Metascore { get; set; }
+
+        public bool IsUnidentified { get; set; }
+
+        public int? AnimeSeriesIndex { get; set; }
         
         
         /// <summary>
         /// <summary>
         /// Gets or sets the DVD season number.
         /// Gets or sets the DVD season number.
@@ -204,6 +208,12 @@ namespace MediaBrowser.Model.Dto
         /// <value>The players.</value>
         /// <value>The players.</value>
         public int? Players { get; set; }
         public int? Players { get; set; }
 
 
+        /// <summary>
+        /// Gets or sets a value indicating whether this instance is place holder.
+        /// </summary>
+        /// <value><c>null</c> if [is place holder] contains no value, <c>true</c> if [is place holder]; otherwise, <c>false</c>.</value>
+        public bool? IsPlaceHolder { get; set; }
+        
         /// <summary>
         /// <summary>
         /// Gets or sets the index number.
         /// Gets or sets the index number.
         /// </summary>
         /// </summary>

+ 2 - 0
MediaBrowser.Model/Providers/RemoteSearchResult.cs

@@ -31,6 +31,8 @@ namespace MediaBrowser.Model.Providers
 
 
         public string SearchProviderName { get; set; }
         public string SearchProviderName { get; set; }
 
 
+        public string GameSystem { get; set; }
+        
         public RemoteSearchResult()
         public RemoteSearchResult()
         {
         {
             ProviderIds = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
             ProviderIds = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);

+ 6 - 0
MediaBrowser.Model/System/SystemInfo.cs

@@ -146,6 +146,12 @@ namespace MediaBrowser.Model.System
         /// <value><c>true</c> if [supports automatic run at startup]; otherwise, <c>false</c>.</value>
         /// <value><c>true</c> if [supports automatic run at startup]; otherwise, <c>false</c>.</value>
         public bool SupportsAutoRunAtStartup { get; set; }
         public bool SupportsAutoRunAtStartup { get; set; }
 
 
+        /// <summary>
+        /// Gets or sets the name of the server.
+        /// </summary>
+        /// <value>The name of the server.</value>
+        public string ServerName { get; set; }
+
         /// <summary>
         /// <summary>
         /// Initializes a new instance of the <see cref="SystemInfo" /> class.
         /// Initializes a new instance of the <see cref="SystemInfo" /> class.
         /// </summary>
         /// </summary>

+ 52 - 8
MediaBrowser.Providers/BoxSets/MovieDbBoxSetProvider.cs

@@ -22,7 +22,6 @@ namespace MediaBrowser.Providers.BoxSets
 {
 {
     public class MovieDbBoxSetProvider : IRemoteMetadataProvider<BoxSet, BoxSetInfo>
     public class MovieDbBoxSetProvider : IRemoteMetadataProvider<BoxSet, BoxSetInfo>
     {
     {
-        private readonly CultureInfo _enUs = new CultureInfo("en-US");
         private const string GetCollectionInfo3 = @"http://api.themoviedb.org/3/collection/{0}?api_key={1}&append_to_response=images";
         private const string GetCollectionInfo3 = @"http://api.themoviedb.org/3/collection/{0}?api_key={1}&append_to_response=images";
 
 
         internal static MovieDbBoxSetProvider Current;
         internal static MovieDbBoxSetProvider Current;
@@ -32,20 +31,53 @@ namespace MediaBrowser.Providers.BoxSets
         private readonly IServerConfigurationManager _config;
         private readonly IServerConfigurationManager _config;
         private readonly IFileSystem _fileSystem;
         private readonly IFileSystem _fileSystem;
         private readonly ILocalizationManager _localization;
         private readonly ILocalizationManager _localization;
+        private readonly IHttpClient _httpClient;
 
 
-        public MovieDbBoxSetProvider(ILogger logger, IJsonSerializer json, IServerConfigurationManager config, IFileSystem fileSystem, ILocalizationManager localization)
+        public MovieDbBoxSetProvider(ILogger logger, IJsonSerializer json, IServerConfigurationManager config, IFileSystem fileSystem, ILocalizationManager localization, IHttpClient httpClient)
         {
         {
             _logger = logger;
             _logger = logger;
             _json = json;
             _json = json;
             _config = config;
             _config = config;
             _fileSystem = fileSystem;
             _fileSystem = fileSystem;
             _localization = localization;
             _localization = localization;
+            _httpClient = httpClient;
             Current = this;
             Current = this;
         }
         }
 
 
+        private readonly CultureInfo _usCulture = new CultureInfo("en-US");
+        
         public async Task<IEnumerable<RemoteSearchResult>> GetSearchResults(BoxSetInfo searchInfo, CancellationToken cancellationToken)
         public async Task<IEnumerable<RemoteSearchResult>> GetSearchResults(BoxSetInfo searchInfo, CancellationToken cancellationToken)
         {
         {
-            return new List<RemoteSearchResult>();
+            var tmdbId = searchInfo.GetProviderId(MetadataProviders.Tmdb);
+
+            var tmdbSettings = await MovieDbProvider.Current.GetTmdbSettings(cancellationToken).ConfigureAwait(false);
+
+            var tmdbImageUrl = tmdbSettings.images.base_url + "original";
+
+            if (!string.IsNullOrEmpty(tmdbId))
+            {
+                await EnsureInfo(tmdbId, searchInfo.MetadataLanguage, cancellationToken).ConfigureAwait(false);
+
+                var dataFilePath = GetDataFilePath(_config.ApplicationPaths, tmdbId, searchInfo.MetadataLanguage);
+                var info = _json.DeserializeFromFile<RootObject>(dataFilePath);
+
+                var images = (info.images ?? new Images()).posters ?? new List<Poster>();
+               
+                var result = new RemoteSearchResult
+                {
+                    Name = info.name,
+
+                    SearchProviderName = Name,
+                    
+                    ImageUrl = images.Count == 0 ? null : (tmdbImageUrl + images[0].file_path)
+                };
+
+                result.SetProviderId(MetadataProviders.Tmdb, info.id.ToString(_usCulture));
+
+                return new[] { result };
+            }
+
+            return await new MovieDbSearch(_logger, _json).GetSearchResults(searchInfo, cancellationToken).ConfigureAwait(false);
         }
         }
 
 
         public async Task<MetadataResult<BoxSet>> GetMetadata(BoxSetInfo id, CancellationToken cancellationToken)
         public async Task<MetadataResult<BoxSet>> GetMetadata(BoxSetInfo id, CancellationToken cancellationToken)
@@ -55,11 +87,13 @@ namespace MediaBrowser.Providers.BoxSets
             // We don't already have an Id, need to fetch it
             // We don't already have an Id, need to fetch it
             if (string.IsNullOrEmpty(tmdbId))
             if (string.IsNullOrEmpty(tmdbId))
             {
             {
-                var searchResult = await new MovieDbSearch(_logger, _json).FindCollectionId(id, cancellationToken).ConfigureAwait(false);
+                var searchResults = await new MovieDbSearch(_logger, _json).GetSearchResults(id, cancellationToken).ConfigureAwait(false);
+
+                var searchResult = searchResults.FirstOrDefault();
 
 
                 if (searchResult != null)
                 if (searchResult != null)
                 {
                 {
-                    tmdbId = searchResult.id.ToString(_enUs);
+                    tmdbId = searchResult.GetProviderId(MetadataProviders.Tmdb);
                 }
                 }
             }
             }
 
 
@@ -106,7 +140,7 @@ namespace MediaBrowser.Providers.BoxSets
                 Overview = obj.overview
                 Overview = obj.overview
             };
             };
 
 
-            item.SetProviderId(MetadataProviders.Tmdb, obj.id.ToString(_enUs));
+            item.SetProviderId(MetadataProviders.Tmdb, obj.id.ToString(_usCulture));
 
 
             return item;
             return item;
         }
         }
@@ -219,10 +253,15 @@ namespace MediaBrowser.Providers.BoxSets
 
 
         private static string GetDataFilePath(IApplicationPaths appPaths, string tmdbId, string preferredLanguage)
         private static string GetDataFilePath(IApplicationPaths appPaths, string tmdbId, string preferredLanguage)
         {
         {
+            if (string.IsNullOrWhiteSpace(preferredLanguage))
+            {
+                throw new ArgumentNullException("preferredLanguage");
+            }
+
             var path = GetDataPath(appPaths, tmdbId);
             var path = GetDataPath(appPaths, tmdbId);
 
 
             var filename = string.Format("all-{0}.json",
             var filename = string.Format("all-{0}.json",
-                preferredLanguage ?? string.Empty);
+                preferredLanguage);
 
 
             return Path.Combine(path, filename);
             return Path.Combine(path, filename);
         }
         }
@@ -291,7 +330,12 @@ namespace MediaBrowser.Providers.BoxSets
 
 
         public Task<HttpResponseInfo> GetImageResponse(string url, CancellationToken cancellationToken)
         public Task<HttpResponseInfo> GetImageResponse(string url, CancellationToken cancellationToken)
         {
         {
-            throw new NotImplementedException();
+            return _httpClient.GetResponse(new HttpRequestOptions
+            {
+                CancellationToken = cancellationToken,
+                Url = url,
+                ResourcePool = MovieDbProvider.Current.MovieDbResourcePool
+            });
         }
         }
     }
     }
 }
 }

+ 6 - 7
MediaBrowser.Providers/Games/GameMetadataService.cs

@@ -1,25 +1,19 @@
 using MediaBrowser.Common.IO;
 using MediaBrowser.Common.IO;
 using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.Providers;
 using MediaBrowser.Controller.Providers;
 using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.Logging;
 using MediaBrowser.Model.Logging;
 using MediaBrowser.Providers.Manager;
 using MediaBrowser.Providers.Manager;
 using System.Collections.Generic;
 using System.Collections.Generic;
-using System.Threading;
-using System.Threading.Tasks;
 
 
 namespace MediaBrowser.Providers.Games
 namespace MediaBrowser.Providers.Games
 {
 {
     public class GameMetadataService : MetadataService<Game, GameInfo>
     public class GameMetadataService : MetadataService<Game, GameInfo>
     {
     {
-        private readonly ILibraryManager _libraryManager;
-
-        public GameMetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, IProviderRepository providerRepo, IFileSystem fileSystem, ILibraryManager libraryManager)
+        public GameMetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, IProviderRepository providerRepo, IFileSystem fileSystem)
             : base(serverConfigurationManager, logger, providerManager, providerRepo, fileSystem)
             : base(serverConfigurationManager, logger, providerManager, providerRepo, fileSystem)
         {
         {
-            _libraryManager = libraryManager;
         }
         }
 
 
         /// <summary>
         /// <summary>
@@ -38,6 +32,11 @@ namespace MediaBrowser.Providers.Games
             {
             {
                 target.GameSystem = source.GameSystem;
                 target.GameSystem = source.GameSystem;
             }
             }
+
+            if (replaceData || !target.PlayersSupported.HasValue)
+            {
+                target.PlayersSupported = source.PlayersSupported;
+            }
         }
         }
     }
     }
 }
 }

+ 23 - 1
MediaBrowser.Providers/Manager/MetadataService.cs

@@ -269,6 +269,13 @@ namespace MediaBrowser.Providers.Manager
                 Providers = providers.Select(i => i.GetType().FullName.GetMD5()).ToList()
                 Providers = providers.Select(i => i.GetType().FullName.GetMD5()).ToList()
             };
             };
 
 
+            var customProviders = providers.OfType<ICustomMetadataProvider<TItemType>>().ToList();
+
+            foreach (var provider in customProviders.Where(i => i is IPreRefreshProvider))
+            {
+                await RunCustomProvider(provider, item, options.DirectoryService, refreshResult, cancellationToken).ConfigureAwait(false);
+            }
+
             var temp = CreateNew();
             var temp = CreateNew();
             temp.Path = item.Path;
             temp.Path = item.Path;
 
 
@@ -342,7 +349,7 @@ namespace MediaBrowser.Providers.Manager
                 MergeData(temp, item, item.LockedFields, true, true);
                 MergeData(temp, item, item.LockedFields, true, true);
             }
             }
 
 
-            foreach (var provider in providers.OfType<ICustomMetadataProvider<TItemType>>())
+            foreach (var provider in customProviders.Where(i => !(i is IPreRefreshProvider)))
             {
             {
                 await RunCustomProvider(provider, item, options.DirectoryService, refreshResult, cancellationToken).ConfigureAwait(false);
                 await RunCustomProvider(provider, item, options.DirectoryService, refreshResult, cancellationToken).ConfigureAwait(false);
             }
             }
@@ -379,6 +386,9 @@ namespace MediaBrowser.Providers.Manager
         {
         {
             TIdType id = null;
             TIdType id = null;
 
 
+            var unidentifiedCount = 0;
+            var identifiedCount = 0;
+
             foreach (var provider in providers)
             foreach (var provider in providers)
             {
             {
                 var providerName = provider.GetType().Name;
                 var providerName = provider.GetType().Name;
@@ -402,9 +412,12 @@ namespace MediaBrowser.Providers.Manager
                         MergeData(result.Item, temp, new List<MetadataFields>(), false, false);
                         MergeData(result.Item, temp, new List<MetadataFields>(), false, false);
 
 
                         refreshResult.UpdateType = refreshResult.UpdateType | ItemUpdateType.MetadataDownload;
                         refreshResult.UpdateType = refreshResult.UpdateType | ItemUpdateType.MetadataDownload;
+
+                        identifiedCount++;
                     }
                     }
                     else
                     else
                     {
                     {
+                        unidentifiedCount++; 
                         Logger.Debug("{0} returned no metadata for {1}", providerName, item.Path ?? item.Name);
                         Logger.Debug("{0} returned no metadata for {1}", providerName, item.Path ?? item.Name);
                     }
                     }
                 }
                 }
@@ -414,11 +427,20 @@ namespace MediaBrowser.Providers.Manager
                 }
                 }
                 catch (Exception ex)
                 catch (Exception ex)
                 {
                 {
+                    unidentifiedCount++; 
                     refreshResult.Status = ProviderRefreshStatus.CompletedWithErrors;
                     refreshResult.Status = ProviderRefreshStatus.CompletedWithErrors;
                     refreshResult.ErrorMessage = ex.Message;
                     refreshResult.ErrorMessage = ex.Message;
                     Logger.ErrorException("Error in {0}", ex, provider.Name);
                     Logger.ErrorException("Error in {0}", ex, provider.Name);
                 }
                 }
             }
             }
+
+            var isUnidentified = unidentifiedCount > 0 && identifiedCount == 0;
+
+            if (item.IsUnidentified != isUnidentified)
+            {
+                item.IsUnidentified = isUnidentified;
+                refreshResult.UpdateType = refreshResult.UpdateType | ItemUpdateType.MetadataImport;
+            }
         }
         }
 
 
         private void MergeNewData(TItemType source, TIdType lookupInfo)
         private void MergeNewData(TItemType source, TIdType lookupInfo)

+ 40 - 3
MediaBrowser.Providers/Manager/ProviderManager.cs

@@ -492,7 +492,7 @@ namespace MediaBrowser.Providers.Manager
                     Type = MetadataPluginType.MetadataFetcher
                     Type = MetadataPluginType.MetadataFetcher
                 }));
                 }));
             }
             }
-            
+
             if (item.IsSaveLocalMetadataEnabled())
             if (item.IsSaveLocalMetadataEnabled())
             {
             {
                 // Savers
                 // Savers
@@ -657,15 +657,24 @@ namespace MediaBrowser.Providers.Manager
                 providers = providers.Where(i => string.Equals(i.Name, searchInfo.SearchProviderName, StringComparison.OrdinalIgnoreCase));
                 providers = providers.Where(i => string.Equals(i.Name, searchInfo.SearchProviderName, StringComparison.OrdinalIgnoreCase));
             }
             }
 
 
+            if (string.IsNullOrWhiteSpace(searchInfo.SearchInfo.MetadataLanguage))
+            {
+                searchInfo.SearchInfo.MetadataLanguage = ConfigurationManager.Configuration.PreferredMetadataLanguage;
+            }
+            if (string.IsNullOrWhiteSpace(searchInfo.SearchInfo.MetadataCountryCode))
+            {
+                searchInfo.SearchInfo.MetadataCountryCode = ConfigurationManager.Configuration.MetadataCountryCode;
+            }
+
             foreach (var provider in providers)
             foreach (var provider in providers)
             {
             {
-                var results = await provider.GetSearchResults(searchInfo.SearchInfo, cancellationToken).ConfigureAwait(false);
+                var results = await GetSearchResults(provider, searchInfo.SearchInfo, cancellationToken).ConfigureAwait(false);
 
 
                 var list = results.ToList();
                 var list = results.ToList();
 
 
                 if (list.Count > 0)
                 if (list.Count > 0)
                 {
                 {
-                    return list;
+                    return list.Take(10);
                 }
                 }
             }
             }
 
 
@@ -673,6 +682,34 @@ namespace MediaBrowser.Providers.Manager
             return new List<RemoteSearchResult>();
             return new List<RemoteSearchResult>();
         }
         }
 
 
+        private async Task<IEnumerable<RemoteSearchResult>> GetSearchResults<TLookupType>(IRemoteSearchProvider<TLookupType> provider, TLookupType searchInfo,
+            CancellationToken cancellationToken)
+            where TLookupType : ItemLookupInfo
+        {
+            var results = await provider.GetSearchResults(searchInfo, cancellationToken).ConfigureAwait(false);
+
+            var list = results.ToList();
+
+            foreach (var item in list)
+            {
+                item.SearchProviderName = provider.Name;
+            }
+
+            return list;
+        }
+
+        public Task<HttpResponseInfo> GetSearchImage(string providerName, string url, CancellationToken cancellationToken)
+        {
+            var provider = _metadataProviders.OfType<IRemoteSearchProvider>().FirstOrDefault(i => string.Equals(i.Name, providerName, StringComparison.OrdinalIgnoreCase));
+
+            if (provider == null)
+            {
+                throw new ArgumentException("Search provider not found.");
+            }
+
+            return provider.GetImageResponse(url, cancellationToken);
+        }
+
         public IEnumerable<IExternalId> GetExternalIds(IHasProviderIds item)
         public IEnumerable<IExternalId> GetExternalIds(IHasProviderIds item)
         {
         {
             return _externalIds.Where(i =>
             return _externalIds.Where(i =>

+ 5 - 0
MediaBrowser.Providers/Manager/ProviderUtils.cs

@@ -58,6 +58,11 @@ namespace MediaBrowser.Providers.Manager
                 target.OfficialRatingDescription = source.OfficialRatingDescription;
                 target.OfficialRatingDescription = source.OfficialRatingDescription;
             }
             }
 
 
+            if (replaceData || string.IsNullOrEmpty(target.CustomRating))
+            {
+                target.CustomRating = source.CustomRating;
+            }
+            
             if (!lockedFields.Contains(MetadataFields.Overview))
             if (!lockedFields.Contains(MetadataFields.Overview))
             {
             {
                 if (replaceData || string.IsNullOrEmpty(target.Overview))
                 if (replaceData || string.IsNullOrEmpty(target.Overview))

+ 6 - 1
MediaBrowser.Providers/MediaInfo/FFProbeProvider.cs

@@ -126,6 +126,11 @@ namespace MediaBrowser.Providers.MediaInfo
                 return _cachedTask;
                 return _cachedTask;
             }
             }
 
 
+            if (item.IsPlaceHolder)
+            {
+                return _cachedTask;
+            }
+
             var prober = new FFProbeVideoInfo(_logger, _isoManager, _mediaEncoder, _itemRepo, _blurayExaminer, _localization, _appPaths, _json, _encodingManager);
             var prober = new FFProbeVideoInfo(_logger, _isoManager, _mediaEncoder, _itemRepo, _blurayExaminer, _localization, _appPaths, _json, _encodingManager);
 
 
             return prober.ProbeVideo(item, directoryService, cancellationToken);
             return prober.ProbeVideo(item, directoryService, cancellationToken);
@@ -155,7 +160,7 @@ namespace MediaBrowser.Providers.MediaInfo
             {
             {
                 var video = item as Video;
                 var video = item as Video;
 
 
-                if (video != null)
+                if (video != null && !video.IsPlaceHolder)
                 {
                 {
                     var prober = new FFProbeVideoInfo(_logger, _isoManager, _mediaEncoder, _itemRepo, _blurayExaminer, _localization, _appPaths, _json, _encodingManager);
                     var prober = new FFProbeVideoInfo(_logger, _isoManager, _mediaEncoder, _itemRepo, _blurayExaminer, _localization, _appPaths, _json, _encodingManager);
 
 

+ 51 - 41
MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs

@@ -53,9 +53,18 @@ namespace MediaBrowser.Providers.MediaInfo
         {
         {
             var isoMount = await MountIsoIfNeeded(item, cancellationToken).ConfigureAwait(false);
             var isoMount = await MountIsoIfNeeded(item, cancellationToken).ConfigureAwait(false);
 
 
+            BlurayDiscInfo blurayDiscInfo = null;
+
             try
             try
             {
             {
-                OnPreFetch(item, isoMount);
+                if (item.VideoType == VideoType.BluRay || (item.IsoType.HasValue && item.IsoType == IsoType.BluRay))
+                {
+                    var inputPath = isoMount != null ? isoMount.MountedPath : item.Path;
+
+                    blurayDiscInfo = GetBDInfo(inputPath);
+                }
+
+                OnPreFetch(item, isoMount, blurayDiscInfo);
 
 
                 // If we didn't find any satisfying the min length, just take them all
                 // If we didn't find any satisfying the min length, just take them all
                 if (item.VideoType == VideoType.Dvd || (item.IsoType.HasValue && item.IsoType == IsoType.Dvd))
                 if (item.VideoType == VideoType.Dvd || (item.IsoType.HasValue && item.IsoType == IsoType.Dvd))
@@ -67,6 +76,15 @@ namespace MediaBrowser.Providers.MediaInfo
                     }
                     }
                 }
                 }
 
 
+                if (item.VideoType == VideoType.BluRay || (item.IsoType.HasValue && item.IsoType == IsoType.BluRay))
+                {
+                    if (item.PlayableStreamFileNames.Count == 0)
+                    {
+                        _logger.Error("No playable vobs found in bluray structure, skipping ffprobe.");
+                        return ItemUpdateType.MetadataImport;
+                    }
+                }
+
                 var result = await GetMediaInfo(item, isoMount, cancellationToken).ConfigureAwait(false);
                 var result = await GetMediaInfo(item, isoMount, cancellationToken).ConfigureAwait(false);
 
 
                 cancellationToken.ThrowIfCancellationRequested();
                 cancellationToken.ThrowIfCancellationRequested();
@@ -75,7 +93,7 @@ namespace MediaBrowser.Providers.MediaInfo
 
 
                 cancellationToken.ThrowIfCancellationRequested();
                 cancellationToken.ThrowIfCancellationRequested();
 
 
-                await Fetch(item, cancellationToken, result, isoMount, directoryService).ConfigureAwait(false);
+                await Fetch(item, cancellationToken, result, isoMount, blurayDiscInfo, directoryService).ConfigureAwait(false);
 
 
             }
             }
             finally
             finally
@@ -128,7 +146,7 @@ namespace MediaBrowser.Providers.MediaInfo
             return result;
             return result;
         }
         }
 
 
-        protected async Task Fetch(Video video, CancellationToken cancellationToken, InternalMediaInfoResult data, IIsoMount isoMount, IDirectoryService directoryService)
+        protected async Task Fetch(Video video, CancellationToken cancellationToken, InternalMediaInfoResult data, IIsoMount isoMount, BlurayDiscInfo blurayInfo, IDirectoryService directoryService)
         {
         {
             if (data.format != null)
             if (data.format != null)
             {
             {
@@ -147,8 +165,7 @@ namespace MediaBrowser.Providers.MediaInfo
 
 
             if (video.VideoType == VideoType.BluRay || (video.IsoType.HasValue && video.IsoType.Value == IsoType.BluRay))
             if (video.VideoType == VideoType.BluRay || (video.IsoType.HasValue && video.IsoType.Value == IsoType.BluRay))
             {
             {
-                var inputPath = isoMount != null ? isoMount.MountedPath : video.Path;
-                FetchBdInfo(video, chapters, mediaStreams, inputPath, cancellationToken);
+                FetchBdInfo(video, chapters, mediaStreams, blurayInfo);
             }
             }
 
 
             AddExternalSubtitles(video, mediaStreams, directoryService);
             AddExternalSubtitles(video, mediaStreams, directoryService);
@@ -183,14 +200,10 @@ namespace MediaBrowser.Providers.MediaInfo
             await _itemRepo.SaveChapters(video.Id, chapters, cancellationToken).ConfigureAwait(false);
             await _itemRepo.SaveChapters(video.Id, chapters, cancellationToken).ConfigureAwait(false);
         }
         }
 
 
-        private void FetchBdInfo(BaseItem item, List<ChapterInfo> chapters, List<MediaStream> mediaStreams, string inputPath, CancellationToken cancellationToken)
+        private void FetchBdInfo(BaseItem item, List<ChapterInfo> chapters, List<MediaStream> mediaStreams, BlurayDiscInfo blurayInfo)
         {
         {
             var video = (Video)item;
             var video = (Video)item;
 
 
-            var result = GetBDInfo(inputPath);
-
-            cancellationToken.ThrowIfCancellationRequested();
-
             int? currentHeight = null;
             int? currentHeight = null;
             int? currentWidth = null;
             int? currentWidth = null;
             int? currentBitRate = null;
             int? currentBitRate = null;
@@ -206,51 +219,43 @@ namespace MediaBrowser.Providers.MediaInfo
             }
             }
 
 
             // Fill video properties from the BDInfo result
             // Fill video properties from the BDInfo result
-            Fetch(video, mediaStreams, result, chapters);
-
-            videoStream = mediaStreams.FirstOrDefault(s => s.Type == MediaStreamType.Video);
-
-            // Use the ffprobe values if these are empty
-            if (videoStream != null)
-            {
-                videoStream.BitRate = IsEmpty(videoStream.BitRate) ? currentBitRate : videoStream.BitRate;
-                videoStream.Width = IsEmpty(videoStream.Width) ? currentWidth : videoStream.Width;
-                videoStream.Height = IsEmpty(videoStream.Height) ? currentHeight : videoStream.Height;
-            }
-        }
-
-        private bool IsEmpty(int? num)
-        {
-            return !num.HasValue || num.Value == 0;
-        }
-
-        /// <param name="chapters">The chapters.</param>
-        private void Fetch(Video video, List<MediaStream> mediaStreams, BlurayDiscInfo stream, List<ChapterInfo> chapters)
-        {
-            // Check all input for null/empty/zero
-
             mediaStreams.Clear();
             mediaStreams.Clear();
-            mediaStreams.AddRange(stream.MediaStreams);
+            mediaStreams.AddRange(blurayInfo.MediaStreams);
 
 
-            video.MainFeaturePlaylistName = stream.PlaylistName;
+            video.MainFeaturePlaylistName = blurayInfo.PlaylistName;
 
 
-            if (stream.RunTimeTicks.HasValue && stream.RunTimeTicks.Value > 0)
+            if (blurayInfo.RunTimeTicks.HasValue && blurayInfo.RunTimeTicks.Value > 0)
             {
             {
-                video.RunTimeTicks = stream.RunTimeTicks;
+                video.RunTimeTicks = blurayInfo.RunTimeTicks;
             }
             }
 
 
-            video.PlayableStreamFileNames = stream.Files.ToList();
+            video.PlayableStreamFileNames = blurayInfo.Files.ToList();
 
 
-            if (stream.Chapters != null)
+            if (blurayInfo.Chapters != null)
             {
             {
                 chapters.Clear();
                 chapters.Clear();
 
 
-                chapters.AddRange(stream.Chapters.Select(c => new ChapterInfo
+                chapters.AddRange(blurayInfo.Chapters.Select(c => new ChapterInfo
                 {
                 {
                     StartPositionTicks = TimeSpan.FromSeconds(c).Ticks
                     StartPositionTicks = TimeSpan.FromSeconds(c).Ticks
 
 
                 }));
                 }));
             }
             }
+
+            videoStream = mediaStreams.FirstOrDefault(s => s.Type == MediaStreamType.Video);
+
+            // Use the ffprobe values if these are empty
+            if (videoStream != null)
+            {
+                videoStream.BitRate = IsEmpty(videoStream.BitRate) ? currentBitRate : videoStream.BitRate;
+                videoStream.Width = IsEmpty(videoStream.Width) ? currentWidth : videoStream.Width;
+                videoStream.Height = IsEmpty(videoStream.Height) ? currentHeight : videoStream.Height;
+            }
+        }
+
+        private bool IsEmpty(int? num)
+        {
+            return !num.HasValue || num.Value == 0;
         }
         }
 
 
         /// <summary>
         /// <summary>
@@ -498,7 +503,7 @@ namespace MediaBrowser.Providers.MediaInfo
         /// </summary>
         /// </summary>
         /// <param name="item">The item.</param>
         /// <param name="item">The item.</param>
         /// <param name="mount">The mount.</param>
         /// <param name="mount">The mount.</param>
-        private void OnPreFetch(Video item, IIsoMount mount)
+        private void OnPreFetch(Video item, IIsoMount mount, BlurayDiscInfo blurayDiscInfo)
         {
         {
             if (item.VideoType == VideoType.Iso)
             if (item.VideoType == VideoType.Iso)
             {
             {
@@ -509,6 +514,11 @@ namespace MediaBrowser.Providers.MediaInfo
             {
             {
                 FetchFromDvdLib(item, mount);
                 FetchFromDvdLib(item, mount);
             }
             }
+
+            if (item.VideoType == VideoType.BluRay || (item.IsoType.HasValue && item.IsoType.Value == IsoType.BluRay))
+            {
+                item.PlayableStreamFileNames = blurayDiscInfo.Files.ToList();
+            }
         }
         }
 
 
         private void FetchFromDvdLib(Video item, IIsoMount mount)
         private void FetchFromDvdLib(Video item, IIsoMount mount)

+ 1 - 1
MediaBrowser.Providers/MediaInfo/VideoImageProvider.cs

@@ -56,7 +56,7 @@ namespace MediaBrowser.Providers.MediaInfo
             var video = (Video)item;
             var video = (Video)item;
 
 
             // No support for this
             // No support for this
-            if (video.VideoType == VideoType.HdDvd)
+            if (video.VideoType == VideoType.HdDvd || video.IsPlaceHolder)
             {
             {
                 return Task.FromResult(new DynamicImageResponse { HasImage = false });
                 return Task.FromResult(new DynamicImageResponse { HasImage = false });
             }
             }

+ 1 - 1
MediaBrowser.Providers/Movies/FanartMovieImageProvider.cs

@@ -380,7 +380,7 @@ namespace MediaBrowser.Providers.Movies
         /// <returns>System.String.</returns>
         /// <returns>System.String.</returns>
         internal static string GetMoviesDataPath(IApplicationPaths appPaths)
         internal static string GetMoviesDataPath(IApplicationPaths appPaths)
         {
         {
-            var dataPath = Path.Combine(appPaths.DataPath, "fanart-movies");
+            var dataPath = Path.Combine(appPaths.CachePath, "fanart-movies");
 
 
             return dataPath;
             return dataPath;
         }
         }

+ 13 - 6
MediaBrowser.Providers/Movies/GenericMovieDbInfo.cs

@@ -39,11 +39,13 @@ namespace MediaBrowser.Providers.Movies
             // Don't search for music video id's because it is very easy to misidentify. 
             // Don't search for music video id's because it is very easy to misidentify. 
             if (string.IsNullOrEmpty(tmdbId) && string.IsNullOrEmpty(imdbId) && typeof(T) != typeof(MusicVideo))
             if (string.IsNullOrEmpty(tmdbId) && string.IsNullOrEmpty(imdbId) && typeof(T) != typeof(MusicVideo))
             {
             {
-                var searchResult = await new MovieDbSearch(_logger, _jsonSerializer).FindMovieId(itemId, cancellationToken).ConfigureAwait(false);
+                var searchResults = await new MovieDbSearch(_logger, _jsonSerializer).GetMovieSearchResults(itemId, cancellationToken).ConfigureAwait(false);
+
+                var searchResult = searchResults.FirstOrDefault();
 
 
                 if (searchResult != null)
                 if (searchResult != null)
                 {
                 {
-                    tmdbId = searchResult.id.ToString(_usCulture);
+                    tmdbId = searchResult.GetProviderId(MetadataProviders.Tmdb);
                 }
                 }
             }
             }
 
 
@@ -174,11 +176,16 @@ namespace MediaBrowser.Providers.Movies
                                                        : null;
                                                        : null;
             }
             }
 
 
-            if (movieData.release_date.Year != 1)
+            if (!string.IsNullOrWhiteSpace(movieData.release_date))
             {
             {
-                //no specific country release info at all
-                movie.PremiereDate = movieData.release_date.ToUniversalTime();
-                movie.ProductionYear = movieData.release_date.Year;
+                DateTime r;
+
+                // These dates are always in this exact format
+                if (DateTime.TryParse(movieData.release_date, _usCulture, DateTimeStyles.None, out r))
+                {
+                    movie.PremiereDate = r.ToUniversalTime();
+                    movie.ProductionYear = movie.PremiereDate.Value.Year;
+                }
             }
             }
 
 
             //studios
             //studios

+ 65 - 7
MediaBrowser.Providers/Movies/MovieDbProvider.cs

@@ -12,6 +12,7 @@ using MediaBrowser.Model.Providers;
 using MediaBrowser.Model.Serialization;
 using MediaBrowser.Model.Serialization;
 using System;
 using System;
 using System.Collections.Generic;
 using System.Collections.Generic;
+using System.Globalization;
 using System.IO;
 using System.IO;
 using System.Linq;
 using System.Linq;
 using System.Threading;
 using System.Threading;
@@ -35,6 +36,8 @@ namespace MediaBrowser.Providers.Movies
         private readonly ILogger _logger;
         private readonly ILogger _logger;
         private readonly ILocalizationManager _localization;
         private readonly ILocalizationManager _localization;
 
 
+        private readonly CultureInfo _usCulture = new CultureInfo("en-US");
+        
         public MovieDbProvider(IJsonSerializer jsonSerializer, IHttpClient httpClient, IFileSystem fileSystem, IServerConfigurationManager configurationManager, ILogger logger, ILocalizationManager localization)
         public MovieDbProvider(IJsonSerializer jsonSerializer, IHttpClient httpClient, IFileSystem fileSystem, IServerConfigurationManager configurationManager, ILogger logger, ILocalizationManager localization)
         {
         {
             _jsonSerializer = jsonSerializer;
             _jsonSerializer = jsonSerializer;
@@ -46,9 +49,59 @@ namespace MediaBrowser.Providers.Movies
             Current = this;
             Current = this;
         }
         }
 
 
-        public async Task<IEnumerable<RemoteSearchResult>> GetSearchResults(MovieInfo searchInfo, CancellationToken cancellationToken)
+        public Task<IEnumerable<RemoteSearchResult>> GetSearchResults(MovieInfo searchInfo, CancellationToken cancellationToken)
         {
         {
-            return new List<RemoteSearchResult>();
+            return GetMovieSearchResults(searchInfo, cancellationToken);
+        }
+
+        public async Task<IEnumerable<RemoteSearchResult>> GetMovieSearchResults(ItemLookupInfo searchInfo, CancellationToken cancellationToken)
+        {
+            var tmdbSettings = await GetTmdbSettings(cancellationToken).ConfigureAwait(false);
+
+            var tmdbImageUrl = tmdbSettings.images.base_url + "original";
+
+            var tmdbId = searchInfo.GetProviderId(MetadataProviders.Tmdb);
+
+            if (!string.IsNullOrEmpty(tmdbId))
+            {
+                cancellationToken.ThrowIfCancellationRequested();
+
+                await EnsureMovieInfo(tmdbId, searchInfo.MetadataLanguage, cancellationToken).ConfigureAwait(false);
+
+                var dataFilePath = GetDataFilePath(tmdbId, searchInfo.MetadataLanguage);
+
+                var obj = _jsonSerializer.DeserializeFromFile<CompleteMovieData>(dataFilePath);
+
+                var remoteResult = new RemoteSearchResult
+                {
+                    Name = obj.title ?? obj.original_title ?? obj.name,
+                    SearchProviderName = Name,
+                    ImageUrl = string.IsNullOrWhiteSpace(obj.poster_path) ? null : tmdbImageUrl + obj.poster_path
+                };
+
+                if (!string.IsNullOrWhiteSpace(obj.release_date))
+                {
+                    DateTime r;
+
+                    // These dates are always in this exact format
+                    if (DateTime.TryParse(obj.release_date, _usCulture, DateTimeStyles.None, out r))
+                    {
+                        remoteResult.PremiereDate = r.ToUniversalTime();
+                        remoteResult.ProductionYear = remoteResult.PremiereDate.Value.Year;
+                    }
+                }
+                
+                remoteResult.SetProviderId(MetadataProviders.Tmdb, obj.id.ToString(_usCulture));
+
+                if (!string.IsNullOrWhiteSpace(obj.imdb_id))
+                {
+                    remoteResult.SetProviderId(MetadataProviders.Imdb, obj.imdb_id);
+                }
+
+                return new[] { remoteResult };
+            }
+
+            return await new MovieDbSearch(_logger, _jsonSerializer).GetMovieSearchResults(searchInfo, cancellationToken).ConfigureAwait(false);
         }
         }
 
 
         public Task<MetadataResult<Movie>> GetMetadata(MovieInfo info, CancellationToken cancellationToken)
         public Task<MetadataResult<Movie>> GetMetadata(MovieInfo info, CancellationToken cancellationToken)
@@ -57,7 +110,7 @@ namespace MediaBrowser.Providers.Movies
         }
         }
 
 
         public Task<MetadataResult<T>> GetItemMetadata<T>(ItemLookupInfo id, CancellationToken cancellationToken)
         public Task<MetadataResult<T>> GetItemMetadata<T>(ItemLookupInfo id, CancellationToken cancellationToken)
-            where T : Video, new ()
+            where T : Video, new()
         {
         {
             var movieDb = new GenericMovieDbInfo<T>(_logger, _jsonSerializer);
             var movieDb = new GenericMovieDbInfo<T>(_logger, _jsonSerializer);
 
 
@@ -347,10 +400,10 @@ namespace MediaBrowser.Providers.Movies
                 var dataFilePath = GetDataFilePath(tmdbId, item.GetPreferredMetadataLanguage());
                 var dataFilePath = GetDataFilePath(tmdbId, item.GetPreferredMetadataLanguage());
 
 
                 var fileInfo = new FileInfo(dataFilePath);
                 var fileInfo = new FileInfo(dataFilePath);
-                
+
                 return !fileInfo.Exists || _fileSystem.GetLastWriteTimeUtc(fileInfo) > date;
                 return !fileInfo.Exists || _fileSystem.GetLastWriteTimeUtc(fileInfo) > date;
             }
             }
-            
+
             return false;
             return false;
         }
         }
 
 
@@ -530,7 +583,7 @@ namespace MediaBrowser.Providers.Movies
             public string poster_path { get; set; }
             public string poster_path { get; set; }
             public List<ProductionCompany> production_companies { get; set; }
             public List<ProductionCompany> production_companies { get; set; }
             public List<ProductionCountry> production_countries { get; set; }
             public List<ProductionCountry> production_countries { get; set; }
-            public DateTime release_date { get; set; }
+            public string release_date { get; set; }
             public int revenue { get; set; }
             public int revenue { get; set; }
             public int runtime { get; set; }
             public int runtime { get; set; }
             public List<SpokenLanguage> spoken_languages { get; set; }
             public List<SpokenLanguage> spoken_languages { get; set; }
@@ -558,7 +611,12 @@ namespace MediaBrowser.Providers.Movies
 
 
         public Task<HttpResponseInfo> GetImageResponse(string url, CancellationToken cancellationToken)
         public Task<HttpResponseInfo> GetImageResponse(string url, CancellationToken cancellationToken)
         {
         {
-            throw new NotImplementedException();
+            return _httpClient.GetResponse(new HttpRequestOptions
+            {
+                CancellationToken = cancellationToken,
+                Url = url,
+                ResourcePool = MovieDbResourcePool
+            });
         }
         }
     }
     }
 }
 }

+ 88 - 78
MediaBrowser.Providers/Movies/MovieDbSearch.cs

@@ -1,6 +1,8 @@
 using MediaBrowser.Common.Net;
 using MediaBrowser.Common.Net;
 using MediaBrowser.Controller.Providers;
 using MediaBrowser.Controller.Providers;
+using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.Logging;
 using MediaBrowser.Model.Logging;
+using MediaBrowser.Model.Providers;
 using MediaBrowser.Model.Serialization;
 using MediaBrowser.Model.Serialization;
 using System;
 using System;
 using System.Collections.Generic;
 using System.Collections.Generic;
@@ -29,27 +31,31 @@ namespace MediaBrowser.Providers.Movies
             _json = json;
             _json = json;
         }
         }
 
 
-        public Task<TmdbMovieSearchResult> FindSeriesId(ItemLookupInfo idInfo, CancellationToken cancellationToken)
+        public Task<IEnumerable<RemoteSearchResult>> GetSearchResults(SeriesInfo idInfo, CancellationToken cancellationToken)
         {
         {
-            return FindId(idInfo, "tv", cancellationToken);
+            return GetSearchResults(idInfo, "tv", cancellationToken);
         }
         }
 
 
-        public Task<TmdbMovieSearchResult> FindMovieId(ItemLookupInfo idInfo, CancellationToken cancellationToken)
+        public Task<IEnumerable<RemoteSearchResult>> GetMovieSearchResults(ItemLookupInfo idInfo, CancellationToken cancellationToken)
         {
         {
-            return FindId(idInfo, "movie", cancellationToken);
+            return GetSearchResults(idInfo, "movie", cancellationToken);
         }
         }
 
 
-        public Task<TmdbMovieSearchResult> FindCollectionId(ItemLookupInfo idInfo, CancellationToken cancellationToken)
+        public Task<IEnumerable<RemoteSearchResult>> GetSearchResults(BoxSetInfo idInfo, CancellationToken cancellationToken)
         {
         {
-            return FindId(idInfo, "collection", cancellationToken);
+            return GetSearchResults(idInfo, "collection", cancellationToken);
         }
         }
 
 
-        private async Task<TmdbMovieSearchResult> FindId(ItemLookupInfo idInfo, string searchType, CancellationToken cancellationToken)
+        private async Task<IEnumerable<RemoteSearchResult>> GetSearchResults(ItemLookupInfo idInfo, string searchType, CancellationToken cancellationToken)
         {
         {
             var name = idInfo.Name;
             var name = idInfo.Name;
             var year = idInfo.Year;
             var year = idInfo.Year;
             int? yearInName = null;
             int? yearInName = null;
 
 
+            var tmdbSettings = await MovieDbProvider.Current.GetTmdbSettings(cancellationToken).ConfigureAwait(false);
+
+            var tmdbImageUrl = tmdbSettings.images.base_url + "original";
+            
             NameParser.ParseName(name, out name, out yearInName);
             NameParser.ParseName(name, out name, out yearInName);
 
 
             year = year ?? yearInName;
             year = year ?? yearInName;
@@ -60,48 +66,57 @@ namespace MediaBrowser.Providers.Movies
             //nope - search for it
             //nope - search for it
             //var searchType = item is BoxSet ? "collection" : "movie";
             //var searchType = item is BoxSet ? "collection" : "movie";
 
 
-            var id = await AttemptFindId(name, searchType, year, language, cancellationToken).ConfigureAwait(false);
+            var results = await GetSearchResults(name, searchType, year, language, tmdbImageUrl, cancellationToken).ConfigureAwait(false);
             
             
-            if (id == null)
+            if (results.Count == 0)
             {
             {
                 //try in english if wasn't before
                 //try in english if wasn't before
-                if (language != "en")
+                if (!string.Equals(language, "en", StringComparison.OrdinalIgnoreCase))
                 {
                 {
-                    id = await AttemptFindId(name, searchType, year, "en", cancellationToken).ConfigureAwait(false);
+                    results = await GetSearchResults(name, searchType, year, "en", tmdbImageUrl, cancellationToken).ConfigureAwait(false);
                 }
                 }
-                else
-                {
-                    // try with dot and _ turned to space
-                    var originalName = name;
+            }
 
 
-                    name = name.Replace(",", " ");
-                    name = name.Replace(".", " ");
-                    name = name.Replace("_", " ");
-                    name = name.Replace("-", " ");
-                    name = name.Replace("!", " ");
-                    name = name.Replace("?", " ");
+            if (results.Count == 0)
+            {
+                // try with dot and _ turned to space
+                var originalName = name;
 
 
-                    name = name.Trim();
+                name = name.Replace(",", " ");
+                name = name.Replace(".", " ");
+                name = name.Replace("_", " ");
+                name = name.Replace("-", " ");
+                name = name.Replace("!", " ");
+                name = name.Replace("?", " ");
 
 
-                    // Search again if the new name is different
-                    if (!string.Equals(name, originalName))
-                    {
-                        id = await AttemptFindId(name, searchType, year, language, cancellationToken).ConfigureAwait(false);
+                name = name.Trim();
 
 
-                        if (id == null && language != "en")
-                        {
-                            //one more time, in english
-                            id = await AttemptFindId(name, searchType, year, "en", cancellationToken).ConfigureAwait(false);
+                // Search again if the new name is different
+                if (!string.Equals(name, originalName))
+                {
+                    results = await GetSearchResults(name, searchType, year, language, tmdbImageUrl, cancellationToken).ConfigureAwait(false);
+
+                    if (results.Count == 0 && !string.Equals(language, "en", StringComparison.OrdinalIgnoreCase))
+                    {
+                        //one more time, in english
+                        results = await GetSearchResults(name, searchType, year, "en", tmdbImageUrl, cancellationToken).ConfigureAwait(false);
 
 
-                        }
                     }
                     }
                 }
                 }
             }
             }
 
 
-            return id;
+            return results.Where(i =>
+            {
+                if (year.HasValue && i.ProductionYear.HasValue)
+                {
+                    return year.Value == i.ProductionYear.Value;
+                }
+
+                return true;
+            });
         }
         }
 
 
-        private async Task<TmdbMovieSearchResult> AttemptFindId(string name, string type, int? year, string language, CancellationToken cancellationToken)
+        private async Task<List<RemoteSearchResult>> GetSearchResults(string name, string type, int? year, string language, string baseImageUrl, CancellationToken cancellationToken)
         {
         {
             var url3 = string.Format(Search3, WebUtility.UrlEncode(name), ApiKey, language, type);
             var url3 = string.Format(Search3, WebUtility.UrlEncode(name), ApiKey, language, type);
 
 
@@ -113,67 +128,62 @@ namespace MediaBrowser.Providers.Movies
 
 
             }).ConfigureAwait(false))
             }).ConfigureAwait(false))
             {
             {
-                var searchResult = _json.DeserializeFromStream<TmdbMovieSearchResults>(json);
-                return FindBestResult(searchResult.results, name, year);
-            }
-        }
+                var searchResults = _json.DeserializeFromStream<TmdbMovieSearchResults>(json);
 
 
-        private TmdbMovieSearchResult FindBestResult(List<TmdbMovieSearchResult> results, string name, int? year)
-        {
-            if (year.HasValue)
-            {
-                // Take the first result from the same year
-                var result = results.FirstOrDefault(i =>
-                {
-                    // Make sure it has a name
-                    if (!string.IsNullOrEmpty(i.title ?? i.name))
+                var results = searchResults.results ?? new List<TmdbMovieSearchResult>();
+
+                var index = 0;
+                var resultTuples = results.Select(result => new Tuple<TmdbMovieSearchResult, int>(result, index++)).ToList();
+
+                return resultTuples.OrderBy(i => GetSearchResultOrder(i.Item1, year))
+                    .ThenBy(i => i.Item2)
+                    .Select(i => i.Item1)
+                    .Select(i =>
                     {
                     {
-                        DateTime r;
+                        var remoteResult = new RemoteSearchResult
+                        {
+                            SearchProviderName = MovieDbProvider.Current.Name,
+                            Name = i.title ?? i.original_title ?? i.name,
+                            ImageUrl = string.IsNullOrWhiteSpace(i.poster_path) ? null : baseImageUrl + i.poster_path
+                        };
 
 
-                        // These dates are always in this exact format
-                        if (DateTime.TryParseExact(i.release_date, "yyyy-MM-dd", EnUs, DateTimeStyles.None, out r))
+                        if (!string.IsNullOrWhiteSpace(i.release_date))
                         {
                         {
-                            return r.Year == year.Value;
+                            DateTime r;
+
+                            // These dates are always in this exact format
+                            if (DateTime.TryParseExact(i.release_date, "yyyy-MM-dd", EnUs, DateTimeStyles.None, out r))
+                            {
+                                remoteResult.PremiereDate = r.ToUniversalTime();
+                                remoteResult.ProductionYear = remoteResult.PremiereDate.Value.Year;
+                            }
                         }
                         }
-                    }
 
 
-                    return false;
-                });
+                        remoteResult.SetProviderId(MetadataProviders.Tmdb, i.id.ToString(EnUs));
 
 
-                if (result != null)
-                {
-                    return result;
-                }
-
-                // Take the first result within one year
-                result = results.FirstOrDefault(i =>
-                {
-                    // Make sure it has a name
-                    if (!string.IsNullOrEmpty(i.title ?? i.name))
-                    {
-                        DateTime r;
+                        return remoteResult;
 
 
-                        // These dates are always in this exact format
-                        if (DateTime.TryParseExact(i.release_date, "yyyy-MM-dd", EnUs, DateTimeStyles.None, out r))
-                        {
-                            return Math.Abs(r.Year - year.Value) <= 1;
-                        }
-                    }
+                    })
+                    .ToList();
+            }
+        }
 
 
-                    return false;
-                });
+        private int GetSearchResultOrder(TmdbMovieSearchResult result, int? year)
+        {
+            if (year.HasValue)
+            {
+                DateTime r;
 
 
-                if (result != null)
+                // These dates are always in this exact format
+                if (DateTime.TryParseExact(result.release_date, "yyyy-MM-dd", EnUs, DateTimeStyles.None, out r))
                 {
                 {
-                    return result;
+                    return Math.Abs(r.Year - year.Value);
                 }
                 }
             }
             }
 
 
-            // Just take the first one
-            return results.FirstOrDefault(i => !string.IsNullOrEmpty(i.title ?? i.name));
+            return 0;
         }
         }
 
 
-
         /// <summary>
         /// <summary>
         /// Class TmdbMovieSearchResult
         /// Class TmdbMovieSearchResult
         /// </summary>
         /// </summary>

+ 15 - 3
MediaBrowser.Providers/Movies/MovieDbTrailerProvider.cs

@@ -11,14 +11,21 @@ namespace MediaBrowser.Providers.Movies
 {
 {
     public class MovieDbTrailerProvider : IRemoteMetadataProvider<Trailer, TrailerInfo>, IHasOrder
     public class MovieDbTrailerProvider : IRemoteMetadataProvider<Trailer, TrailerInfo>, IHasOrder
     {
     {
+        private readonly IHttpClient _httpClient;
+
+        public MovieDbTrailerProvider(IHttpClient httpClient)
+        {
+            _httpClient = httpClient;
+        }
+
         public Task<MetadataResult<Trailer>> GetMetadata(TrailerInfo info, CancellationToken cancellationToken)
         public Task<MetadataResult<Trailer>> GetMetadata(TrailerInfo info, CancellationToken cancellationToken)
         {
         {
             return MovieDbProvider.Current.GetItemMetadata<Trailer>(info, cancellationToken);
             return MovieDbProvider.Current.GetItemMetadata<Trailer>(info, cancellationToken);
         }
         }
 
 
-        public async Task<IEnumerable<RemoteSearchResult>> GetSearchResults(TrailerInfo searchInfo, CancellationToken cancellationToken)
+        public Task<IEnumerable<RemoteSearchResult>> GetSearchResults(TrailerInfo searchInfo, CancellationToken cancellationToken)
         {
         {
-            return new List<RemoteSearchResult>();
+            return MovieDbProvider.Current.GetMovieSearchResults(searchInfo, cancellationToken);
         }
         }
 
 
         public string Name
         public string Name
@@ -42,7 +49,12 @@ namespace MediaBrowser.Providers.Movies
 
 
         public Task<HttpResponseInfo> GetImageResponse(string url, CancellationToken cancellationToken)
         public Task<HttpResponseInfo> GetImageResponse(string url, CancellationToken cancellationToken)
         {
         {
-            throw new NotImplementedException();
+            return _httpClient.GetResponse(new HttpRequestOptions
+            {
+                CancellationToken = cancellationToken,
+                Url = url,
+                ResourcePool = MovieDbProvider.Current.MovieDbResourcePool
+            });
         }
         }
     }
     }
 }
 }

+ 1 - 1
MediaBrowser.Providers/Music/FanArtArtistProvider.cs

@@ -458,7 +458,7 @@ namespace MediaBrowser.Providers.Music
         /// <returns>System.String.</returns>
         /// <returns>System.String.</returns>
         internal static string GetArtistDataPath(IApplicationPaths appPaths)
         internal static string GetArtistDataPath(IApplicationPaths appPaths)
         {
         {
-            var dataPath = Path.Combine(appPaths.DataPath, "fanart-music");
+            var dataPath = Path.Combine(appPaths.CachePath, "fanart-music");
 
 
             return dataPath;
             return dataPath;
         }
         }

+ 14 - 3
MediaBrowser.Providers/People/MovieDbPersonProvider.cs

@@ -29,12 +29,14 @@ namespace MediaBrowser.Providers.People
         private readonly IJsonSerializer _jsonSerializer;
         private readonly IJsonSerializer _jsonSerializer;
         private readonly IFileSystem _fileSystem;
         private readonly IFileSystem _fileSystem;
         private readonly IServerConfigurationManager _configurationManager;
         private readonly IServerConfigurationManager _configurationManager;
+        private readonly IHttpClient _httpClient;
 
 
-        public MovieDbPersonProvider(IFileSystem fileSystem, IServerConfigurationManager configurationManager, IJsonSerializer jsonSerializer)
+        public MovieDbPersonProvider(IFileSystem fileSystem, IServerConfigurationManager configurationManager, IJsonSerializer jsonSerializer, IHttpClient httpClient)
         {
         {
             _fileSystem = fileSystem;
             _fileSystem = fileSystem;
             _configurationManager = configurationManager;
             _configurationManager = configurationManager;
             _jsonSerializer = jsonSerializer;
             _jsonSerializer = jsonSerializer;
+            _httpClient = httpClient;
             Current = this;
             Current = this;
         }
         }
 
 
@@ -64,6 +66,8 @@ namespace MediaBrowser.Providers.People
                 {
                 {
                     Name = info.name,
                     Name = info.name,
 
 
+                    SearchProviderName = Name,
+                    
                     ImageUrl = images.Count == 0 ? null : (tmdbImageUrl + images[0].file_path)
                     ImageUrl = images.Count == 0 ? null : (tmdbImageUrl + images[0].file_path)
                 };
                 };
 
 
@@ -94,6 +98,8 @@ namespace MediaBrowser.Providers.People
         {
         {
             var result = new RemoteSearchResult
             var result = new RemoteSearchResult
             {
             {
+                SearchProviderName = Name,
+                
                 Name = i.Name,
                 Name = i.Name,
 
 
                 ImageUrl = string.IsNullOrEmpty(i.Profile_Path) ? null : (baseImageUrl + i.Profile_Path)
                 ImageUrl = string.IsNullOrEmpty(i.Profile_Path) ? null : (baseImageUrl + i.Profile_Path)
@@ -217,7 +223,7 @@ namespace MediaBrowser.Providers.People
 
 
         private static string GetPersonsDataPath(IApplicationPaths appPaths)
         private static string GetPersonsDataPath(IApplicationPaths appPaths)
         {
         {
-            return Path.Combine(appPaths.DataPath, "tmdb-people");
+            return Path.Combine(appPaths.CachePath, "tmdb-people");
         }
         }
 
 
         #region Result Objects
         #region Result Objects
@@ -349,7 +355,12 @@ namespace MediaBrowser.Providers.People
 
 
         public Task<HttpResponseInfo> GetImageResponse(string url, CancellationToken cancellationToken)
         public Task<HttpResponseInfo> GetImageResponse(string url, CancellationToken cancellationToken)
         {
         {
-            throw new NotImplementedException();
+            return _httpClient.GetResponse(new HttpRequestOptions
+            {
+                CancellationToken = cancellationToken,
+                Url = url,
+                ResourcePool = MovieDbProvider.Current.MovieDbResourcePool
+            });
         }
         }
     }
     }
 }
 }

+ 11 - 2
MediaBrowser.Providers/Savers/SeriesXmlSaver.cs

@@ -1,4 +1,5 @@
-using MediaBrowser.Controller.Entities;
+using System.Globalization;
+using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Entities.TV;
 using MediaBrowser.Controller.Entities.TV;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.Entities;
@@ -36,6 +37,8 @@ namespace MediaBrowser.Providers.Savers
             return item is Series && updateType >= ItemUpdateType.MetadataDownload;
             return item is Series && updateType >= ItemUpdateType.MetadataDownload;
         }
         }
 
 
+        private static readonly CultureInfo UsCulture = new CultureInfo("en-US");
+        
         /// <summary>
         /// <summary>
         /// Saves the specified item.
         /// Saves the specified item.
         /// </summary>
         /// </summary>
@@ -94,6 +97,11 @@ namespace MediaBrowser.Providers.Savers
                 builder.Append("<FirstAired>" + SecurityElement.Escape(series.PremiereDate.Value.ToLocalTime().ToString("yyyy-MM-dd")) + "</FirstAired>");
                 builder.Append("<FirstAired>" + SecurityElement.Escape(series.PremiereDate.Value.ToLocalTime().ToString("yyyy-MM-dd")) + "</FirstAired>");
             }
             }
 
 
+            if (series.AnimeSeriesIndex.HasValue)
+            {
+                builder.Append("<AnimeSeriesIndex>" + SecurityElement.Escape(series.AnimeSeriesIndex.Value.ToString(UsCulture)) + "</AnimeSeriesIndex>");
+            }
+
             XmlSaverHelpers.AddCommonNodes(series, builder);
             XmlSaverHelpers.AddCommonNodes(series, builder);
 
 
             builder.Append("</Series>");
             builder.Append("</Series>");
@@ -111,7 +119,8 @@ namespace MediaBrowser.Providers.Savers
                     "FirstAired",
                     "FirstAired",
 
 
                     // Don't preserve old series node
                     // Don't preserve old series node
-                    "Series"
+                    "Series",
+                    "AnimeSeriesIndex"
                 });
                 });
         }
         }
 
 

+ 1 - 1
MediaBrowser.Providers/TV/FanartSeriesProvider.cs

@@ -356,7 +356,7 @@ namespace MediaBrowser.Providers.TV
         /// <returns>System.String.</returns>
         /// <returns>System.String.</returns>
         internal static string GetSeriesDataPath(IApplicationPaths appPaths)
         internal static string GetSeriesDataPath(IApplicationPaths appPaths)
         {
         {
-            var dataPath = Path.Combine(appPaths.DataPath, "fanart-tv");
+            var dataPath = Path.Combine(appPaths.CachePath, "fanart-tv");
 
 
             return dataPath;
             return dataPath;
         }
         }

+ 8 - 5
MediaBrowser.Providers/TV/MissingEpisodeProvider.cs

@@ -105,12 +105,15 @@ namespace MediaBrowser.Providers.TV
                 hasNewSeasons = await AddDummySeasonFolders(series, cancellationToken).ConfigureAwait(false);
                 hasNewSeasons = await AddDummySeasonFolders(series, cancellationToken).ConfigureAwait(false);
             }
             }
 
 
-            var seriesConfig = _config.Configuration.MetadataOptions.FirstOrDefault(i => string.Equals(i.ItemType, typeof(Series).Name, StringComparison.OrdinalIgnoreCase));
-
-            if (seriesConfig == null || !seriesConfig.DisabledMetadataFetchers.Contains(TvdbSeriesProvider.Current.Name, StringComparer.OrdinalIgnoreCase))
+            if (_config.Configuration.EnableInternetProviders)
             {
             {
-                hasNewEpisodes = await AddMissingEpisodes(group.ToList(), seriesDataPath, episodeLookup, cancellationToken)
-                    .ConfigureAwait(false);
+                var seriesConfig = _config.Configuration.MetadataOptions.FirstOrDefault(i => string.Equals(i.ItemType, typeof(Series).Name, StringComparison.OrdinalIgnoreCase));
+
+                if (seriesConfig == null || !seriesConfig.DisabledMetadataFetchers.Contains(TvdbSeriesProvider.Current.Name, StringComparer.OrdinalIgnoreCase))
+                {
+                    hasNewEpisodes = await AddMissingEpisodes(group.ToList(), seriesDataPath, episodeLookup, cancellationToken)
+                        .ConfigureAwait(false);
+                }
             }
             }
 
 
             if (hasNewSeasons || hasNewEpisodes || anySeasonsRemoved || anyEpisodesRemoved)
             if (hasNewSeasons || hasNewEpisodes || anySeasonsRemoved || anyEpisodesRemoved)

+ 106 - 18
MediaBrowser.Providers/TV/MovieDbSeriesProvider.cs

@@ -21,7 +21,7 @@ using System.Threading.Tasks;
 
 
 namespace MediaBrowser.Providers.TV
 namespace MediaBrowser.Providers.TV
 {
 {
-    public class MovieDbSeriesProvider : IRemoteMetadataProvider<Series,SeriesInfo>, IHasOrder
+    public class MovieDbSeriesProvider : IRemoteMetadataProvider<Series, SeriesInfo>, IHasOrder
     {
     {
         private const string GetTvInfo3 = @"http://api.themoviedb.org/3/tv/{0}?api_key={1}&append_to_response=casts,images,keywords,external_ids";
         private const string GetTvInfo3 = @"http://api.themoviedb.org/3/tv/{0}?api_key={1}&append_to_response=casts,images,keywords,external_ids";
         private readonly CultureInfo _usCulture = new CultureInfo("en-US");
         private readonly CultureInfo _usCulture = new CultureInfo("en-US");
@@ -33,14 +33,16 @@ namespace MediaBrowser.Providers.TV
         private readonly IServerConfigurationManager _configurationManager;
         private readonly IServerConfigurationManager _configurationManager;
         private readonly ILogger _logger;
         private readonly ILogger _logger;
         private readonly ILocalizationManager _localization;
         private readonly ILocalizationManager _localization;
+        private readonly IHttpClient _httpClient;
 
 
-        public MovieDbSeriesProvider(IJsonSerializer jsonSerializer, IFileSystem fileSystem, IServerConfigurationManager configurationManager, ILogger logger, ILocalizationManager localization)
+        public MovieDbSeriesProvider(IJsonSerializer jsonSerializer, IFileSystem fileSystem, IServerConfigurationManager configurationManager, ILogger logger, ILocalizationManager localization, IHttpClient httpClient)
         {
         {
             _jsonSerializer = jsonSerializer;
             _jsonSerializer = jsonSerializer;
             _fileSystem = fileSystem;
             _fileSystem = fileSystem;
             _configurationManager = configurationManager;
             _configurationManager = configurationManager;
             _logger = logger;
             _logger = logger;
             _localization = localization;
             _localization = localization;
+            _httpClient = httpClient;
             Current = this;
             Current = this;
         }
         }
 
 
@@ -51,7 +53,64 @@ namespace MediaBrowser.Providers.TV
 
 
         public async Task<IEnumerable<RemoteSearchResult>> GetSearchResults(SeriesInfo searchInfo, CancellationToken cancellationToken)
         public async Task<IEnumerable<RemoteSearchResult>> GetSearchResults(SeriesInfo searchInfo, CancellationToken cancellationToken)
         {
         {
-            return new List<RemoteSearchResult>();
+            var tmdbId = searchInfo.GetProviderId(MetadataProviders.Tmdb);
+
+            if (!string.IsNullOrEmpty(tmdbId))
+            {
+                cancellationToken.ThrowIfCancellationRequested();
+
+                await EnsureSeriesInfo(tmdbId, searchInfo.MetadataLanguage, cancellationToken).ConfigureAwait(false);
+                
+                var dataFilePath = GetDataFilePath(tmdbId, searchInfo.MetadataLanguage);
+
+                var obj = _jsonSerializer.DeserializeFromFile<RootObject>(dataFilePath);
+
+                var tmdbSettings = await MovieDbProvider.Current.GetTmdbSettings(cancellationToken).ConfigureAwait(false);
+                var tmdbImageUrl = tmdbSettings.images.base_url + "original";
+
+                var remoteResult = new RemoteSearchResult
+                {
+                    Name = obj.name,
+                    SearchProviderName = Name,
+                    ImageUrl = string.IsNullOrWhiteSpace(obj.poster_path) ? null : tmdbImageUrl + obj.poster_path
+                };
+
+                remoteResult.SetProviderId(MetadataProviders.Tmdb, obj.id.ToString(_usCulture));
+                remoteResult.SetProviderId(MetadataProviders.Imdb, obj.external_ids.imdb_id);
+
+                if (obj.external_ids.tvdb_id > 0)
+                {
+                    remoteResult.SetProviderId(MetadataProviders.Tvdb, obj.external_ids.tvdb_id.ToString(_usCulture));
+                }
+                
+                return new[] { remoteResult };
+            }
+
+            var imdbId = searchInfo.GetProviderId(MetadataProviders.Imdb);
+
+            if (!string.IsNullOrEmpty(imdbId))
+            {
+                var searchResult = await FindByExternalId(imdbId, "imdb_id", cancellationToken).ConfigureAwait(false);
+
+                if (searchResult != null)
+                {
+                    return new[] { searchResult };
+                }
+            }
+
+            var tvdbId = searchInfo.GetProviderId(MetadataProviders.Tvdb);
+
+            if (!string.IsNullOrEmpty(tvdbId))
+            {
+                var searchResult = await FindByExternalId(tvdbId, "tvdb_id", cancellationToken).ConfigureAwait(false);
+
+                if (searchResult != null)
+                {
+                    return new[] { searchResult };
+                }
+            }
+
+            return await new MovieDbSearch(_logger, _jsonSerializer).GetSearchResults(searchInfo, cancellationToken).ConfigureAwait(false);
         }
         }
 
 
         public async Task<MetadataResult<Series>> GetMetadata(SeriesInfo info, CancellationToken cancellationToken)
         public async Task<MetadataResult<Series>> GetMetadata(SeriesInfo info, CancellationToken cancellationToken)
@@ -66,7 +125,12 @@ namespace MediaBrowser.Providers.TV
 
 
                 if (!string.IsNullOrEmpty(imdbId))
                 if (!string.IsNullOrEmpty(imdbId))
                 {
                 {
-                    tmdbId = await FindIdByExternalId(imdbId, "imdb_id", cancellationToken).ConfigureAwait(false);
+                    var searchResult = await FindByExternalId(imdbId, "imdb_id", cancellationToken).ConfigureAwait(false);
+
+                    if (searchResult != null)
+                    {
+                        tmdbId = searchResult.GetProviderId(MetadataProviders.Tmdb);
+                    }
                 }
                 }
             }
             }
 
 
@@ -76,17 +140,24 @@ namespace MediaBrowser.Providers.TV
 
 
                 if (!string.IsNullOrEmpty(tvdbId))
                 if (!string.IsNullOrEmpty(tvdbId))
                 {
                 {
-                    tmdbId = await FindIdByExternalId(tvdbId, "tvdb_id", cancellationToken).ConfigureAwait(false);
+                    var searchResult = await FindByExternalId(tvdbId, "tvdb_id", cancellationToken).ConfigureAwait(false);
+
+                    if (searchResult != null)
+                    {
+                        tmdbId = searchResult.GetProviderId(MetadataProviders.Tmdb);
+                    }
                 }
                 }
             }
             }
 
 
             if (string.IsNullOrEmpty(tmdbId))
             if (string.IsNullOrEmpty(tmdbId))
             {
             {
-                var searchResult = await new MovieDbSearch(_logger, _jsonSerializer).FindSeriesId(info, cancellationToken).ConfigureAwait(false);
+                var searchResults = await new MovieDbSearch(_logger, _jsonSerializer).GetSearchResults(info, cancellationToken).ConfigureAwait(false);
+
+                var searchResult = searchResults.FirstOrDefault();
 
 
                 if (searchResult != null)
                 if (searchResult != null)
                 {
                 {
-                    tmdbId = searchResult.id.ToString(_usCulture);
+                    tmdbId = searchResult.GetProviderId(MetadataProviders.Tmdb);
                 }
                 }
             }
             }
 
 
@@ -98,7 +169,7 @@ namespace MediaBrowser.Providers.TV
 
 
                 result.HasMetadata = result.Item != null;
                 result.HasMetadata = result.Item != null;
             }
             }
-            
+
             return result;
             return result;
         }
         }
 
 
@@ -119,7 +190,7 @@ namespace MediaBrowser.Providers.TV
 
 
             tmdbId = seriesInfo.id.ToString(_usCulture);
             tmdbId = seriesInfo.id.ToString(_usCulture);
 
 
-            dataFilePath = MovieDbProvider.Current.GetDataFilePath(tmdbId, language);
+            dataFilePath = GetDataFilePath(tmdbId, language);
             Directory.CreateDirectory(Path.GetDirectoryName(dataFilePath));
             Directory.CreateDirectory(Path.GetDirectoryName(dataFilePath));
             _jsonSerializer.SerializeToFile(seriesInfo, dataFilePath);
             _jsonSerializer.SerializeToFile(seriesInfo, dataFilePath);
 
 
@@ -147,7 +218,7 @@ namespace MediaBrowser.Providers.TV
                 series.CommunityRating = rating;
                 series.CommunityRating = rating;
             }
             }
 
 
-           series.Overview =  seriesInfo.overview;
+            series.Overview = seriesInfo.overview;
 
 
             if (seriesInfo.networks != null)
             if (seriesInfo.networks != null)
             {
             {
@@ -206,7 +277,7 @@ namespace MediaBrowser.Providers.TV
 
 
             return dataPath;
             return dataPath;
         }
         }
-        
+
         internal async Task DownloadSeriesInfo(string id, string preferredMetadataLanguage, CancellationToken cancellationToken)
         internal async Task DownloadSeriesInfo(string id, string preferredMetadataLanguage, CancellationToken cancellationToken)
         {
         {
             var mainResult = await FetchMainResult(id, preferredMetadataLanguage, cancellationToken).ConfigureAwait(false);
             var mainResult = await FetchMainResult(id, preferredMetadataLanguage, cancellationToken).ConfigureAwait(false);
@@ -241,7 +312,7 @@ namespace MediaBrowser.Providers.TV
 
 
                 url += string.Format("&language={0}", language);
                 url += string.Format("&language={0}", language);
             }
             }
-            
+
             // Get images in english and with no language
             // Get images in english and with no language
             url += "&include_image_language=" + string.Join(",", imageLanguages.ToArray());
             url += "&include_image_language=" + string.Join(",", imageLanguages.ToArray());
 
 
@@ -258,7 +329,7 @@ namespace MediaBrowser.Providers.TV
                 return _jsonSerializer.DeserializeFromStream<RootObject>(json);
                 return _jsonSerializer.DeserializeFromStream<RootObject>(json);
             }
             }
         }
         }
-        
+
         private readonly Task _cachedTask = Task.FromResult(true);
         private readonly Task _cachedTask = Task.FromResult(true);
         internal Task EnsureSeriesInfo(string tmdbId, string language, CancellationToken cancellationToken)
         internal Task EnsureSeriesInfo(string tmdbId, string language, CancellationToken cancellationToken)
         {
         {
@@ -328,10 +399,10 @@ namespace MediaBrowser.Providers.TV
             return false;
             return false;
         }
         }
 
 
-        private async Task<string> FindIdByExternalId(string id, string externalSource, CancellationToken cancellationToken)
+        private async Task<RemoteSearchResult> FindByExternalId(string id, string externalSource, CancellationToken cancellationToken)
         {
         {
-            var url = string.Format("http://api.themoviedb.org/3/tv/find/{0}?api_key={1}&external_source={2}", 
-                id, 
+            var url = string.Format("http://api.themoviedb.org/3/tv/find/{0}?api_key={1}&external_source={2}",
+                id,
                 MovieDbProvider.ApiKey,
                 MovieDbProvider.ApiKey,
                 externalSource);
                 externalSource);
 
 
@@ -351,7 +422,19 @@ namespace MediaBrowser.Providers.TV
 
 
                     if (tv != null)
                     if (tv != null)
                     {
                     {
-                        return tv.id.ToString(_usCulture);
+                        var tmdbSettings = await MovieDbProvider.Current.GetTmdbSettings(cancellationToken).ConfigureAwait(false);
+                        var tmdbImageUrl = tmdbSettings.images.base_url + "original";
+
+                        var remoteResult = new RemoteSearchResult
+                        {
+                            Name = tv.name,
+                            SearchProviderName = Name,
+                            ImageUrl = string.IsNullOrWhiteSpace(tv.poster_path) ? null : tmdbImageUrl + tv.poster_path
+                        };
+
+                        remoteResult.SetProviderId(MetadataProviders.Tmdb, tv.id.ToString(_usCulture));
+
+                        return remoteResult;
                     }
                     }
                 }
                 }
             }
             }
@@ -462,7 +545,12 @@ namespace MediaBrowser.Providers.TV
 
 
         public Task<HttpResponseInfo> GetImageResponse(string url, CancellationToken cancellationToken)
         public Task<HttpResponseInfo> GetImageResponse(string url, CancellationToken cancellationToken)
         {
         {
-            throw new NotImplementedException();
+            return _httpClient.GetResponse(new HttpRequestOptions
+            {
+                CancellationToken = cancellationToken,
+                Url = url,
+                ResourcePool = MovieDbProvider.Current.MovieDbResourcePool
+            });
         }
         }
     }
     }
 }
 }

+ 15 - 0
MediaBrowser.Providers/TV/SeriesXmlParser.cs

@@ -74,6 +74,21 @@ namespace MediaBrowser.Providers.TV
                         break;
                         break;
                     }
                     }
 
 
+                case "AnimeSeriesIndex":
+                    {
+                        var number = reader.ReadElementContentAsString();
+
+                        if (!string.IsNullOrWhiteSpace(number))
+                        {
+                            int num;
+
+                            if (int.TryParse(number, out num))
+                            {
+                                item.AnimeSeriesIndex = num;
+                            }
+                        }
+                        break;
+                    }
                 case "SeriesName":
                 case "SeriesName":
                     item.Name = reader.ReadElementContentAsString();
                     item.Name = reader.ReadElementContentAsString();
                     break;
                     break;

+ 3 - 0
MediaBrowser.Providers/TV/TvdbEpisodeProvider.cs

@@ -45,6 +45,9 @@ namespace MediaBrowser.Providers.TV
 
 
             if (!string.IsNullOrEmpty(seriesTvdbId))
             if (!string.IsNullOrEmpty(seriesTvdbId))
             {
             {
+                await TvdbSeriesProvider.Current.EnsureSeriesInfo(seriesTvdbId, searchInfo.MetadataLanguage,
+                        cancellationToken).ConfigureAwait(false);
+
                 var seriesDataPath = TvdbSeriesProvider.GetSeriesDataPath(_config.ApplicationPaths, seriesTvdbId);
                 var seriesDataPath = TvdbSeriesProvider.GetSeriesDataPath(_config.ApplicationPaths, seriesTvdbId);
 
 
                 try
                 try

+ 6 - 0
MediaBrowser.Providers/TV/TvdbPrescanTask.cs

@@ -73,6 +73,12 @@ namespace MediaBrowser.Providers.TV
         /// <returns>Task.</returns>
         /// <returns>Task.</returns>
         public async Task Run(IProgress<double> progress, CancellationToken cancellationToken)
         public async Task Run(IProgress<double> progress, CancellationToken cancellationToken)
         {
         {
+            if (!_config.Configuration.EnableInternetProviders)
+            {
+                progress.Report(100);
+                return;
+            }
+
             var seriesConfig = _config.Configuration.MetadataOptions.FirstOrDefault(i => string.Equals(i.ItemType, typeof(Series).Name, StringComparison.OrdinalIgnoreCase));
             var seriesConfig = _config.Configuration.MetadataOptions.FirstOrDefault(i => string.Equals(i.ItemType, typeof(Series).Name, StringComparison.OrdinalIgnoreCase));
 
 
             if (seriesConfig != null && seriesConfig.DisabledMetadataFetchers.Contains(TvdbSeriesProvider.Current.Name, StringComparer.OrdinalIgnoreCase))
             if (seriesConfig != null && seriesConfig.DisabledMetadataFetchers.Contains(TvdbSeriesProvider.Current.Name, StringComparer.OrdinalIgnoreCase))

+ 13 - 2
MediaBrowser.Providers/TV/TvdbSeriesProvider.cs

@@ -50,6 +50,12 @@ namespace MediaBrowser.Providers.TV
 
 
         public async Task<IEnumerable<RemoteSearchResult>> GetSearchResults(SeriesInfo searchInfo, CancellationToken cancellationToken)
         public async Task<IEnumerable<RemoteSearchResult>> GetSearchResults(SeriesInfo searchInfo, CancellationToken cancellationToken)
         {
         {
+            var seriesId = searchInfo.GetProviderId(MetadataProviders.Tvdb);
+
+            if (!string.IsNullOrEmpty(seriesId))
+            {
+            }
+            
             return new List<RemoteSearchResult>();
             return new List<RemoteSearchResult>();
         }
         }
 
 
@@ -999,7 +1005,7 @@ namespace MediaBrowser.Providers.TV
         /// <returns>System.String.</returns>
         /// <returns>System.String.</returns>
         internal static string GetSeriesDataPath(IApplicationPaths appPaths)
         internal static string GetSeriesDataPath(IApplicationPaths appPaths)
         {
         {
-            var dataPath = Path.Combine(appPaths.DataPath, "tvdb-v3");
+            var dataPath = Path.Combine(appPaths.CachePath, "tvdb");
 
 
             return dataPath;
             return dataPath;
         }
         }
@@ -1092,7 +1098,12 @@ namespace MediaBrowser.Providers.TV
 
 
         public Task<HttpResponseInfo> GetImageResponse(string url, CancellationToken cancellationToken)
         public Task<HttpResponseInfo> GetImageResponse(string url, CancellationToken cancellationToken)
         {
         {
-            throw new NotImplementedException();
+            return _httpClient.GetResponse(new HttpRequestOptions
+            {
+                CancellationToken = cancellationToken,
+                Url = url,
+                ResourcePool = TvDbResourcePool
+            });
         }
         }
     }
     }
 }
 }

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

@@ -664,6 +664,7 @@ namespace MediaBrowser.Server.Implementations.Dto
             }
             }
 
 
             dto.DisplayMediaType = item.DisplayMediaType;
             dto.DisplayMediaType = item.DisplayMediaType;
+            dto.IsUnidentified = item.IsUnidentified;
 
 
             if (fields.Contains(ItemFields.Settings))
             if (fields.Contains(ItemFields.Settings))
             {
             {
@@ -969,6 +970,12 @@ namespace MediaBrowser.Server.Implementations.Dto
                 }
                 }
             }
             }
 
 
+            var supportsPlaceHolders = item as ISupportsPlaceHolders;
+            if (supportsPlaceHolders != null)
+            {
+                dto.IsPlaceHolder = supportsPlaceHolders.IsPlaceHolder;
+            }
+            
             // Add audio info
             // Add audio info
             var audio = item as Audio;
             var audio = item as Audio;
             if (audio != null)
             if (audio != null)
@@ -1092,6 +1099,8 @@ namespace MediaBrowser.Server.Implementations.Dto
                 {
                 {
                     dto.DisplaySpecialsWithSeasons = series.DisplaySpecialsWithSeasons;
                     dto.DisplaySpecialsWithSeasons = series.DisplaySpecialsWithSeasons;
                 }
                 }
+
+                dto.AnimeSeriesIndex = series.AnimeSeriesIndex;
             }
             }
 
 
             if (episode != null)
             if (episode != null)

+ 14 - 14
MediaBrowser.Server.Implementations/EntryPoints/ExternalPortForwarding.cs

@@ -42,7 +42,7 @@ namespace MediaBrowser.Server.Implementations.EntryPoints
 
 
         public void Run()
         public void Run()
         {
         {
-            NatUtility.Logger = new LogWriter(_logger);
+            //NatUtility.Logger = new LogWriter(_logger);
             
             
             Reload();
             Reload();
         }
         }
@@ -64,17 +64,17 @@ namespace MediaBrowser.Server.Implementations.EntryPoints
 
 
         void NatUtility_UnhandledException(object sender, UnhandledExceptionEventArgs e)
         void NatUtility_UnhandledException(object sender, UnhandledExceptionEventArgs e)
         {
         {
-            var ex = e.ExceptionObject as Exception;
-
-            if (ex == null)
-            {
-                _logger.Error("Unidentified error reported by Mono.Nat");
-            }
-            else
-            {
-                // Seeing some blank exceptions coming through here
-                _logger.ErrorException("Error reported by Mono.Nat: ", ex);
-            }
+            //var ex = e.ExceptionObject as Exception;
+
+            //if (ex == null)
+            //{
+            //    _logger.Error("Unidentified error reported by Mono.Nat");
+            //}
+            //else
+            //{
+            //    // Seeing some blank exceptions coming through here
+            //    _logger.ErrorException("Error reported by Mono.Nat: ", ex);
+            //}
         }
         }
 
 
         void NatUtility_DeviceFound(object sender, DeviceEventArgs e)
         void NatUtility_DeviceFound(object sender, DeviceEventArgs e)
@@ -88,7 +88,7 @@ namespace MediaBrowser.Server.Implementations.EntryPoints
             }
             }
             catch (Exception ex)
             catch (Exception ex)
             {
             {
-                _logger.ErrorException("Error creating port forwarding rules", ex);
+                //_logger.ErrorException("Error creating port forwarding rules", ex);
             }
             }
         }
         }
 
 
@@ -106,7 +106,7 @@ namespace MediaBrowser.Server.Implementations.EntryPoints
 
 
         private void CreatePortMap(INatDevice device, int port)
         private void CreatePortMap(INatDevice device, int port)
         {
         {
-            _logger.Info("Creating port map on port {0}", port);
+            _logger.Debug("Creating port map on port {0}", port);
 
 
             device.CreatePortMap(new Mapping(Protocol.Tcp, port, port)
             device.CreatePortMap(new Mapping(Protocol.Tcp, port, port)
             {
             {

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

@@ -451,7 +451,7 @@ namespace MediaBrowser.Server.Implementations.Library
                 }
                 }
             }
             }
 
 
-            if (options.DeleteFileLocation && (locationType == LocationType.FileSystem || locationType == LocationType.Offline))
+            if (options.DeleteFileLocation && locationType != LocationType.Remote && locationType != LocationType.Virtual)
             {
             {
                 foreach (var path in item.GetDeletePaths().ToList())
                 foreach (var path in item.GetDeletePaths().ToList())
                 {
                 {
@@ -922,6 +922,9 @@ namespace MediaBrowser.Server.Implementations.Library
         /// <returns>Task.</returns>
         /// <returns>Task.</returns>
         public Task ValidatePeople(CancellationToken cancellationToken, IProgress<double> progress)
         public Task ValidatePeople(CancellationToken cancellationToken, IProgress<double> progress)
         {
         {
+            // Ensure the location is unavailable.
+            Directory.CreateDirectory(ConfigurationManager.ApplicationPaths.PeoplePath);
+
             return new PeopleValidator(this, _logger).ValidatePeople(cancellationToken, progress);
             return new PeopleValidator(this, _logger).ValidatePeople(cancellationToken, progress);
         }
         }
 
 
@@ -933,6 +936,9 @@ namespace MediaBrowser.Server.Implementations.Library
         /// <returns>Task.</returns>
         /// <returns>Task.</returns>
         public Task ValidateArtists(CancellationToken cancellationToken, IProgress<double> progress)
         public Task ValidateArtists(CancellationToken cancellationToken, IProgress<double> progress)
         {
         {
+            // Ensure the location is unavailable.
+            Directory.CreateDirectory(ConfigurationManager.ApplicationPaths.ArtistsPath);
+            
             return new ArtistsValidator(this, _userManager, _logger).Run(progress, cancellationToken);
             return new ArtistsValidator(this, _userManager, _logger).Run(progress, cancellationToken);
         }
         }
 
 
@@ -944,6 +950,9 @@ namespace MediaBrowser.Server.Implementations.Library
         /// <returns>Task.</returns>
         /// <returns>Task.</returns>
         public Task ValidateMusicGenres(CancellationToken cancellationToken, IProgress<double> progress)
         public Task ValidateMusicGenres(CancellationToken cancellationToken, IProgress<double> progress)
         {
         {
+            // Ensure the location is unavailable.
+            Directory.CreateDirectory(ConfigurationManager.ApplicationPaths.MusicGenrePath);
+            
             return new MusicGenresValidator(this, _userManager, _logger).Run(progress, cancellationToken);
             return new MusicGenresValidator(this, _userManager, _logger).Run(progress, cancellationToken);
         }
         }
 
 
@@ -955,6 +964,9 @@ namespace MediaBrowser.Server.Implementations.Library
         /// <returns>Task.</returns>
         /// <returns>Task.</returns>
         public Task ValidateGameGenres(CancellationToken cancellationToken, IProgress<double> progress)
         public Task ValidateGameGenres(CancellationToken cancellationToken, IProgress<double> progress)
         {
         {
+            // Ensure the location is unavailable.
+            Directory.CreateDirectory(ConfigurationManager.ApplicationPaths.GameGenrePath);
+            
             return new GameGenresValidator(this, _userManager, _logger).Run(progress, cancellationToken);
             return new GameGenresValidator(this, _userManager, _logger).Run(progress, cancellationToken);
         }
         }
 
 
@@ -966,6 +978,9 @@ namespace MediaBrowser.Server.Implementations.Library
         /// <returns>Task.</returns>
         /// <returns>Task.</returns>
         public Task ValidateStudios(CancellationToken cancellationToken, IProgress<double> progress)
         public Task ValidateStudios(CancellationToken cancellationToken, IProgress<double> progress)
         {
         {
+            // Ensure the location is unavailable.
+            Directory.CreateDirectory(ConfigurationManager.ApplicationPaths.StudioPath);
+
             return new StudiosValidator(this, _userManager, _logger).Run(progress, cancellationToken);
             return new StudiosValidator(this, _userManager, _logger).Run(progress, cancellationToken);
         }
         }
 
 
@@ -977,6 +992,9 @@ namespace MediaBrowser.Server.Implementations.Library
         /// <returns>Task.</returns>
         /// <returns>Task.</returns>
         public Task ValidateGenres(CancellationToken cancellationToken, IProgress<double> progress)
         public Task ValidateGenres(CancellationToken cancellationToken, IProgress<double> progress)
         {
         {
+            // Ensure the location is unavailable.
+            Directory.CreateDirectory(ConfigurationManager.ApplicationPaths.GenrePath);
+
             return new GenresValidator(this, _userManager, _logger).Run(progress, cancellationToken);
             return new GenresValidator(this, _userManager, _logger).Run(progress, cancellationToken);
         }
         }
 
 

+ 1 - 0
MediaBrowser.Server.Implementations/Library/Resolvers/Audio/MusicAlbumResolver.cs

@@ -132,6 +132,7 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Audio
                     return true;
                     return true;
                 }
                 }
                 if (EntityResolutionHelper.IsVideoFile(fullName)) return false;
                 if (EntityResolutionHelper.IsVideoFile(fullName)) return false;
+                if (EntityResolutionHelper.IsVideoPlaceHolder(fullName)) return false;
             }
             }
 
 
             //  or a single audio file and no video files
             //  or a single audio file and no video files

+ 1 - 2
MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs

@@ -7,7 +7,6 @@ using MediaBrowser.Controller.Dto;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.LiveTv;
 using MediaBrowser.Controller.LiveTv;
-using MediaBrowser.Controller.MediaEncoding;
 using MediaBrowser.Controller.Persistence;
 using MediaBrowser.Controller.Persistence;
 using MediaBrowser.Controller.Providers;
 using MediaBrowser.Controller.Providers;
 using MediaBrowser.Controller.Sorting;
 using MediaBrowser.Controller.Sorting;
@@ -49,7 +48,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
         private List<Guid> _channelIdList = new List<Guid>();
         private List<Guid> _channelIdList = new List<Guid>();
         private Dictionary<Guid, LiveTvProgram> _programs = new Dictionary<Guid, LiveTvProgram>();
         private Dictionary<Guid, LiveTvProgram> _programs = new Dictionary<Guid, LiveTvProgram>();
 
 
-        private SemaphoreSlim _refreshSemaphore = new SemaphoreSlim(1, 1);
+        private readonly SemaphoreSlim _refreshSemaphore = new SemaphoreSlim(1, 1);
 
 
         public LiveTvManager(IServerConfigurationManager config, IFileSystem fileSystem, ILogger logger, IItemRepository itemRepo, IImageProcessor imageProcessor, IUserDataManager userDataManager, IDtoService dtoService, IUserManager userManager, ILibraryManager libraryManager, ITaskManager taskManager)
         public LiveTvManager(IServerConfigurationManager config, IFileSystem fileSystem, ILogger logger, IItemRepository itemRepo, IImageProcessor imageProcessor, IUserDataManager userDataManager, IDtoService dtoService, IUserManager userManager, ILibraryManager libraryManager, ITaskManager taskManager)
         {
         {

+ 5 - 0
MediaBrowser.Server.Implementations/MediaEncoder/EncodingManager.cs

@@ -84,6 +84,11 @@ namespace MediaBrowser.Server.Implementations.MediaEncoder
         /// <returns><c>true</c> if [is eligible for chapter image extraction] [the specified video]; otherwise, <c>false</c>.</returns>
         /// <returns><c>true</c> if [is eligible for chapter image extraction] [the specified video]; otherwise, <c>false</c>.</returns>
         private bool IsEligibleForChapterImageExtraction(Video video)
         private bool IsEligibleForChapterImageExtraction(Video video)
         {
         {
+            if (video.IsPlaceHolder)
+            {
+                return false;
+            }
+
             if (video is Movie)
             if (video is Movie)
             {
             {
                 if (!_config.Configuration.EnableMovieChapterImageExtraction)
                 if (!_config.Configuration.EnableMovieChapterImageExtraction)

+ 1 - 3
MediaBrowser.Server.Implementations/MediaEncoder/MediaEncoder.cs

@@ -125,13 +125,11 @@ namespace MediaBrowser.Server.Implementations.MediaEncoder
 
 
             switch (type)
             switch (type)
             {
             {
+                case InputType.Bluray:
                 case InputType.Dvd:
                 case InputType.Dvd:
                 case InputType.File:
                 case InputType.File:
                     inputPath = GetConcatInputArgument(inputFiles);
                     inputPath = GetConcatInputArgument(inputFiles);
                     break;
                     break;
-                case InputType.Bluray:
-                    inputPath = GetBlurayInputArgument(inputFiles[0]);
-                    break;
                 case InputType.Url:
                 case InputType.Url:
                     inputPath = GetHttpInputArgument(inputFiles);
                     inputPath = GetHttpInputArgument(inputFiles);
                     break;
                     break;

+ 1 - 3
MediaBrowser.Server.Implementations/ScheduledTasks/PeopleValidationTask.cs

@@ -34,9 +34,7 @@ namespace MediaBrowser.Server.Implementations.ScheduledTasks
         {
         {
             return new ITaskTrigger[]
             return new ITaskTrigger[]
                 {
                 {
-                    new DailyTrigger { TimeOfDay = TimeSpan.FromHours(2) },
-
-                    new IntervalTrigger{ Interval = TimeSpan.FromHours(24)}
+                    new DailyTrigger { TimeOfDay = TimeSpan.FromHours(3) },
                 };
                 };
         }
         }
 
 

+ 1 - 1
MediaBrowser.Server.Implementations/ScheduledTasks/RefreshMediaLibraryTask.cs

@@ -40,7 +40,7 @@ namespace MediaBrowser.Server.Implementations.ScheduledTasks
 
 
                 new SystemEventTrigger{ SystemEvent = SystemEvent.WakeFromSleep},
                 new SystemEventTrigger{ SystemEvent = SystemEvent.WakeFromSleep},
 
 
-                new IntervalTrigger{ Interval = TimeSpan.FromHours(4)}
+                new IntervalTrigger{ Interval = TimeSpan.FromHours(6)}
             };
             };
         }
         }
 
 

+ 60 - 3
MediaBrowser.ServerApplication/ApplicationHost.cs

@@ -336,6 +336,51 @@ namespace MediaBrowser.ServerApplication
                 {
                 {
                     // Not there, no big deal
                     // Not there, no big deal
                 }
                 }
+
+                try
+                {
+                    Directory.Delete(Path.Combine(ApplicationPaths.DataPath, "fanart-movies"), true);
+                }
+                catch (IOException)
+                {
+                    // Not there, no big deal
+                }
+
+                try
+                {
+                    Directory.Delete(Path.Combine(ApplicationPaths.DataPath, "fanart-music"), true);
+                }
+                catch (IOException)
+                {
+                    // Not there, no big deal
+                }
+
+                try
+                {
+                    Directory.Delete(Path.Combine(ApplicationPaths.DataPath, "fanart-tv"), true);
+                }
+                catch (IOException)
+                {
+                    // Not there, no big deal
+                }
+
+                try
+                {
+                    Directory.Delete(Path.Combine(ApplicationPaths.DataPath, "tmdb-people"), true);
+                }
+                catch (IOException)
+                {
+                    // Not there, no big deal
+                }
+
+                try
+                {
+                    Directory.Delete(Path.Combine(ApplicationPaths.DataPath, "tvdb-v3"), true);
+                }
+                catch (IOException)
+                {
+                    // Not there, no big deal
+                }
             });
             });
         }
         }
 
 
@@ -812,18 +857,30 @@ namespace MediaBrowser.ServerApplication
                 HasUpdateAvailable = _hasUpdateAvailable,
                 HasUpdateAvailable = _hasUpdateAvailable,
                 SupportsAutoRunAtStartup = SupportsAutoRunAtStartup,
                 SupportsAutoRunAtStartup = SupportsAutoRunAtStartup,
                 TranscodingTempPath = ApplicationPaths.TranscodingTempPath,
                 TranscodingTempPath = ApplicationPaths.TranscodingTempPath,
-                IsRunningAsService = IsRunningAsService
+                IsRunningAsService = IsRunningAsService,
+                ServerName = string.IsNullOrWhiteSpace(ServerConfigurationManager.Configuration.ServerName) ? Environment.MachineName : ServerConfigurationManager.Configuration.ServerName
             };
             };
         }
         }
 
 
         private readonly CultureInfo _usCulture = new CultureInfo("en-US");
         private readonly CultureInfo _usCulture = new CultureInfo("en-US");
         private string GetWanAddress()
         private string GetWanAddress()
         {
         {
-            var ip = WanAddressEntryPoint.WanAddress;
+            var ip = ServerConfigurationManager.Configuration.WanDdns;
+
+            if (string.IsNullOrWhiteSpace(ip))
+            {
+                ip = WanAddressEntryPoint.WanAddress;
+            }
 
 
             if (!string.IsNullOrEmpty(ip))
             if (!string.IsNullOrEmpty(ip))
             {
             {
-                return "http://" + ip + ":" + ServerConfigurationManager.Configuration.HttpServerPortNumber.ToString(_usCulture);
+                if (!ip.StartsWith("http://", StringComparison.OrdinalIgnoreCase) &&
+                    !ip.StartsWith("https://", StringComparison.OrdinalIgnoreCase))
+                {
+                    ip = "http://" + ip;
+                }
+
+                return ip + ":" + ServerConfigurationManager.Configuration.HttpServerPortNumber.ToString(_usCulture);
             }
             }
 
 
             return null;
             return null;

+ 13 - 11
MediaBrowser.ServerApplication/FFMpeg/FFMpegDownloadInfo.cs

@@ -11,6 +11,7 @@ namespace MediaBrowser.ServerApplication.FFMpeg
     {
     {
         // Windows builds: http://ffmpeg.zeranoe.com/builds/
         // Windows builds: http://ffmpeg.zeranoe.com/builds/
         // Linux builds: http://ffmpeg.gusari.org/static/
         // Linux builds: http://ffmpeg.gusari.org/static/
+        // OS X builds: http://ffmpegmac.net/
 
 
         public static string Version = ffmpegOsType("Version");
         public static string Version = ffmpegOsType("Version");
 
 
@@ -31,7 +32,7 @@ namespace MediaBrowser.ServerApplication.FFMpeg
                     switch (arg)
                     switch (arg)
                     {
                     {
                         case "Version":
                         case "Version":
-                            return "20140105";
+                            return "20140304";
                         case "FFMpegFilename":
                         case "FFMpegFilename":
                             return "ffmpeg.exe";
                             return "ffmpeg.exe";
                         case "FFProbeFilename":
                         case "FFProbeFilename":
@@ -68,7 +69,7 @@ namespace MediaBrowser.ServerApplication.FFMpeg
                             switch (arg)
                             switch (arg)
                             {
                             {
                                 case "Version":
                                 case "Version":
-                                    return "linux_x86_20140118";
+                                    return "20140304";
                                 case "FFMpegFilename":
                                 case "FFMpegFilename":
                                     return "ffmpeg";
                                     return "ffmpeg";
                                 case "FFProbeFilename":
                                 case "FFProbeFilename":
@@ -84,7 +85,7 @@ namespace MediaBrowser.ServerApplication.FFMpeg
                             switch (arg)
                             switch (arg)
                             {
                             {
                                 case "Version":
                                 case "Version":
-                                    return "linux_x86_64_20140118";
+                                    return "20140304";
                                 case "FFMpegFilename":
                                 case "FFMpegFilename":
                                     return "ffmpeg";
                                     return "ffmpeg";
                                 case "FFProbeFilename":
                                 case "FFProbeFilename":
@@ -97,7 +98,7 @@ namespace MediaBrowser.ServerApplication.FFMpeg
                     }
                     }
                     // Unsupported Unix platform
                     // Unsupported Unix platform
                     return "";
                     return "";
-                #endif
+#endif
             }
             }
             return "";
             return "";
         }
         }
@@ -111,8 +112,8 @@ namespace MediaBrowser.ServerApplication.FFMpeg
                 case PlatformID.Win32NT:
                 case PlatformID.Win32NT:
                     return new[]
                     return new[]
                     {
                     {
-                        "http://ffmpeg.zeranoe.com/builds/win32/static/ffmpeg-20140105-git-70937d9-win32-static.7z",
-                        "https://www.dropbox.com/s/oghurnp5zh292ry/ffmpeg-20140105-git-70937d9-win32-static.7z?dl=1"
+                        "http://ffmpeg.zeranoe.com/builds/win32/static/ffmpeg-20140304-git-f34cceb-win32-static.7z",
+                        "https://www.dropbox.com/s/6brdetuzbld93jk/ffmpeg-20140304-git-f34cceb-win32-static.7z?dl=1"
                     };
                     };
            
            
                     #if __MonoCS__
                     #if __MonoCS__
@@ -121,7 +122,7 @@ namespace MediaBrowser.ServerApplication.FFMpeg
                     {
                     {
                         return new[]
                         return new[]
                         {
                         {
-                            "https://copy.com/IB0W4efS6t9A/ffall-2.1.1.tar.gz?download=1"
+                            "https://www.dropbox.com/s/n188rxbulqem8ry/ffmpeg-osx-20131121.gz?dl=1"
                         };
                         };
                     }
                     }
 
 
@@ -131,8 +132,8 @@ namespace MediaBrowser.ServerApplication.FFMpeg
                         {
                         {
                             return new[]
                             return new[]
                             {
                             {
-                                "http://ffmpeg.gusari.org/static/32bit/ffmpeg.static.32bit.2014-01-18.tar.gz",
-                                "https://www.dropbox.com/s/b7nkg71sil812hp/ffmpeg.static.32bit.2014-01-04.tar.gz?dl=1"
+                                "http://ffmpeg.gusari.org/static/32bit/ffmpeg.static.32bit.2014-03-04.tar.gz",
+                                "https://www.dropbox.com/s/0l76mcauqqkta31/ffmpeg.static.32bit.2014-03-04.tar.gz?dl=1"
                             };
                             };
                         }
                         }
 
 
@@ -140,7 +141,8 @@ namespace MediaBrowser.ServerApplication.FFMpeg
                         {
                         {
                             return new[]
                             return new[]
                             {
                             {
-                                "http://ffmpeg.gusari.org/static/64bit/ffmpeg.static.64bit.2014-01-18.tar.gz"
+                                "http://ffmpeg.gusari.org/static/64bit/ffmpeg.static.64bit.2014-03-04.tar.gz",
+                                "https://www.dropbox.com/s/9wlxz440mdejuqe/ffmpeg.static.64bit.2014-03-04.tar.gz?dl=1"
                             };
                             };
                         }
                         }
 
 
@@ -148,7 +150,7 @@ namespace MediaBrowser.ServerApplication.FFMpeg
 
 
                     //No Unix version available 
                     //No Unix version available 
                     return new string[] {};
                     return new string[] {};
-                    #endif
+#endif
             }
             }
             return new string[] {};
             return new string[] {};
         }
         }

+ 8 - 5
MediaBrowser.ServerApplication/LibraryViewer.cs

@@ -84,7 +84,8 @@ namespace MediaBrowser.ServerApplication
         {
         {
             treeView1.Nodes.Clear();
             treeView1.Nodes.Clear();
 
 
-            IEnumerable<BaseItem> children = _currentUser.Name == "Physical" ? new[] { _libraryManager.RootFolder } : _libraryManager.RootFolder.GetChildren(_currentUser, true);
+            var isPhysical = _currentUser.Name == "Physical";
+            IEnumerable<BaseItem> children = isPhysical ? new[] { _libraryManager.RootFolder } : _libraryManager.RootFolder.GetChildren(_currentUser, true);
             children = OrderByName(children, _currentUser);
             children = OrderByName(children, _currentUser);
 
 
             foreach (Folder folder in children)
             foreach (Folder folder in children)
@@ -94,9 +95,9 @@ namespace MediaBrowser.ServerApplication
 
 
                 var node = new TreeNode { Tag = currentFolder };
                 var node = new TreeNode { Tag = currentFolder };
 
 
-                var subChildren = currentFolder.GetChildren(_currentUser, true);
+                var subChildren = isPhysical ? currentFolder.Children : currentFolder.GetChildren(_currentUser, true);
                 subChildren = OrderByName(subChildren, _currentUser);
                 subChildren = OrderByName(subChildren, _currentUser);
-                AddChildren(node, subChildren, _currentUser);
+                AddChildren(node, subChildren, _currentUser, isPhysical);
                 node.Text = currentFolder.Name + " (" +
                 node.Text = currentFolder.Name + " (" +
                             node.Nodes.Count + ")";
                             node.Nodes.Count + ")";
 
 
@@ -110,7 +111,7 @@ namespace MediaBrowser.ServerApplication
         /// <param name="parent">The parent.</param>
         /// <param name="parent">The parent.</param>
         /// <param name="children">The children.</param>
         /// <param name="children">The children.</param>
         /// <param name="user">The user.</param>
         /// <param name="user">The user.</param>
-        private void AddChildren(TreeNode parent, IEnumerable<BaseItem> children, User user)
+        private void AddChildren(TreeNode parent, IEnumerable<BaseItem> children, User user, bool isPhysical)
         {
         {
             foreach (var item in children)
             foreach (var item in children)
             {
             {
@@ -120,7 +121,9 @@ namespace MediaBrowser.ServerApplication
                 {
                 {
                     var prefs = _displayPreferencesManager.GetDisplayPreferences(subFolder.DisplayPreferencesId, user.Id, "LibraryExplorer");
                     var prefs = _displayPreferencesManager.GetDisplayPreferences(subFolder.DisplayPreferencesId, user.Id, "LibraryExplorer");
 
 
-                    AddChildren(node, OrderBy(subFolder.GetChildren(user, true), user, prefs.SortBy), user);
+                    var subChildren = isPhysical ? subFolder.Children : subFolder.GetChildren(_currentUser, true);
+
+                    AddChildren(node, OrderBy(subChildren, user, prefs.SortBy), user, isPhysical);
                     node.Text = item.Name + " (" + node.Nodes.Count + ")";
                     node.Text = item.Name + " (" + node.Nodes.Count + ")";
                 }
                 }
                 else
                 else

+ 4 - 4
MediaBrowser.WebDashboard/Api/DashboardService.cs

@@ -416,7 +416,7 @@ namespace MediaBrowser.WebDashboard.Api
 
 
             var files = new[]
             var files = new[]
                             {
                             {
-                                "thirdparty/jquerymobile-1.4.1/jquery.mobile-1.4.1.min.css",
+                                "thirdparty/jquerymobile-1.4.2/jquery.mobile-1.4.2.min.css",
                                 "css/all.css" + versionString
                                 "css/all.css" + versionString
                             };
                             };
 
 
@@ -456,8 +456,6 @@ namespace MediaBrowser.WebDashboard.Api
         /// <returns>Task{Stream}.</returns>
         /// <returns>Task{Stream}.</returns>
         private async Task<Stream> GetAllJavascript()
         private async Task<Stream> GetAllJavascript()
         {
         {
-            var assembly = GetType().Assembly;
-
             var scriptFiles = new[]
             var scriptFiles = new[]
                                   {
                                   {
                                       "extensions.js",
                                       "extensions.js",
@@ -497,6 +495,7 @@ namespace MediaBrowser.WebDashboard.Api
                                       "itemgallery.js",
                                       "itemgallery.js",
                                       "itemlistpage.js",
                                       "itemlistpage.js",
                                       "librarypathmapping.js",
                                       "librarypathmapping.js",
+                                      "libraryreport.js",
                                       "librarysettings.js",
                                       "librarysettings.js",
                                       "livetvchannel.js",
                                       "livetvchannel.js",
                                       "livetvchannels.js",
                                       "livetvchannels.js",
@@ -570,7 +569,7 @@ namespace MediaBrowser.WebDashboard.Api
             var newLineBytes = Encoding.UTF8.GetBytes(Environment.NewLine);
             var newLineBytes = Encoding.UTF8.GetBytes(Environment.NewLine);
 
 
             await AppendResource(memoryStream, "thirdparty/jquery-2.0.3.min.js", newLineBytes).ConfigureAwait(false);
             await AppendResource(memoryStream, "thirdparty/jquery-2.0.3.min.js", newLineBytes).ConfigureAwait(false);
-            await AppendResource(memoryStream, "thirdparty/jquerymobile-1.4.1/jquery.mobile-1.4.1.min.js", newLineBytes).ConfigureAwait(false);
+            await AppendResource(memoryStream, "thirdparty/jquerymobile-1.4.2/jquery.mobile-1.4.2.min.js", newLineBytes).ConfigureAwait(false);
 
 
             var versionString = string.Format("window.dashboardVersion='{0}';", _appHost.ApplicationVersion);
             var versionString = string.Format("window.dashboardVersion='{0}';", _appHost.ApplicationVersion);
             var versionBytes = Encoding.UTF8.GetBytes(versionString);
             var versionBytes = Encoding.UTF8.GetBytes(versionString);
@@ -580,6 +579,7 @@ namespace MediaBrowser.WebDashboard.Api
 
 
             await AppendResource(memoryStream, "thirdparty/autonumeric/autoNumeric.min.js", newLineBytes).ConfigureAwait(false);
             await AppendResource(memoryStream, "thirdparty/autonumeric/autoNumeric.min.js", newLineBytes).ConfigureAwait(false);
 
 
+            var assembly = GetType().Assembly;
             await AppendResource(assembly, memoryStream, "MediaBrowser.WebDashboard.ApiClient.js", newLineBytes).ConfigureAwait(false);
             await AppendResource(assembly, memoryStream, "MediaBrowser.WebDashboard.ApiClient.js", newLineBytes).ConfigureAwait(false);
 
 
             foreach (var file in scriptFiles)
             foreach (var file in scriptFiles)

+ 215 - 204
MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj

@@ -84,7 +84,9 @@
     </ProjectReference>
     </ProjectReference>
   </ItemGroup>
   </ItemGroup>
   <ItemGroup>
   <ItemGroup>
-    <EmbeddedResource Include="ApiClient.js" />
+    <EmbeddedResource Include="ApiClient.js">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </EmbeddedResource>
     <Content Include="dashboard-ui\advancedserversettings.html">
     <Content Include="dashboard-ui\advancedserversettings.html">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
@@ -196,6 +198,9 @@
     <Content Include="dashboard-ui\css\images\items\detail\tv.png">
     <Content Include="dashboard-ui\css\images\items\detail\tv.png">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
+    <Content Include="dashboard-ui\css\images\items\list\remotesearch.png">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
     <Content Include="dashboard-ui\css\images\media\tvflyout.png">
     <Content Include="dashboard-ui\css\images\media\tvflyout.png">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
@@ -220,6 +225,9 @@
     <Content Include="dashboard-ui\librarypathmapping.html">
     <Content Include="dashboard-ui\librarypathmapping.html">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
+    <Content Include="dashboard-ui\libraryreport.html">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
     <Content Include="dashboard-ui\livetvchannel.html">
     <Content Include="dashboard-ui\livetvchannel.html">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
@@ -487,6 +495,9 @@
     <Content Include="dashboard-ui\scripts\librarypathmapping.js">
     <Content Include="dashboard-ui\scripts\librarypathmapping.js">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
+    <Content Include="dashboard-ui\scripts\libraryreport.js">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
     <Content Include="dashboard-ui\scripts\livetvchannel.js">
     <Content Include="dashboard-ui\scripts\livetvchannel.js">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
@@ -574,613 +585,613 @@
     <Content Include="dashboard-ui\thirdparty\jquery-2.0.3.min.js">
     <Content Include="dashboard-ui\thirdparty\jquery-2.0.3.min.js">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\ajax-loader.gif">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\ajax-loader.gif">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-png\action-black.png">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-png\action-black.png">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-png\action-white.png">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-png\action-white.png">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-png\alert-black.png">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-png\alert-black.png">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-png\alert-white.png">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-png\alert-white.png">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-png\arrow-d-black.png">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-png\arrow-d-black.png">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-png\arrow-d-l-black.png">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-png\arrow-d-l-black.png">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-png\arrow-d-l-white.png">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-png\arrow-d-l-white.png">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-png\arrow-d-r-black.png">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-png\arrow-d-r-black.png">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-png\arrow-d-r-white.png">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-png\arrow-d-r-white.png">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-png\arrow-d-white.png">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-png\arrow-d-white.png">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-png\arrow-l-black.png">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-png\arrow-l-black.png">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-png\arrow-l-white.png">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-png\arrow-l-white.png">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-png\arrow-r-black.png">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-png\arrow-r-black.png">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-png\arrow-r-white.png">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-png\arrow-r-white.png">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-png\arrow-u-black.png">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-png\arrow-u-black.png">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-png\arrow-u-l-black.png">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-png\arrow-u-l-black.png">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-png\arrow-u-l-white.png">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-png\arrow-u-l-white.png">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-png\arrow-u-r-black.png">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-png\arrow-u-r-black.png">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-png\arrow-u-r-white.png">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-png\arrow-u-r-white.png">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-png\arrow-u-white.png">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-png\arrow-u-white.png">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-png\audio-black.png">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-png\audio-black.png">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-png\audio-white.png">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-png\audio-white.png">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-png\back-black.png">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-png\back-black.png">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-png\back-white.png">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-png\back-white.png">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-png\bars-black.png">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-png\bars-black.png">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-png\bars-white.png">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-png\bars-white.png">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-png\bullets-black.png">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-png\bullets-black.png">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-png\bullets-white.png">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-png\bullets-white.png">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-png\calendar-black.png">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-png\calendar-black.png">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-png\calendar-white.png">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-png\calendar-white.png">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-png\camera-black.png">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-png\camera-black.png">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-png\camera-white.png">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-png\camera-white.png">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-png\carat-d-black.png">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-png\carat-d-black.png">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-png\carat-d-white.png">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-png\carat-d-white.png">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-png\carat-l-black.png">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-png\carat-l-black.png">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-png\carat-l-white.png">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-png\carat-l-white.png">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-png\carat-r-black.png">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-png\carat-r-black.png">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-png\carat-r-white.png">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-png\carat-r-white.png">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-png\carat-u-black.png">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-png\carat-u-black.png">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-png\carat-u-white.png">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-png\carat-u-white.png">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-png\check-black.png">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-png\check-black.png">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-png\check-white.png">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-png\check-white.png">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-png\clock-black.png">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-png\clock-black.png">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-png\clock-white.png">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-png\clock-white.png">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-png\cloud-black.png">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-png\cloud-black.png">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-png\cloud-white.png">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-png\cloud-white.png">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-png\comment-black.png">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-png\comment-black.png">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-png\comment-white.png">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-png\comment-white.png">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-png\delete-black.png">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-png\delete-black.png">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-png\delete-white.png">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-png\delete-white.png">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-png\edit-black.png">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-png\edit-black.png">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-png\edit-white.png">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-png\edit-white.png">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-png\eye-black.png">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-png\eye-black.png">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-png\eye-white.png">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-png\eye-white.png">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-png\forbidden-black.png">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-png\forbidden-black.png">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-png\forbidden-white.png">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-png\forbidden-white.png">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-png\forward-black.png">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-png\forward-black.png">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-png\forward-white.png">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-png\forward-white.png">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-png\gear-black.png">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-png\gear-black.png">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-png\gear-white.png">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-png\gear-white.png">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-png\grid-black.png">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-png\grid-black.png">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-png\grid-white.png">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-png\grid-white.png">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-png\heart-black.png">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-png\heart-black.png">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-png\heart-white.png">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-png\heart-white.png">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-png\home-black.png">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-png\home-black.png">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-png\home-white.png">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-png\home-white.png">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-png\info-black.png">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-png\info-black.png">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-png\info-white.png">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-png\info-white.png">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-png\location-black.png">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-png\location-black.png">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-png\location-white.png">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-png\location-white.png">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-png\lock-black.png">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-png\lock-black.png">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-png\lock-white.png">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-png\lock-white.png">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-png\mail-black.png">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-png\mail-black.png">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-png\mail-white.png">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-png\mail-white.png">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-png\minus-black.png">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-png\minus-black.png">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-png\minus-white.png">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-png\minus-white.png">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-png\navigation-black.png">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-png\navigation-black.png">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-png\navigation-white.png">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-png\navigation-white.png">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-png\phone-black.png">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-png\phone-black.png">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-png\phone-white.png">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-png\phone-white.png">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-png\plus-black.png">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-png\plus-black.png">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-png\plus-white.png">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-png\plus-white.png">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-png\power-black.png">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-png\power-black.png">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-png\power-white.png">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-png\power-white.png">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-png\recycle-black.png">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-png\recycle-black.png">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-png\recycle-white.png">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-png\recycle-white.png">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-png\refresh-black.png">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-png\refresh-black.png">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-png\refresh-white.png">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-png\refresh-white.png">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-png\search-black.png">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-png\search-black.png">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-png\search-white.png">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-png\search-white.png">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-png\shop-black.png">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-png\shop-black.png">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-png\shop-white.png">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-png\shop-white.png">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-png\star-black.png">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-png\star-black.png">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-png\star-white.png">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-png\star-white.png">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-png\tag-black.png">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-png\tag-black.png">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-png\tag-white.png">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-png\tag-white.png">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-png\user-black.png">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-png\user-black.png">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-png\user-white.png">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-png\user-white.png">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-png\video-black.png">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-png\video-black.png">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-png\video-white.png">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-png\video-white.png">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-svg\action-black.svg">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-svg\action-black.svg">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-svg\action-white.svg">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-svg\action-white.svg">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-svg\alert-black.svg">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-svg\alert-black.svg">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-svg\alert-white.svg">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-svg\alert-white.svg">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-svg\arrow-d-black.svg">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-svg\arrow-d-black.svg">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-svg\arrow-d-l-black.svg">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-svg\arrow-d-l-black.svg">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-svg\arrow-d-l-white.svg">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-svg\arrow-d-l-white.svg">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-svg\arrow-d-r-black.svg">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-svg\arrow-d-r-black.svg">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-svg\arrow-d-r-white.svg">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-svg\arrow-d-r-white.svg">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-svg\arrow-d-white.svg">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-svg\arrow-d-white.svg">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-svg\arrow-l-black.svg">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-svg\arrow-l-black.svg">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-svg\arrow-l-white.svg">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-svg\arrow-l-white.svg">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-svg\arrow-r-black.svg">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-svg\arrow-r-black.svg">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-svg\arrow-r-white.svg">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-svg\arrow-r-white.svg">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-svg\arrow-u-black.svg">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-svg\arrow-u-black.svg">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-svg\arrow-u-l-black.svg">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-svg\arrow-u-l-black.svg">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-svg\arrow-u-l-white.svg">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-svg\arrow-u-l-white.svg">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-svg\arrow-u-r-black.svg">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-svg\arrow-u-r-black.svg">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-svg\arrow-u-r-white.svg">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-svg\arrow-u-r-white.svg">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-svg\arrow-u-white.svg">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-svg\arrow-u-white.svg">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-svg\audio-black.svg">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-svg\audio-black.svg">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-svg\audio-white.svg">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-svg\audio-white.svg">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-svg\back-black.svg">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-svg\back-black.svg">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-svg\back-white.svg">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-svg\back-white.svg">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-svg\bars-black.svg">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-svg\bars-black.svg">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-svg\bars-white.svg">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-svg\bars-white.svg">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-svg\bullets-black.svg">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-svg\bullets-black.svg">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-svg\bullets-white.svg">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-svg\bullets-white.svg">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-svg\calendar-black.svg">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-svg\calendar-black.svg">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-svg\calendar-white.svg">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-svg\calendar-white.svg">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-svg\camera-black.svg">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-svg\camera-black.svg">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-svg\camera-white.svg">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-svg\camera-white.svg">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-svg\carat-d-black.svg">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-svg\carat-d-black.svg">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-svg\carat-d-white.svg">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-svg\carat-d-white.svg">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-svg\carat-l-black.svg">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-svg\carat-l-black.svg">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-svg\carat-l-white.svg">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-svg\carat-l-white.svg">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-svg\carat-r-black.svg">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-svg\carat-r-black.svg">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-svg\carat-r-white.svg">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-svg\carat-r-white.svg">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-svg\carat-u-black.svg">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-svg\carat-u-black.svg">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-svg\carat-u-white.svg">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-svg\carat-u-white.svg">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-svg\check-black.svg">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-svg\check-black.svg">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-svg\check-white.svg">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-svg\check-white.svg">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-svg\clock-black.svg">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-svg\clock-black.svg">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-svg\clock-white.svg">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-svg\clock-white.svg">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-svg\cloud-black.svg">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-svg\cloud-black.svg">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-svg\cloud-white.svg">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-svg\cloud-white.svg">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-svg\comment-black.svg">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-svg\comment-black.svg">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-svg\comment-white.svg">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-svg\comment-white.svg">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-svg\delete-black.svg">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-svg\delete-black.svg">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-svg\delete-white.svg">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-svg\delete-white.svg">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-svg\edit-black.svg">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-svg\edit-black.svg">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-svg\edit-white.svg">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-svg\edit-white.svg">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-svg\eye-black.svg">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-svg\eye-black.svg">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-svg\eye-white.svg">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-svg\eye-white.svg">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-svg\forbidden-black.svg">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-svg\forbidden-black.svg">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-svg\forbidden-white.svg">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-svg\forbidden-white.svg">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-svg\forward-black.svg">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-svg\forward-black.svg">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-svg\forward-white.svg">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-svg\forward-white.svg">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-svg\gear-black.svg">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-svg\gear-black.svg">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-svg\gear-white.svg">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-svg\gear-white.svg">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-svg\grid-black.svg">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-svg\grid-black.svg">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-svg\grid-white.svg">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-svg\grid-white.svg">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-svg\heart-black.svg">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-svg\heart-black.svg">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-svg\heart-white.svg">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-svg\heart-white.svg">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-svg\home-black.svg">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-svg\home-black.svg">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-svg\home-white.svg">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-svg\home-white.svg">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-svg\info-black.svg">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-svg\info-black.svg">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-svg\info-white.svg">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-svg\info-white.svg">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-svg\location-black.svg">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-svg\location-black.svg">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-svg\location-white.svg">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-svg\location-white.svg">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-svg\lock-black.svg">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-svg\lock-black.svg">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-svg\lock-white.svg">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-svg\lock-white.svg">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-svg\mail-black.svg">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-svg\mail-black.svg">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-svg\mail-white.svg">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-svg\mail-white.svg">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-svg\minus-black.svg">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-svg\minus-black.svg">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-svg\minus-white.svg">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-svg\minus-white.svg">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-svg\navigation-black.svg">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-svg\navigation-black.svg">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-svg\navigation-white.svg">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-svg\navigation-white.svg">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-svg\phone-black.svg">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-svg\phone-black.svg">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-svg\phone-white.svg">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-svg\phone-white.svg">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-svg\plus-black.svg">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-svg\plus-black.svg">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-svg\plus-white.svg">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-svg\plus-white.svg">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-svg\power-black.svg">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-svg\power-black.svg">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-svg\power-white.svg">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-svg\power-white.svg">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-svg\recycle-black.svg">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-svg\recycle-black.svg">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-svg\recycle-white.svg">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-svg\recycle-white.svg">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-svg\refresh-black.svg">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-svg\refresh-black.svg">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-svg\refresh-white.svg">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-svg\refresh-white.svg">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-svg\search-black.svg">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-svg\search-black.svg">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-svg\search-white.svg">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-svg\search-white.svg">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-svg\shop-black.svg">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-svg\shop-black.svg">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-svg\shop-white.svg">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-svg\shop-white.svg">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-svg\star-black.svg">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-svg\star-black.svg">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-svg\star-white.svg">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-svg\star-white.svg">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-svg\tag-black.svg">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-svg\tag-black.svg">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-svg\tag-white.svg">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-svg\tag-white.svg">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-svg\user-black.svg">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-svg\user-black.svg">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-svg\user-white.svg">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-svg\user-white.svg">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-svg\video-black.svg">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-svg\video-black.svg">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\images\icons-svg\video-white.svg">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\images\icons-svg\video-white.svg">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\jquery.mobile-1.4.1.min.css">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\jquery.mobile-1.4.2.min.css">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.1\jquery.mobile-1.4.1.min.js">
+    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.2\jquery.mobile-1.4.2.min.js">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
     <Content Include="dashboard-ui\thirdparty\jstree1.0\jquery.jstree.min.js">
     <Content Include="dashboard-ui\thirdparty\jstree1.0\jquery.jstree.min.js">

+ 2 - 2
Nuget/MediaBrowser.Common.Internal.nuspec

@@ -2,7 +2,7 @@
 <package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
 <package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
     <metadata>
     <metadata>
         <id>MediaBrowser.Common.Internal</id>
         <id>MediaBrowser.Common.Internal</id>
-        <version>3.0.333</version>
+        <version>3.0.335</version>
         <title>MediaBrowser.Common.Internal</title>
         <title>MediaBrowser.Common.Internal</title>
         <authors>Luke</authors>
         <authors>Luke</authors>
         <owners>ebr,Luke,scottisafool</owners>
         <owners>ebr,Luke,scottisafool</owners>
@@ -12,7 +12,7 @@
         <description>Contains common components shared by Media Browser Theater and Media Browser Server. Not intended for plugin developer consumption.</description>
         <description>Contains common components shared by Media Browser Theater and Media Browser Server. Not intended for plugin developer consumption.</description>
         <copyright>Copyright © Media Browser 2013</copyright>
         <copyright>Copyright © Media Browser 2013</copyright>
         <dependencies>
         <dependencies>
-            <dependency id="MediaBrowser.Common" version="3.0.333" />
+            <dependency id="MediaBrowser.Common" version="3.0.335" />
             <dependency id="NLog" version="2.1.0" />
             <dependency id="NLog" version="2.1.0" />
             <dependency id="SimpleInjector" version="2.4.1" />
             <dependency id="SimpleInjector" version="2.4.1" />
             <dependency id="sharpcompress" version="0.10.2" />
             <dependency id="sharpcompress" version="0.10.2" />

+ 1 - 1
Nuget/MediaBrowser.Common.nuspec

@@ -2,7 +2,7 @@
 <package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
 <package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
     <metadata>
     <metadata>
         <id>MediaBrowser.Common</id>
         <id>MediaBrowser.Common</id>
-        <version>3.0.333</version>
+        <version>3.0.335</version>
         <title>MediaBrowser.Common</title>
         <title>MediaBrowser.Common</title>
         <authors>Media Browser Team</authors>
         <authors>Media Browser Team</authors>
         <owners>ebr,Luke,scottisafool</owners>
         <owners>ebr,Luke,scottisafool</owners>

+ 2 - 2
Nuget/MediaBrowser.Server.Core.nuspec

@@ -2,7 +2,7 @@
 <package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
 <package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
     <metadata>
     <metadata>
         <id>MediaBrowser.Server.Core</id>
         <id>MediaBrowser.Server.Core</id>
-        <version>3.0.333</version>
+        <version>3.0.335</version>
         <title>Media Browser.Server.Core</title>
         <title>Media Browser.Server.Core</title>
         <authors>Media Browser Team</authors>
         <authors>Media Browser Team</authors>
         <owners>ebr,Luke,scottisafool</owners>
         <owners>ebr,Luke,scottisafool</owners>
@@ -12,7 +12,7 @@
         <description>Contains core components required to build plugins for Media Browser Server.</description>
         <description>Contains core components required to build plugins for Media Browser Server.</description>
         <copyright>Copyright © Media Browser 2013</copyright>
         <copyright>Copyright © Media Browser 2013</copyright>
         <dependencies>
         <dependencies>
-            <dependency id="MediaBrowser.Common" version="3.0.333" />
+            <dependency id="MediaBrowser.Common" version="3.0.335" />
         </dependencies>
         </dependencies>
     </metadata>
     </metadata>
     <files>
     <files>