소스 검색

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();
 
-            summary.ClientInstalledGameCount = games.Count(i => !i.IsInstalledOnClient);
+            summary.ClientInstalledGameCount = games.Count(i => !i.IsPlaceHolder);
 
             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)
                 .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.Library;
 using MediaBrowser.Controller.Persistence;
-using MediaBrowser.Controller.Providers;
 using MediaBrowser.Model.Dto;
 using MediaBrowser.Model.Entities;
-using MediaBrowser.Model.Providers;
 using MediaBrowser.Model.Querying;
 using ServiceStack;
 using System;
@@ -50,18 +48,6 @@ namespace MediaBrowser.Api.Library
         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>
     /// Class GetCriticReviews
     /// </summary>
@@ -256,29 +242,18 @@ namespace MediaBrowser.Api.Library
         private readonly IUserDataManager _userDataManager;
 
         private readonly IDtoService _dtoService;
-        private readonly IProviderManager _providerManager;
 
         /// <summary>
         /// Initializes a new instance of the <see cref="LibraryService" /> class.
         /// </summary>
         public LibraryService(IItemRepository itemRepo, ILibraryManager libraryManager, IUserManager userManager,
-                              IDtoService dtoService, IUserDataManager userDataManager, IProviderManager providerManager)
+                              IDtoService dtoService, IUserDataManager userDataManager)
         {
             _itemRepo = itemRepo;
             _libraryManager = libraryManager;
             _userManager = userManager;
             _dtoService = dtoService;
             _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)

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

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

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

@@ -265,7 +265,7 @@ namespace MediaBrowser.Api.Playback
 
                 if (cpuCount >= 4)
                 {
-                    return EncodingQuality.HighQuality;
+                    //return EncodingQuality.HighQuality;
                 }
 
                 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);
             }
+            
+              // 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);
 
@@ -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.
                     // 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);
 
@@ -1408,6 +1418,9 @@ namespace MediaBrowser.Api.Playback
 
             state.HasMediaStreams = mediaStreams.Count > 0;
 
+            state.SegmentLength = state.ReadInputAtNativeFramerate ? 3 : 10;
+            state.HlsListSize = state.ReadInputAtNativeFramerate ? 20 : 1440;
+
             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
             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,
                 inputModifier,
                 GetInputArgument(state),
@@ -296,6 +296,7 @@ namespace MediaBrowser.Api.Playback.Hls
                 GetAudioArguments(state),
                 state.SegmentLength.ToString(UsCulture),
                 startNumberParam,
+                state.HlsListSize.ToString(UsCulture),
                 outputPath
                 ).Trim();
 
@@ -307,11 +308,12 @@ namespace MediaBrowser.Api.Playback.Hls
 
                     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,
                         bitrate / 2,
                         state.SegmentLength.ToString(UsCulture),
                         startNumberParam,
+                        state.HlsListSize.ToString(UsCulture),
                         lowBitratePath);
 
                     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";
             }
 
-            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 &&
                                  (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 int SegmentLength = 10;
+        public int HlsListSize;
 
         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")]
         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>
@@ -332,7 +344,7 @@ namespace MediaBrowser.Api.UserLibrary
             var userId = user == null ? (Guid?)null : user.Id;
 
             var item = string.IsNullOrEmpty(request.ParentId) ?
-                user == null ? (BaseItem)_libraryManager.RootFolder : user.RootFolder :
+                user == null ? _libraryManager.RootFolder : user.RootFolder :
                 _dtoService.GetItemByDtoId(request.ParentId, userId);
 
             // Default list type = children
@@ -1019,6 +1031,18 @@ namespace MediaBrowser.Api.UserLibrary
                 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)
             {
                 var filterValue = request.ParentIndexNumber.Value;
@@ -1117,6 +1141,37 @@ namespace MediaBrowser.Api.UserLibrary
                 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;
         }
 

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

@@ -48,13 +48,13 @@
     <RunPostBuildEvent>Always</RunPostBuildEvent>
   </PropertyGroup>
   <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>
-      <HintPath>..\packages\SimpleInjector.2.4.1\lib\net45\SimpleInjector.dll</HintPath>
+      <HintPath>..\packages\SimpleInjector.2.5.0\lib\net45\SimpleInjector.dll</HintPath>
     </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>
-      <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 Include="System" />
     <Reference Include="System.Configuration" />

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

@@ -2,5 +2,5 @@
 <packages>
   <package id="NLog" version="2.1.0" 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>

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

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

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

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

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

@@ -352,6 +352,26 @@ namespace MediaBrowser.Controller.Entities
             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>
         /// Validates the children internal.
         /// </summary>
@@ -401,7 +421,7 @@ namespace MediaBrowser.Controller.Entities
                 {
                     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;
                         if (currentChildLocationType != LocationType.Remote &&

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

@@ -7,7 +7,7 @@ using System.Linq;
 
 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; }
 
@@ -63,10 +63,10 @@ namespace MediaBrowser.Controller.Entities
         public int? PlayersSupported { get; set; }
 
         /// <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>
-        /// <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>
         /// 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>
         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>
         /// Updates to repository.
         /// </summary>
@@ -55,5 +49,11 @@ namespace MediaBrowser.Controller.Entities
         /// </summary>
         /// <returns><c>true</c> if XXXX, <c>false</c> otherwise.</returns>
         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
             {
-                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>
     /// Class Video
     /// </summary>
-    public class Video : BaseItem, IHasMediaStreams, IHasAspectRatio, IHasTags
+    public class Video : BaseItem, IHasMediaStreams, IHasAspectRatio, IHasTags, ISupportsPlaceHolders
     {
         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>
         public bool HasSubtitles { get; set; }
 
+        public bool IsPlaceHolder { get; set; }
+        
         /// <summary>
         /// Gets or sets the tags.
         /// </summary>
@@ -108,10 +110,13 @@ namespace MediaBrowser.Controller.Entities
                     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;
@@ -257,10 +262,7 @@ namespace MediaBrowser.Controller.Entities
         {
             if (!IsInMixedFolder)
             {
-                if (VideoType == VideoType.VideoFile || VideoType == VideoType.Iso)
-                {
-                    return new[] { System.IO.Path.GetDirectoryName(Path) };
-                }
+                return new[] { ContainingFolderPath };
             }
 
             return base.GetDeletePaths();

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

@@ -234,9 +234,12 @@ namespace MediaBrowser.Controller.Library
                 {
                     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\ImageSourceInfo.cs" />
     <Compile Include="Entities\IMetadataContainer.cs" />
+    <Compile Include="Entities\ISupportsPlaceHolders.cs" />
     <Compile Include="Entities\ItemImageInfo.cs" />
     <Compile Include="Entities\LinkedChild.cs" />
     <Compile Include="Entities\MusicVideo.cs" />

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

@@ -34,6 +34,7 @@ namespace MediaBrowser.Controller.MediaEncoding
             {
                 case VideoType.BluRay:
                     type = InputType.Bluray;
+                    inputPath = GetPlayableStreamFiles(inputPath[0], playableStreamFileNames).ToArray();
                     break;
                 case VideoType.Dvd:
                     type = InputType.Dvd;
@@ -46,6 +47,7 @@ namespace MediaBrowser.Controller.MediaEncoding
                         {
                             case IsoType.BluRay:
                                 type = InputType.Bluray;
+                                inputPath = GetPlayableStreamFiles(inputPath[0], playableStreamFileNames).ToArray();
                                 break;
                             case IsoType.Dvd:
                                 type = InputType.Dvd;
@@ -118,15 +120,16 @@ namespace MediaBrowser.Controller.MediaEncoding
             return type;
         }
 
-        public static Model.Entities.MediaInfo GetMediaInfo(InternalMediaInfoResult data)
+        public static MediaInfo GetMediaInfo(InternalMediaInfoResult data)
         {
             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)
             {
@@ -137,7 +140,7 @@ namespace MediaBrowser.Controller.MediaEncoding
         }
 
         private static readonly CultureInfo UsCulture = new CultureInfo("en-US");
-        
+
         /// <summary>
         /// Converts ffprobe stream info to our MediaStream class
         /// </summary>

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

@@ -779,7 +779,6 @@ namespace MediaBrowser.Controller.Providers
                     break;
 
                 case "TMDbCollectionId":
-                case "CollectionNumber":
                     var tmdbCollection = reader.ReadElementContentAsString();
                     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);
     }
+
+    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.Model.Configuration;
 using MediaBrowser.Model.Entities;
@@ -126,5 +127,14 @@ namespace MediaBrowser.Controller.Providers
             CancellationToken cancellationToken)
             where TItemType : BaseItem, new()
             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);
     }
 
-    public interface IRemoteSearchProvider<in TLookupInfoType> : IMetadataProvider
-        where TLookupInfoType : ItemLookupInfo
+    public interface IRemoteSearchProvider : IMetadataProvider
     {
-        Task<IEnumerable<RemoteSearchResult>> GetSearchResults(TLookupInfoType searchInfo, CancellationToken cancellationToken);
-
         /// <summary>
         /// Gets the image response.
         /// </summary>
@@ -31,6 +28,12 @@ namespace MediaBrowser.Controller.Providers
         /// <returns>Task{HttpResponseInfo}.</returns>
         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>
         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 (!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 type = string.Equals(extension, ".iso", StringComparison.OrdinalIgnoreCase) || string.Equals(extension, ".img", StringComparison.OrdinalIgnoreCase) ?
                         VideoType.Iso : VideoType.VideoFile;
 
-                    return new TVideoType
+                    var video = new TVideoType
                     {
                         VideoType = type,
                         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);
         }
 
+        /// <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>
         /// Ensures DateCreated and DateModified have values
         /// </summary>

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

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

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

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

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

@@ -48,6 +48,10 @@ namespace MediaBrowser.Model.Dto
         public string AwardSummary { get; set; }
 
         public float? Metascore { get; set; }
+
+        public bool IsUnidentified { get; set; }
+
+        public int? AnimeSeriesIndex { get; set; }
         
         /// <summary>
         /// Gets or sets the DVD season number.
@@ -204,6 +208,12 @@ namespace MediaBrowser.Model.Dto
         /// <value>The players.</value>
         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>
         /// Gets or sets the index number.
         /// </summary>

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

@@ -31,6 +31,8 @@ namespace MediaBrowser.Model.Providers
 
         public string SearchProviderName { get; set; }
 
+        public string GameSystem { get; set; }
+        
         public RemoteSearchResult()
         {
             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>
         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>
         /// Initializes a new instance of the <see cref="SystemInfo" /> class.
         /// </summary>

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

@@ -22,7 +22,6 @@ namespace MediaBrowser.Providers.BoxSets
 {
     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";
 
         internal static MovieDbBoxSetProvider Current;
@@ -32,20 +31,53 @@ namespace MediaBrowser.Providers.BoxSets
         private readonly IServerConfigurationManager _config;
         private readonly IFileSystem _fileSystem;
         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;
             _json = json;
             _config = config;
             _fileSystem = fileSystem;
             _localization = localization;
+            _httpClient = httpClient;
             Current = this;
         }
 
+        private readonly CultureInfo _usCulture = new CultureInfo("en-US");
+        
         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)
@@ -55,11 +87,13 @@ namespace MediaBrowser.Providers.BoxSets
             // We don't already have an Id, need to fetch it
             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)
                 {
-                    tmdbId = searchResult.id.ToString(_enUs);
+                    tmdbId = searchResult.GetProviderId(MetadataProviders.Tmdb);
                 }
             }
 
@@ -106,7 +140,7 @@ namespace MediaBrowser.Providers.BoxSets
                 Overview = obj.overview
             };
 
-            item.SetProviderId(MetadataProviders.Tmdb, obj.id.ToString(_enUs));
+            item.SetProviderId(MetadataProviders.Tmdb, obj.id.ToString(_usCulture));
 
             return item;
         }
@@ -219,10 +253,15 @@ namespace MediaBrowser.Providers.BoxSets
 
         private static string GetDataFilePath(IApplicationPaths appPaths, string tmdbId, string preferredLanguage)
         {
+            if (string.IsNullOrWhiteSpace(preferredLanguage))
+            {
+                throw new ArgumentNullException("preferredLanguage");
+            }
+
             var path = GetDataPath(appPaths, tmdbId);
 
             var filename = string.Format("all-{0}.json",
-                preferredLanguage ?? string.Empty);
+                preferredLanguage);
 
             return Path.Combine(path, filename);
         }
@@ -291,7 +330,12 @@ namespace MediaBrowser.Providers.BoxSets
 
         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.Controller.Configuration;
 using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.Providers;
 using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.Logging;
 using MediaBrowser.Providers.Manager;
 using System.Collections.Generic;
-using System.Threading;
-using System.Threading.Tasks;
 
 namespace MediaBrowser.Providers.Games
 {
     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)
         {
-            _libraryManager = libraryManager;
         }
 
         /// <summary>
@@ -38,6 +32,11 @@ namespace MediaBrowser.Providers.Games
             {
                 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()
             };
 
+            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();
             temp.Path = item.Path;
 
@@ -342,7 +349,7 @@ namespace MediaBrowser.Providers.Manager
                 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);
             }
@@ -379,6 +386,9 @@ namespace MediaBrowser.Providers.Manager
         {
             TIdType id = null;
 
+            var unidentifiedCount = 0;
+            var identifiedCount = 0;
+
             foreach (var provider in providers)
             {
                 var providerName = provider.GetType().Name;
@@ -402,9 +412,12 @@ namespace MediaBrowser.Providers.Manager
                         MergeData(result.Item, temp, new List<MetadataFields>(), false, false);
 
                         refreshResult.UpdateType = refreshResult.UpdateType | ItemUpdateType.MetadataDownload;
+
+                        identifiedCount++;
                     }
                     else
                     {
+                        unidentifiedCount++; 
                         Logger.Debug("{0} returned no metadata for {1}", providerName, item.Path ?? item.Name);
                     }
                 }
@@ -414,11 +427,20 @@ namespace MediaBrowser.Providers.Manager
                 }
                 catch (Exception ex)
                 {
+                    unidentifiedCount++; 
                     refreshResult.Status = ProviderRefreshStatus.CompletedWithErrors;
                     refreshResult.ErrorMessage = ex.Message;
                     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)

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

@@ -492,7 +492,7 @@ namespace MediaBrowser.Providers.Manager
                     Type = MetadataPluginType.MetadataFetcher
                 }));
             }
-            
+
             if (item.IsSaveLocalMetadataEnabled())
             {
                 // Savers
@@ -657,15 +657,24 @@ namespace MediaBrowser.Providers.Manager
                 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)
             {
-                var results = await provider.GetSearchResults(searchInfo.SearchInfo, cancellationToken).ConfigureAwait(false);
+                var results = await GetSearchResults(provider, searchInfo.SearchInfo, cancellationToken).ConfigureAwait(false);
 
                 var list = results.ToList();
 
                 if (list.Count > 0)
                 {
-                    return list;
+                    return list.Take(10);
                 }
             }
 
@@ -673,6 +682,34 @@ namespace MediaBrowser.Providers.Manager
             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)
         {
             return _externalIds.Where(i =>

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

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

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

@@ -126,6 +126,11 @@ namespace MediaBrowser.Providers.MediaInfo
                 return _cachedTask;
             }
 
+            if (item.IsPlaceHolder)
+            {
+                return _cachedTask;
+            }
+
             var prober = new FFProbeVideoInfo(_logger, _isoManager, _mediaEncoder, _itemRepo, _blurayExaminer, _localization, _appPaths, _json, _encodingManager);
 
             return prober.ProbeVideo(item, directoryService, cancellationToken);
@@ -155,7 +160,7 @@ namespace MediaBrowser.Providers.MediaInfo
             {
                 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);
 

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

@@ -53,9 +53,18 @@ namespace MediaBrowser.Providers.MediaInfo
         {
             var isoMount = await MountIsoIfNeeded(item, cancellationToken).ConfigureAwait(false);
 
+            BlurayDiscInfo blurayDiscInfo = null;
+
             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 (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);
 
                 cancellationToken.ThrowIfCancellationRequested();
@@ -75,7 +93,7 @@ namespace MediaBrowser.Providers.MediaInfo
 
                 cancellationToken.ThrowIfCancellationRequested();
 
-                await Fetch(item, cancellationToken, result, isoMount, directoryService).ConfigureAwait(false);
+                await Fetch(item, cancellationToken, result, isoMount, blurayDiscInfo, directoryService).ConfigureAwait(false);
 
             }
             finally
@@ -128,7 +146,7 @@ namespace MediaBrowser.Providers.MediaInfo
             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)
             {
@@ -147,8 +165,7 @@ namespace MediaBrowser.Providers.MediaInfo
 
             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);
@@ -183,14 +200,10 @@ namespace MediaBrowser.Providers.MediaInfo
             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 result = GetBDInfo(inputPath);
-
-            cancellationToken.ThrowIfCancellationRequested();
-
             int? currentHeight = null;
             int? currentWidth = null;
             int? currentBitRate = null;
@@ -206,51 +219,43 @@ namespace MediaBrowser.Providers.MediaInfo
             }
 
             // 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.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.AddRange(stream.Chapters.Select(c => new ChapterInfo
+                chapters.AddRange(blurayInfo.Chapters.Select(c => new ChapterInfo
                 {
                     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>
@@ -498,7 +503,7 @@ namespace MediaBrowser.Providers.MediaInfo
         /// </summary>
         /// <param name="item">The item.</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)
             {
@@ -509,6 +514,11 @@ namespace MediaBrowser.Providers.MediaInfo
             {
                 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)

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

@@ -56,7 +56,7 @@ namespace MediaBrowser.Providers.MediaInfo
             var video = (Video)item;
 
             // No support for this
-            if (video.VideoType == VideoType.HdDvd)
+            if (video.VideoType == VideoType.HdDvd || video.IsPlaceHolder)
             {
                 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>
         internal static string GetMoviesDataPath(IApplicationPaths appPaths)
         {
-            var dataPath = Path.Combine(appPaths.DataPath, "fanart-movies");
+            var dataPath = Path.Combine(appPaths.CachePath, "fanart-movies");
 
             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. 
             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)
                 {
-                    tmdbId = searchResult.id.ToString(_usCulture);
+                    tmdbId = searchResult.GetProviderId(MetadataProviders.Tmdb);
                 }
             }
 
@@ -174,11 +176,16 @@ namespace MediaBrowser.Providers.Movies
                                                        : 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

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

@@ -12,6 +12,7 @@ using MediaBrowser.Model.Providers;
 using MediaBrowser.Model.Serialization;
 using System;
 using System.Collections.Generic;
+using System.Globalization;
 using System.IO;
 using System.Linq;
 using System.Threading;
@@ -35,6 +36,8 @@ namespace MediaBrowser.Providers.Movies
         private readonly ILogger _logger;
         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)
         {
             _jsonSerializer = jsonSerializer;
@@ -46,9 +49,59 @@ namespace MediaBrowser.Providers.Movies
             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)
@@ -57,7 +110,7 @@ namespace MediaBrowser.Providers.Movies
         }
 
         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);
 
@@ -347,10 +400,10 @@ namespace MediaBrowser.Providers.Movies
                 var dataFilePath = GetDataFilePath(tmdbId, item.GetPreferredMetadataLanguage());
 
                 var fileInfo = new FileInfo(dataFilePath);
-                
+
                 return !fileInfo.Exists || _fileSystem.GetLastWriteTimeUtc(fileInfo) > date;
             }
-            
+
             return false;
         }
 
@@ -530,7 +583,7 @@ namespace MediaBrowser.Providers.Movies
             public string poster_path { get; set; }
             public List<ProductionCompany> production_companies { 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 runtime { 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)
         {
-            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.Controller.Providers;
+using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.Logging;
+using MediaBrowser.Model.Providers;
 using MediaBrowser.Model.Serialization;
 using System;
 using System.Collections.Generic;
@@ -29,27 +31,31 @@ namespace MediaBrowser.Providers.Movies
             _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 year = idInfo.Year;
             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);
 
             year = year ?? yearInName;
@@ -60,48 +66,57 @@ namespace MediaBrowser.Providers.Movies
             //nope - search for it
             //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
-                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);
 
@@ -113,67 +128,62 @@ namespace MediaBrowser.Providers.Movies
 
             }).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>
         /// Class TmdbMovieSearchResult
         /// </summary>

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

@@ -11,14 +11,21 @@ namespace MediaBrowser.Providers.Movies
 {
     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)
         {
             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
@@ -42,7 +49,12 @@ namespace MediaBrowser.Providers.Movies
 
         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>
         internal static string GetArtistDataPath(IApplicationPaths appPaths)
         {
-            var dataPath = Path.Combine(appPaths.DataPath, "fanart-music");
+            var dataPath = Path.Combine(appPaths.CachePath, "fanart-music");
 
             return dataPath;
         }

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

@@ -29,12 +29,14 @@ namespace MediaBrowser.Providers.People
         private readonly IJsonSerializer _jsonSerializer;
         private readonly IFileSystem _fileSystem;
         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;
             _configurationManager = configurationManager;
             _jsonSerializer = jsonSerializer;
+            _httpClient = httpClient;
             Current = this;
         }
 
@@ -64,6 +66,8 @@ namespace MediaBrowser.Providers.People
                 {
                     Name = info.name,
 
+                    SearchProviderName = Name,
+                    
                     ImageUrl = images.Count == 0 ? null : (tmdbImageUrl + images[0].file_path)
                 };
 
@@ -94,6 +98,8 @@ namespace MediaBrowser.Providers.People
         {
             var result = new RemoteSearchResult
             {
+                SearchProviderName = Name,
+                
                 Name = i.Name,
 
                 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)
         {
-            return Path.Combine(appPaths.DataPath, "tmdb-people");
+            return Path.Combine(appPaths.CachePath, "tmdb-people");
         }
 
         #region Result Objects
@@ -349,7 +355,12 @@ namespace MediaBrowser.Providers.People
 
         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.Library;
 using MediaBrowser.Model.Entities;
@@ -36,6 +37,8 @@ namespace MediaBrowser.Providers.Savers
             return item is Series && updateType >= ItemUpdateType.MetadataDownload;
         }
 
+        private static readonly CultureInfo UsCulture = new CultureInfo("en-US");
+        
         /// <summary>
         /// Saves the specified item.
         /// </summary>
@@ -94,6 +97,11 @@ namespace MediaBrowser.Providers.Savers
                 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);
 
             builder.Append("</Series>");
@@ -111,7 +119,8 @@ namespace MediaBrowser.Providers.Savers
                     "FirstAired",
 
                     // 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>
         internal static string GetSeriesDataPath(IApplicationPaths appPaths)
         {
-            var dataPath = Path.Combine(appPaths.DataPath, "fanart-tv");
+            var dataPath = Path.Combine(appPaths.CachePath, "fanart-tv");
 
             return dataPath;
         }

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

@@ -105,12 +105,15 @@ namespace MediaBrowser.Providers.TV
                 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)

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

@@ -21,7 +21,7 @@ using System.Threading.Tasks;
 
 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 readonly CultureInfo _usCulture = new CultureInfo("en-US");
@@ -33,14 +33,16 @@ namespace MediaBrowser.Providers.TV
         private readonly IServerConfigurationManager _configurationManager;
         private readonly ILogger _logger;
         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;
             _fileSystem = fileSystem;
             _configurationManager = configurationManager;
             _logger = logger;
             _localization = localization;
+            _httpClient = httpClient;
             Current = this;
         }
 
@@ -51,7 +53,64 @@ namespace MediaBrowser.Providers.TV
 
         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)
@@ -66,7 +125,12 @@ namespace MediaBrowser.Providers.TV
 
                 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))
                 {
-                    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))
             {
-                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)
                 {
-                    tmdbId = searchResult.id.ToString(_usCulture);
+                    tmdbId = searchResult.GetProviderId(MetadataProviders.Tmdb);
                 }
             }
 
@@ -98,7 +169,7 @@ namespace MediaBrowser.Providers.TV
 
                 result.HasMetadata = result.Item != null;
             }
-            
+
             return result;
         }
 
@@ -119,7 +190,7 @@ namespace MediaBrowser.Providers.TV
 
             tmdbId = seriesInfo.id.ToString(_usCulture);
 
-            dataFilePath = MovieDbProvider.Current.GetDataFilePath(tmdbId, language);
+            dataFilePath = GetDataFilePath(tmdbId, language);
             Directory.CreateDirectory(Path.GetDirectoryName(dataFilePath));
             _jsonSerializer.SerializeToFile(seriesInfo, dataFilePath);
 
@@ -147,7 +218,7 @@ namespace MediaBrowser.Providers.TV
                 series.CommunityRating = rating;
             }
 
-           series.Overview =  seriesInfo.overview;
+            series.Overview = seriesInfo.overview;
 
             if (seriesInfo.networks != null)
             {
@@ -206,7 +277,7 @@ namespace MediaBrowser.Providers.TV
 
             return dataPath;
         }
-        
+
         internal async Task DownloadSeriesInfo(string id, string preferredMetadataLanguage, CancellationToken cancellationToken)
         {
             var mainResult = await FetchMainResult(id, preferredMetadataLanguage, cancellationToken).ConfigureAwait(false);
@@ -241,7 +312,7 @@ namespace MediaBrowser.Providers.TV
 
                 url += string.Format("&language={0}", language);
             }
-            
+
             // Get images in english and with no language
             url += "&include_image_language=" + string.Join(",", imageLanguages.ToArray());
 
@@ -258,7 +329,7 @@ namespace MediaBrowser.Providers.TV
                 return _jsonSerializer.DeserializeFromStream<RootObject>(json);
             }
         }
-        
+
         private readonly Task _cachedTask = Task.FromResult(true);
         internal Task EnsureSeriesInfo(string tmdbId, string language, CancellationToken cancellationToken)
         {
@@ -328,10 +399,10 @@ namespace MediaBrowser.Providers.TV
             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,
                 externalSource);
 
@@ -351,7 +422,19 @@ namespace MediaBrowser.Providers.TV
 
                     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)
         {
-            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;
                     }
 
+                case "AnimeSeriesIndex":
+                    {
+                        var number = reader.ReadElementContentAsString();
+
+                        if (!string.IsNullOrWhiteSpace(number))
+                        {
+                            int num;
+
+                            if (int.TryParse(number, out num))
+                            {
+                                item.AnimeSeriesIndex = num;
+                            }
+                        }
+                        break;
+                    }
                 case "SeriesName":
                     item.Name = reader.ReadElementContentAsString();
                     break;

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

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

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

@@ -73,6 +73,12 @@ namespace MediaBrowser.Providers.TV
         /// <returns>Task.</returns>
         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));
 
             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)
         {
+            var seriesId = searchInfo.GetProviderId(MetadataProviders.Tvdb);
+
+            if (!string.IsNullOrEmpty(seriesId))
+            {
+            }
+            
             return new List<RemoteSearchResult>();
         }
 
@@ -999,7 +1005,7 @@ namespace MediaBrowser.Providers.TV
         /// <returns>System.String.</returns>
         internal static string GetSeriesDataPath(IApplicationPaths appPaths)
         {
-            var dataPath = Path.Combine(appPaths.DataPath, "tvdb-v3");
+            var dataPath = Path.Combine(appPaths.CachePath, "tvdb");
 
             return dataPath;
         }
@@ -1092,7 +1098,12 @@ namespace MediaBrowser.Providers.TV
 
         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.IsUnidentified = item.IsUnidentified;
 
             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
             var audio = item as Audio;
             if (audio != null)
@@ -1092,6 +1099,8 @@ namespace MediaBrowser.Server.Implementations.Dto
                 {
                     dto.DisplaySpecialsWithSeasons = series.DisplaySpecialsWithSeasons;
                 }
+
+                dto.AnimeSeriesIndex = series.AnimeSeriesIndex;
             }
 
             if (episode != null)

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

@@ -42,7 +42,7 @@ namespace MediaBrowser.Server.Implementations.EntryPoints
 
         public void Run()
         {
-            NatUtility.Logger = new LogWriter(_logger);
+            //NatUtility.Logger = new LogWriter(_logger);
             
             Reload();
         }
@@ -64,17 +64,17 @@ namespace MediaBrowser.Server.Implementations.EntryPoints
 
         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)
@@ -88,7 +88,7 @@ namespace MediaBrowser.Server.Implementations.EntryPoints
             }
             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)
         {
-            _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)
             {

+ 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())
                 {
@@ -922,6 +922,9 @@ namespace MediaBrowser.Server.Implementations.Library
         /// <returns>Task.</returns>
         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);
         }
 
@@ -933,6 +936,9 @@ namespace MediaBrowser.Server.Implementations.Library
         /// <returns>Task.</returns>
         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);
         }
 
@@ -944,6 +950,9 @@ namespace MediaBrowser.Server.Implementations.Library
         /// <returns>Task.</returns>
         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);
         }
 
@@ -955,6 +964,9 @@ namespace MediaBrowser.Server.Implementations.Library
         /// <returns>Task.</returns>
         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);
         }
 
@@ -966,6 +978,9 @@ namespace MediaBrowser.Server.Implementations.Library
         /// <returns>Task.</returns>
         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);
         }
 
@@ -977,6 +992,9 @@ namespace MediaBrowser.Server.Implementations.Library
         /// <returns>Task.</returns>
         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);
         }
 

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

@@ -132,6 +132,7 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Audio
                     return true;
                 }
                 if (EntityResolutionHelper.IsVideoFile(fullName)) return false;
+                if (EntityResolutionHelper.IsVideoPlaceHolder(fullName)) return false;
             }
 
             //  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.Library;
 using MediaBrowser.Controller.LiveTv;
-using MediaBrowser.Controller.MediaEncoding;
 using MediaBrowser.Controller.Persistence;
 using MediaBrowser.Controller.Providers;
 using MediaBrowser.Controller.Sorting;
@@ -49,7 +48,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
         private List<Guid> _channelIdList = new List<Guid>();
         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)
         {

+ 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>
         private bool IsEligibleForChapterImageExtraction(Video video)
         {
+            if (video.IsPlaceHolder)
+            {
+                return false;
+            }
+
             if (video is Movie)
             {
                 if (!_config.Configuration.EnableMovieChapterImageExtraction)

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

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

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

@@ -34,9 +34,7 @@ namespace MediaBrowser.Server.Implementations.ScheduledTasks
         {
             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 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
                 }
+
+                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,
                 SupportsAutoRunAtStartup = SupportsAutoRunAtStartup,
                 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 string GetWanAddress()
         {
-            var ip = WanAddressEntryPoint.WanAddress;
+            var ip = ServerConfigurationManager.Configuration.WanDdns;
+
+            if (string.IsNullOrWhiteSpace(ip))
+            {
+                ip = WanAddressEntryPoint.WanAddress;
+            }
 
             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;

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

@@ -11,6 +11,7 @@ namespace MediaBrowser.ServerApplication.FFMpeg
     {
         // Windows builds: http://ffmpeg.zeranoe.com/builds/
         // Linux builds: http://ffmpeg.gusari.org/static/
+        // OS X builds: http://ffmpegmac.net/
 
         public static string Version = ffmpegOsType("Version");
 
@@ -31,7 +32,7 @@ namespace MediaBrowser.ServerApplication.FFMpeg
                     switch (arg)
                     {
                         case "Version":
-                            return "20140105";
+                            return "20140304";
                         case "FFMpegFilename":
                             return "ffmpeg.exe";
                         case "FFProbeFilename":
@@ -68,7 +69,7 @@ namespace MediaBrowser.ServerApplication.FFMpeg
                             switch (arg)
                             {
                                 case "Version":
-                                    return "linux_x86_20140118";
+                                    return "20140304";
                                 case "FFMpegFilename":
                                     return "ffmpeg";
                                 case "FFProbeFilename":
@@ -84,7 +85,7 @@ namespace MediaBrowser.ServerApplication.FFMpeg
                             switch (arg)
                             {
                                 case "Version":
-                                    return "linux_x86_64_20140118";
+                                    return "20140304";
                                 case "FFMpegFilename":
                                     return "ffmpeg";
                                 case "FFProbeFilename":
@@ -97,7 +98,7 @@ namespace MediaBrowser.ServerApplication.FFMpeg
                     }
                     // Unsupported Unix platform
                     return "";
-                #endif
+#endif
             }
             return "";
         }
@@ -111,8 +112,8 @@ namespace MediaBrowser.ServerApplication.FFMpeg
                 case PlatformID.Win32NT:
                     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__
@@ -121,7 +122,7 @@ namespace MediaBrowser.ServerApplication.FFMpeg
                     {
                         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[]
                             {
-                                "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[]
                             {
-                                "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 
                     return new string[] {};
-                    #endif
+#endif
             }
             return new string[] {};
         }

+ 8 - 5
MediaBrowser.ServerApplication/LibraryViewer.cs

@@ -84,7 +84,8 @@ namespace MediaBrowser.ServerApplication
         {
             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);
 
             foreach (Folder folder in children)
@@ -94,9 +95,9 @@ namespace MediaBrowser.ServerApplication
 
                 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);
-                AddChildren(node, subChildren, _currentUser);
+                AddChildren(node, subChildren, _currentUser, isPhysical);
                 node.Text = currentFolder.Name + " (" +
                             node.Nodes.Count + ")";
 
@@ -110,7 +111,7 @@ namespace MediaBrowser.ServerApplication
         /// <param name="parent">The parent.</param>
         /// <param name="children">The children.</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)
             {
@@ -120,7 +121,9 @@ namespace MediaBrowser.ServerApplication
                 {
                     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 + ")";
                 }
                 else

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

@@ -416,7 +416,7 @@ namespace MediaBrowser.WebDashboard.Api
 
             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
                             };
 
@@ -456,8 +456,6 @@ namespace MediaBrowser.WebDashboard.Api
         /// <returns>Task{Stream}.</returns>
         private async Task<Stream> GetAllJavascript()
         {
-            var assembly = GetType().Assembly;
-
             var scriptFiles = new[]
                                   {
                                       "extensions.js",
@@ -497,6 +495,7 @@ namespace MediaBrowser.WebDashboard.Api
                                       "itemgallery.js",
                                       "itemlistpage.js",
                                       "librarypathmapping.js",
+                                      "libraryreport.js",
                                       "librarysettings.js",
                                       "livetvchannel.js",
                                       "livetvchannels.js",
@@ -570,7 +569,7 @@ namespace MediaBrowser.WebDashboard.Api
             var newLineBytes = Encoding.UTF8.GetBytes(Environment.NewLine);
 
             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 versionBytes = Encoding.UTF8.GetBytes(versionString);
@@ -580,6 +579,7 @@ namespace MediaBrowser.WebDashboard.Api
 
             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);
 
             foreach (var file in scriptFiles)

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

@@ -84,7 +84,9 @@
     </ProjectReference>
   </ItemGroup>
   <ItemGroup>
-    <EmbeddedResource Include="ApiClient.js" />
+    <EmbeddedResource Include="ApiClient.js">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </EmbeddedResource>
     <Content Include="dashboard-ui\advancedserversettings.html">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
@@ -196,6 +198,9 @@
     <Content Include="dashboard-ui\css\images\items\detail\tv.png">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
+    <Content Include="dashboard-ui\css\images\items\list\remotesearch.png">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
     <Content Include="dashboard-ui\css\images\media\tvflyout.png">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
@@ -220,6 +225,9 @@
     <Content Include="dashboard-ui\librarypathmapping.html">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
+    <Content Include="dashboard-ui\libraryreport.html">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
     <Content Include="dashboard-ui\livetvchannel.html">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
@@ -487,6 +495,9 @@
     <Content Include="dashboard-ui\scripts\librarypathmapping.js">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
+    <Content Include="dashboard-ui\scripts\libraryreport.js">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
     <Content Include="dashboard-ui\scripts\livetvchannel.js">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
@@ -574,613 +585,613 @@
     <Content Include="dashboard-ui\thirdparty\jquery-2.0.3.min.js">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </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>
     </Content>
     <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">
     <metadata>
         <id>MediaBrowser.Common.Internal</id>
-        <version>3.0.333</version>
+        <version>3.0.335</version>
         <title>MediaBrowser.Common.Internal</title>
         <authors>Luke</authors>
         <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>
         <copyright>Copyright © Media Browser 2013</copyright>
         <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="SimpleInjector" version="2.4.1" />
             <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">
     <metadata>
         <id>MediaBrowser.Common</id>
-        <version>3.0.333</version>
+        <version>3.0.335</version>
         <title>MediaBrowser.Common</title>
         <authors>Media Browser Team</authors>
         <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">
     <metadata>
         <id>MediaBrowser.Server.Core</id>
-        <version>3.0.333</version>
+        <version>3.0.335</version>
         <title>Media Browser.Server.Core</title>
         <authors>Media Browser Team</authors>
         <owners>ebr,Luke,scottisafool</owners>
@@ -12,7 +12,7 @@
         <description>Contains core components required to build plugins for Media Browser Server.</description>
         <copyright>Copyright © Media Browser 2013</copyright>
         <dependencies>
-            <dependency id="MediaBrowser.Common" version="3.0.333" />
+            <dependency id="MediaBrowser.Common" version="3.0.335" />
         </dependencies>
     </metadata>
     <files>