浏览代码

Merge pull request #2186 from MediaBrowser/dev

Dev
Luke 8 年之前
父节点
当前提交
888d17635a
共有 29 个文件被更改,包括 303 次插入113 次删除
  1. 18 2
      MediaBrowser.Api/Library/LibraryStructureService.cs
  2. 1 1
      MediaBrowser.Api/Playback/BaseStreamingService.cs
  3. 0 5
      MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs
  4. 1 1
      MediaBrowser.Controller/Entities/Audio/Audio.cs
  5. 2 2
      MediaBrowser.Controller/Entities/BaseItem.cs
  6. 18 13
      MediaBrowser.Controller/Entities/CollectionFolder.cs
  7. 1 1
      MediaBrowser.Controller/Entities/Video.cs
  8. 3 3
      MediaBrowser.Controller/Library/ILibraryManager.cs
  9. 3 1
      MediaBrowser.Controller/Providers/MetadataResult.cs
  10. 8 0
      MediaBrowser.Model/Configuration/LibraryOptions.cs
  11. 43 1
      MediaBrowser.Providers/Manager/MetadataService.cs
  12. 6 2
      MediaBrowser.Providers/Omdb/OmdbItemProvider.cs
  13. 2 1
      MediaBrowser.Providers/TV/Omdb/OmdbEpisodeProvider.cs
  14. 7 0
      MediaBrowser.Providers/TV/TheMovieDb/MovieDbEpisodeProvider.cs
  15. 18 7
      MediaBrowser.Providers/TV/TheMovieDb/MovieDbSeriesProvider.cs
  16. 12 0
      MediaBrowser.Providers/TV/TheTVDB/TvdbEpisodeProvider.cs
  17. 16 6
      MediaBrowser.Providers/TV/TheTVDB/TvdbSeriesProvider.cs
  18. 14 8
      MediaBrowser.Server.Implementations/Connect/ConnectManager.cs
  19. 2 2
      MediaBrowser.Server.Implementations/Dto/DtoService.cs
  20. 2 1
      MediaBrowser.Server.Implementations/Library/CoreResolutionIgnoreRule.cs
  21. 98 42
      MediaBrowser.Server.Implementations/Library/LibraryManager.cs
  22. 7 1
      MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs
  23. 1 1
      MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs
  24. 2 2
      MediaBrowser.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs
  25. 14 0
      MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs
  26. 2 2
      MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj
  27. 1 1
      MediaBrowser.Server.Implementations/packages.config
  28. 1 1
      MediaBrowser.WebDashboard/Api/PackageCreator.cs
  29. 0 6
      MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj

+ 18 - 2
MediaBrowser.Api/Library/LibraryStructureService.cs

@@ -112,6 +112,8 @@ namespace MediaBrowser.Api.Library
         /// <value>The name.</value>
         /// <value>The name.</value>
         public string Path { get; set; }
         public string Path { get; set; }
 
 
+        public MediaPathInfo PathInfo { get; set; }
+
         /// <summary>
         /// <summary>
         /// Gets or sets a value indicating whether [refresh library].
         /// Gets or sets a value indicating whether [refresh library].
         /// </summary>
         /// </summary>
@@ -212,7 +214,12 @@ namespace MediaBrowser.Api.Library
         {
         {
             var libraryOptions = request.LibraryOptions ?? new LibraryOptions();
             var libraryOptions = request.LibraryOptions ?? new LibraryOptions();
 
 
-            _libraryManager.AddVirtualFolder(request.Name, request.CollectionType, request.Paths, libraryOptions, request.RefreshLibrary);
+            if (request.Paths != null && request.Paths.Length > 0)
+            {
+                libraryOptions.PathInfos = request.Paths.Select(i => new MediaPathInfo { Path = i }).ToArray();
+            }
+
+            _libraryManager.AddVirtualFolder(request.Name, request.CollectionType, libraryOptions, request.RefreshLibrary);
         }
         }
 
 
         /// <summary>
         /// <summary>
@@ -308,7 +315,16 @@ namespace MediaBrowser.Api.Library
 
 
             try
             try
             {
             {
-                _libraryManager.AddMediaPath(request.Name, request.Path);
+                var mediaPath = request.PathInfo;
+
+                if (mediaPath == null)
+                {
+                    mediaPath = new MediaPathInfo
+                    {
+                        Path = request.Path
+                    };
+                }
+                _libraryManager.AddMediaPath(request.Name, mediaPath);
             }
             }
             finally
             finally
             {
             {

+ 1 - 1
MediaBrowser.Api/Playback/BaseStreamingService.cs

@@ -1241,7 +1241,7 @@ namespace MediaBrowser.Api.Playback
             }
             }
         }
         }
 
 
-        protected virtual bool EnableThrottling(StreamState state)
+        private bool EnableThrottling(StreamState state)
         {
         {
             // do not use throttling with hardware encoders
             // do not use throttling with hardware encoders
             return state.InputProtocol == MediaProtocol.File &&
             return state.InputProtocol == MediaProtocol.File &&

+ 0 - 5
MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs

@@ -922,11 +922,6 @@ namespace MediaBrowser.Api.Playback.Hls
                             ).Trim();
                             ).Trim();
         }
         }
 
 
-        protected override bool EnableThrottling(StreamState state)
-        {
-            return true;
-        }
-
         /// <summary>
         /// <summary>
         /// Gets the segment file extension.
         /// Gets the segment file extension.
         /// </summary>
         /// </summary>

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

@@ -262,7 +262,7 @@ namespace MediaBrowser.Controller.Entities.Audio
                 Protocol = locationType == LocationType.Remote ? MediaProtocol.Http : MediaProtocol.File,
                 Protocol = locationType == LocationType.Remote ? MediaProtocol.Http : MediaProtocol.File,
                 MediaStreams = MediaSourceManager.GetMediaStreams(i.Id).ToList(),
                 MediaStreams = MediaSourceManager.GetMediaStreams(i.Id).ToList(),
                 Name = i.Name,
                 Name = i.Name,
-                Path = enablePathSubstituion ? GetMappedPath(i.Path, locationType) : i.Path,
+                Path = enablePathSubstituion ? GetMappedPath(i, i.Path, locationType) : i.Path,
                 RunTimeTicks = i.RunTimeTicks,
                 RunTimeTicks = i.RunTimeTicks,
                 Container = i.Container,
                 Container = i.Container,
                 Size = i.Size
                 Size = i.Size

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

@@ -2121,11 +2121,11 @@ namespace MediaBrowser.Controller.Entities
             return hasChanges;
             return hasChanges;
         }
         }
 
 
-        protected static string GetMappedPath(string path, LocationType locationType)
+        protected static string GetMappedPath(BaseItem item, string path, LocationType locationType)
         {
         {
             if (locationType == LocationType.FileSystem || locationType == LocationType.Offline)
             if (locationType == LocationType.FileSystem || locationType == LocationType.Offline)
             {
             {
-                return LibraryManager.GetPathAfterNetworkSubstitution(path);
+                return LibraryManager.GetPathAfterNetworkSubstitution(path, item);
             }
             }
 
 
             return path;
             return path;

+ 18 - 13
MediaBrowser.Controller/Entities/CollectionFolder.cs

@@ -48,24 +48,14 @@ namespace MediaBrowser.Controller.Entities
         private static readonly Dictionary<string, LibraryOptions> LibraryOptions = new Dictionary<string, LibraryOptions>();
         private static readonly Dictionary<string, LibraryOptions> LibraryOptions = new Dictionary<string, LibraryOptions>();
         public LibraryOptions GetLibraryOptions()
         public LibraryOptions GetLibraryOptions()
         {
         {
-            lock (LibraryOptions)
-            {
-                LibraryOptions options;
-                if (!LibraryOptions.TryGetValue(Path, out options))
-                {
-                    options = LoadLibraryOptions();
-                    LibraryOptions[Path] = options;
-                }
-
-                return options;
-            }
+            return GetLibraryOptions(Path);
         }
         }
 
 
-        private LibraryOptions LoadLibraryOptions()
+        private static LibraryOptions LoadLibraryOptions(string path)
         {
         {
             try
             try
             {
             {
-                var result = XmlSerializer.DeserializeFromFile(typeof(LibraryOptions), GetLibraryOptionsPath(Path)) as LibraryOptions;
+                var result = XmlSerializer.DeserializeFromFile(typeof(LibraryOptions), GetLibraryOptionsPath(path)) as LibraryOptions;
 
 
                 if (result == null)
                 if (result == null)
                 {
                 {
@@ -100,6 +90,21 @@ namespace MediaBrowser.Controller.Entities
             SaveLibraryOptions(Path, options);
             SaveLibraryOptions(Path, options);
         }
         }
 
 
+        public static LibraryOptions GetLibraryOptions(string path)
+        {
+            lock (LibraryOptions)
+            {
+                LibraryOptions options;
+                if (!LibraryOptions.TryGetValue(path, out options))
+                {
+                    options = LoadLibraryOptions(path);
+                    LibraryOptions[path] = options;
+                }
+
+                return options;
+            }
+        }
+
         public static void SaveLibraryOptions(string path, LibraryOptions options)
         public static void SaveLibraryOptions(string path, LibraryOptions options)
         {
         {
             lock (LibraryOptions)
             lock (LibraryOptions)

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

@@ -600,7 +600,7 @@ namespace MediaBrowser.Controller.Entities
                 Protocol = locationType == LocationType.Remote ? MediaProtocol.Http : MediaProtocol.File,
                 Protocol = locationType == LocationType.Remote ? MediaProtocol.Http : MediaProtocol.File,
                 MediaStreams = mediaStreams,
                 MediaStreams = mediaStreams,
                 Name = GetMediaSourceName(i, mediaStreams),
                 Name = GetMediaSourceName(i, mediaStreams),
-                Path = enablePathSubstitution ? GetMappedPath(i.Path, locationType) : i.Path,
+                Path = enablePathSubstitution ? GetMappedPath(i, i.Path, locationType) : i.Path,
                 RunTimeTicks = i.RunTimeTicks,
                 RunTimeTicks = i.RunTimeTicks,
                 Video3DFormat = i.Video3DFormat,
                 Video3DFormat = i.Video3DFormat,
                 VideoType = i.VideoType,
                 VideoType = i.VideoType,

+ 3 - 3
MediaBrowser.Controller/Library/ILibraryManager.cs

@@ -506,7 +506,7 @@ namespace MediaBrowser.Controller.Library
         /// <returns>QueryResult&lt;BaseItem&gt;.</returns>
         /// <returns>QueryResult&lt;BaseItem&gt;.</returns>
         QueryResult<BaseItem> QueryItems(InternalItemsQuery query);
         QueryResult<BaseItem> QueryItems(InternalItemsQuery query);
 
 
-        string GetPathAfterNetworkSubstitution(string path);
+        string GetPathAfterNetworkSubstitution(string path, BaseItem ownerItem = null);
 
 
         /// <summary>
         /// <summary>
         /// Substitutes the path.
         /// Substitutes the path.
@@ -556,9 +556,9 @@ namespace MediaBrowser.Controller.Library
         /// <returns><c>true</c> if XXXX, <c>false</c> otherwise.</returns>
         /// <returns><c>true</c> if XXXX, <c>false</c> otherwise.</returns>
         bool IgnoreFile(FileSystemMetadata file, BaseItem parent);
         bool IgnoreFile(FileSystemMetadata file, BaseItem parent);
 
 
-        void AddVirtualFolder(string name, string collectionType, string[] mediaPaths, LibraryOptions options, bool refreshLibrary);
+        void AddVirtualFolder(string name, string collectionType, LibraryOptions options, bool refreshLibrary);
         void RemoveVirtualFolder(string name, bool refreshLibrary);
         void RemoveVirtualFolder(string name, bool refreshLibrary);
-        void AddMediaPath(string virtualFolderName, string path);
+        void AddMediaPath(string virtualFolderName, MediaPathInfo path);
         void RemoveMediaPath(string virtualFolderName, string path);
         void RemoveMediaPath(string virtualFolderName, string path);
 
 
         QueryResult<Tuple<BaseItem, ItemCounts>> GetGenres(InternalItemsQuery query);
         QueryResult<Tuple<BaseItem, ItemCounts>> GetGenres(InternalItemsQuery query);

+ 3 - 1
MediaBrowser.Controller/Providers/MetadataResult.cs

@@ -13,13 +13,15 @@ namespace MediaBrowser.Controller.Providers
         public MetadataResult()
         public MetadataResult()
         {
         {
             Images = new List<LocalImageInfo>();
             Images = new List<LocalImageInfo>();
+            ResultLanguage = "en";
         }
         }
 
 
         public List<PersonInfo> People { get; set; }
         public List<PersonInfo> People { get; set; }
 
 
         public bool HasMetadata { get; set; }
         public bool HasMetadata { get; set; }
         public T Item { get; set; }
         public T Item { get; set; }
-
+        public string ResultLanguage { get; set; }
+        public bool QueriedById { get; set; }
         public void AddPerson(PersonInfo p)
         public void AddPerson(PersonInfo p)
         {
         {
             if (People == null)
             if (People == null)

+ 8 - 0
MediaBrowser.Model/Configuration/LibraryOptions.cs

@@ -9,11 +9,19 @@
         public bool EnableChapterImageExtraction { get; set; }
         public bool EnableChapterImageExtraction { get; set; }
         public bool ExtractChapterImagesDuringLibraryScan { get; set; }
         public bool ExtractChapterImagesDuringLibraryScan { get; set; }
         public bool DownloadImagesInAdvance { get; set; }
         public bool DownloadImagesInAdvance { get; set; }
+        public MediaPathInfo[] PathInfos { get; set; }
 
 
         public LibraryOptions()
         public LibraryOptions()
         {
         {
             EnablePhotos = true;
             EnablePhotos = true;
             EnableRealtimeMonitor = true;
             EnableRealtimeMonitor = true;
+            PathInfos = new MediaPathInfo[] { };
         }
         }
     }
     }
+
+    public class MediaPathInfo
+    {
+        public string Path { get; set; }
+        public string NetworkPath { get; set; }
+    }
 }
 }

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

@@ -651,6 +651,8 @@ namespace MediaBrowser.Providers.Manager
         {
         {
             var refreshResult = new RefreshResult();
             var refreshResult = new RefreshResult();
 
 
+            var results = new List<MetadataResult<TItemType>>();
+
             foreach (var provider in providers)
             foreach (var provider in providers)
             {
             {
                 var providerName = provider.GetType().Name;
                 var providerName = provider.GetType().Name;
@@ -667,7 +669,7 @@ namespace MediaBrowser.Providers.Manager
 
 
                     if (result.HasMetadata)
                     if (result.HasMetadata)
                     {
                     {
-                        MergeData(result, temp, new List<MetadataFields>(), false, false);
+                        results.Add(result);
 
 
                         refreshResult.UpdateType = refreshResult.UpdateType | ItemUpdateType.MetadataDownload;
                         refreshResult.UpdateType = refreshResult.UpdateType | ItemUpdateType.MetadataDownload;
                     }
                     }
@@ -688,9 +690,49 @@ namespace MediaBrowser.Providers.Manager
                 }
                 }
             }
             }
 
 
+            var orderedResults = new List<MetadataResult<TItemType>>();
+            var preferredLanguage = NormalizeLanguage(id.MetadataLanguage);
+
+            // prioritize results with matching ResultLanguage
+            foreach (var result in results)
+            {
+                if (!result.QueriedById)
+                {
+                    break;
+                }
+
+                if (string.Equals(NormalizeLanguage(result.ResultLanguage), preferredLanguage, StringComparison.OrdinalIgnoreCase) && result.QueriedById)
+                {
+                    orderedResults.Add(result);
+                }
+            }
+
+            // add all other results
+            foreach (var result in results)
+            {
+                if (!orderedResults.Contains(result))
+                {
+                    orderedResults.Add(result);
+                }
+            }
+
+            foreach (var result in results)
+            {
+                MergeData(result, temp, new List<MetadataFields>(), false, false);
+            }
+
             return refreshResult;
             return refreshResult;
         }
         }
 
 
+        private string NormalizeLanguage(string language)
+        {
+            if (string.IsNullOrWhiteSpace(language))
+            {
+                return "en";
+            }
+            return language;
+        }
+
         private void MergeNewData(TItemType source, TIdType lookupInfo)
         private void MergeNewData(TItemType source, TIdType lookupInfo)
         {
         {
             // Copy new provider id's that may have been obtained
             // Copy new provider id's that may have been obtained

+ 6 - 2
MediaBrowser.Providers/Omdb/OmdbItemProvider.cs

@@ -212,13 +212,15 @@ namespace MediaBrowser.Providers.Omdb
         {
         {
             var result = new MetadataResult<Series>
             var result = new MetadataResult<Series>
             {
             {
-                Item = new Series()
+                Item = new Series(),
+                QueriedById = true
             };
             };
 
 
             var imdbId = info.GetProviderId(MetadataProviders.Imdb);
             var imdbId = info.GetProviderId(MetadataProviders.Imdb);
             if (string.IsNullOrWhiteSpace(imdbId))
             if (string.IsNullOrWhiteSpace(imdbId))
             {
             {
                 imdbId = await GetSeriesImdbId(info, cancellationToken).ConfigureAwait(false);
                 imdbId = await GetSeriesImdbId(info, cancellationToken).ConfigureAwait(false);
+                result.QueriedById = false;
             }
             }
 
 
             if (!string.IsNullOrEmpty(imdbId))
             if (!string.IsNullOrEmpty(imdbId))
@@ -251,13 +253,15 @@ namespace MediaBrowser.Providers.Omdb
         {
         {
             var result = new MetadataResult<T>
             var result = new MetadataResult<T>
             {
             {
-                Item = new T()
+                Item = new T(),
+                QueriedById = true
             };
             };
 
 
             var imdbId = info.GetProviderId(MetadataProviders.Imdb);
             var imdbId = info.GetProviderId(MetadataProviders.Imdb);
             if (string.IsNullOrWhiteSpace(imdbId))
             if (string.IsNullOrWhiteSpace(imdbId))
             {
             {
                 imdbId = await GetMovieImdbId(info, cancellationToken).ConfigureAwait(false);
                 imdbId = await GetMovieImdbId(info, cancellationToken).ConfigureAwait(false);
+                result.QueriedById = false;
             }
             }
 
 
             if (!string.IsNullOrEmpty(imdbId))
             if (!string.IsNullOrEmpty(imdbId))

+ 2 - 1
MediaBrowser.Providers/TV/Omdb/OmdbEpisodeProvider.cs

@@ -43,7 +43,8 @@ namespace MediaBrowser.Providers.TV
         {
         {
             var result = new MetadataResult<Episode>()
             var result = new MetadataResult<Episode>()
             {
             {
-                Item = new Episode()
+                Item = new Episode(),
+                QueriedById = true
             };
             };
 
 
             // Allowing this will dramatically increase scan times
             // Allowing this will dramatically increase scan times

+ 7 - 0
MediaBrowser.Providers/TV/TheMovieDb/MovieDbEpisodeProvider.cs

@@ -91,6 +91,13 @@ namespace MediaBrowser.Providers.TV
                 var response = await GetEpisodeInfo(seriesTmdbId, seasonNumber.Value, episodeNumber.Value, info.MetadataLanguage, cancellationToken).ConfigureAwait(false);
                 var response = await GetEpisodeInfo(seriesTmdbId, seasonNumber.Value, episodeNumber.Value, info.MetadataLanguage, cancellationToken).ConfigureAwait(false);
 
 
                 result.HasMetadata = true;
                 result.HasMetadata = true;
+                result.QueriedById = true;
+
+                if (!string.IsNullOrEmpty(response.overview))
+                {
+                    // if overview is non-empty, we can assume that localized data was returned
+                    result.ResultLanguage = info.MetadataLanguage;
+                }
 
 
                 var item = new Episode();
                 var item = new Episode();
                 result.Item = item;
                 result.Item = item;

+ 18 - 7
MediaBrowser.Providers/TV/TheMovieDb/MovieDbSeriesProvider.cs

@@ -119,6 +119,7 @@ namespace MediaBrowser.Providers.TV
         public async Task<MetadataResult<Series>> GetMetadata(SeriesInfo info, CancellationToken cancellationToken)
         public async Task<MetadataResult<Series>> GetMetadata(SeriesInfo info, CancellationToken cancellationToken)
         {
         {
             var result = new MetadataResult<Series>();
             var result = new MetadataResult<Series>();
+            result.QueriedById = true;
 
 
             var tmdbId = info.GetProviderId(MetadataProviders.Tmdb);
             var tmdbId = info.GetProviderId(MetadataProviders.Tmdb);
 
 
@@ -154,6 +155,7 @@ namespace MediaBrowser.Providers.TV
 
 
             if (string.IsNullOrEmpty(tmdbId))
             if (string.IsNullOrEmpty(tmdbId))
             {
             {
+                result.QueriedById = false;
                 var searchResults = await new MovieDbSearch(_logger, _jsonSerializer, _libraryManager).GetSearchResults(info, cancellationToken).ConfigureAwait(false);
                 var searchResults = await new MovieDbSearch(_logger, _jsonSerializer, _libraryManager).GetSearchResults(info, cancellationToken).ConfigureAwait(false);
 
 
                 var searchResult = searchResults.FirstOrDefault();
                 var searchResult = searchResults.FirstOrDefault();
@@ -168,7 +170,7 @@ namespace MediaBrowser.Providers.TV
             {
             {
                 cancellationToken.ThrowIfCancellationRequested();
                 cancellationToken.ThrowIfCancellationRequested();
 
 
-                result.Item = await FetchSeriesData(tmdbId, info.MetadataLanguage, info.MetadataCountryCode, cancellationToken).ConfigureAwait(false);
+                result = await FetchMovieData(tmdbId, info.MetadataLanguage, info.MetadataCountryCode, cancellationToken).ConfigureAwait(false);
 
 
                 result.HasMetadata = result.Item != null;
                 result.HasMetadata = result.Item != null;
             }
             }
@@ -176,7 +178,7 @@ namespace MediaBrowser.Providers.TV
             return result;
             return result;
         }
         }
 
 
-        private async Task<Series> FetchSeriesData(string tmdbId, string language, string preferredCountryCode, CancellationToken cancellationToken)
+        private async Task<MetadataResult<Series>> FetchMovieData(string tmdbId, string language, string preferredCountryCode, CancellationToken cancellationToken)
         {
         {
             string dataFilePath = null;
             string dataFilePath = null;
             RootObject seriesInfo = null;
             RootObject seriesInfo = null;
@@ -194,16 +196,18 @@ namespace MediaBrowser.Providers.TV
             tmdbId = seriesInfo.id.ToString(_usCulture);
             tmdbId = seriesInfo.id.ToString(_usCulture);
 
 
             dataFilePath = GetDataFilePath(tmdbId, language);
             dataFilePath = GetDataFilePath(tmdbId, language);
-			_fileSystem.CreateDirectory(Path.GetDirectoryName(dataFilePath));
+            _fileSystem.CreateDirectory(Path.GetDirectoryName(dataFilePath));
             _jsonSerializer.SerializeToFile(seriesInfo, dataFilePath);
             _jsonSerializer.SerializeToFile(seriesInfo, dataFilePath);
 
 
             await EnsureSeriesInfo(tmdbId, language, cancellationToken).ConfigureAwait(false);
             await EnsureSeriesInfo(tmdbId, language, cancellationToken).ConfigureAwait(false);
 
 
-            var item = new Series();
+            var result = new MetadataResult<Series>();
+            result.Item = new Series();
+            result.ResultLanguage = seriesInfo.ResultLanguage;
 
 
-            ProcessMainInfo(item, seriesInfo, preferredCountryCode);
+            ProcessMainInfo(result.Item, seriesInfo, preferredCountryCode);
 
 
-            return item;
+            return result;
         }
         }
 
 
         private void ProcessMainInfo(Series series, RootObject seriesInfo, string preferredCountryCode)
         private void ProcessMainInfo(Series series, RootObject seriesInfo, string preferredCountryCode)
@@ -324,7 +328,7 @@ namespace MediaBrowser.Providers.TV
 
 
             var dataFilePath = GetDataFilePath(id, preferredMetadataLanguage);
             var dataFilePath = GetDataFilePath(id, preferredMetadataLanguage);
 
 
-			_fileSystem.CreateDirectory(Path.GetDirectoryName(dataFilePath));
+            _fileSystem.CreateDirectory(Path.GetDirectoryName(dataFilePath));
 
 
             _jsonSerializer.SerializeToFile(mainResult, dataFilePath);
             _jsonSerializer.SerializeToFile(mainResult, dataFilePath);
         }
         }
@@ -354,6 +358,11 @@ namespace MediaBrowser.Providers.TV
             }).ConfigureAwait(false))
             }).ConfigureAwait(false))
             {
             {
                 mainResult = _jsonSerializer.DeserializeFromStream<RootObject>(json);
                 mainResult = _jsonSerializer.DeserializeFromStream<RootObject>(json);
+
+                if (!string.IsNullOrEmpty(language))
+                {
+                    mainResult.ResultLanguage = language;
+                }
             }
             }
 
 
             cancellationToken.ThrowIfCancellationRequested();
             cancellationToken.ThrowIfCancellationRequested();
@@ -385,6 +394,7 @@ namespace MediaBrowser.Providers.TV
                     var englishResult = _jsonSerializer.DeserializeFromStream<RootObject>(json);
                     var englishResult = _jsonSerializer.DeserializeFromStream<RootObject>(json);
 
 
                     mainResult.overview = englishResult.overview;
                     mainResult.overview = englishResult.overview;
+                    mainResult.ResultLanguage = "en";
                 }
                 }
             }
             }
 
 
@@ -627,6 +637,7 @@ namespace MediaBrowser.Providers.TV
             public ExternalIds external_ids { get; set; }
             public ExternalIds external_ids { get; set; }
             public Videos videos { get; set; }
             public Videos videos { get; set; }
             public ContentRatings content_ratings { get; set; }
             public ContentRatings content_ratings { get; set; }
+            public string ResultLanguage { get; set; }
         }
         }
 
 
         public int Order
         public int Order

+ 12 - 0
MediaBrowser.Providers/TV/TheTVDB/TvdbEpisodeProvider.cs

@@ -108,6 +108,7 @@ namespace MediaBrowser.Providers.TV
         public async Task<MetadataResult<Episode>> GetMetadata(EpisodeInfo searchInfo, CancellationToken cancellationToken)
         public async Task<MetadataResult<Episode>> GetMetadata(EpisodeInfo searchInfo, CancellationToken cancellationToken)
         {
         {
             var result = new MetadataResult<Episode>();
             var result = new MetadataResult<Episode>();
+            result.QueriedById = true;
 
 
             if (TvdbSeriesProvider.IsValidSeries(searchInfo.SeriesProviderIds) && 
             if (TvdbSeriesProvider.IsValidSeries(searchInfo.SeriesProviderIds) && 
 				(searchInfo.IndexNumber.HasValue || searchInfo.PremiereDate.HasValue))
 				(searchInfo.IndexNumber.HasValue || searchInfo.PremiereDate.HasValue))
@@ -713,6 +714,17 @@ namespace MediaBrowser.Providers.TV
 									}
 									}
 								}
 								}
 
 
+								break;
+							}
+						case "Language":
+							{
+								var val = reader.ReadElementContentAsString();
+
+								if (!string.IsNullOrWhiteSpace(val))
+								{
+                                    result.ResultLanguage = val;
+								}
+
 								break;
 								break;
 							}
 							}
 
 

+ 16 - 6
MediaBrowser.Providers/TV/TheTVDB/TvdbSeriesProvider.cs

@@ -93,9 +93,11 @@ namespace MediaBrowser.Providers.TV
         public async Task<MetadataResult<Series>> GetMetadata(SeriesInfo itemId, CancellationToken cancellationToken)
         public async Task<MetadataResult<Series>> GetMetadata(SeriesInfo itemId, CancellationToken cancellationToken)
         {
         {
             var result = new MetadataResult<Series>();
             var result = new MetadataResult<Series>();
+            result.QueriedById = true;
 
 
             if (!IsValidSeries(itemId.ProviderIds))
             if (!IsValidSeries(itemId.ProviderIds))
             {
             {
+                result.QueriedById = false;
                 await Identify(itemId).ConfigureAwait(false);
                 await Identify(itemId).ConfigureAwait(false);
             }
             }
 
 
@@ -159,7 +161,7 @@ namespace MediaBrowser.Providers.TV
             var seriesXmlPath = GetSeriesXmlPath(seriesProviderIds, metadataLanguage);
             var seriesXmlPath = GetSeriesXmlPath(seriesProviderIds, metadataLanguage);
             var actorsXmlPath = Path.Combine(seriesDataPath, "actors.xml");
             var actorsXmlPath = Path.Combine(seriesDataPath, "actors.xml");
 
 
-            FetchSeriesInfo(series, seriesXmlPath, cancellationToken);
+            FetchSeriesInfo(result, seriesXmlPath, cancellationToken);
 
 
             cancellationToken.ThrowIfCancellationRequested();
             cancellationToken.ThrowIfCancellationRequested();
 
 
@@ -607,7 +609,7 @@ namespace MediaBrowser.Providers.TV
             return name.Trim();
             return name.Trim();
         }
         }
 
 
-        private void FetchSeriesInfo(Series item, string seriesXmlPath, CancellationToken cancellationToken)
+        private void FetchSeriesInfo(MetadataResult<Series> result, string seriesXmlPath, CancellationToken cancellationToken)
         {
         {
             var settings = new XmlReaderSettings
             var settings = new XmlReaderSettings
             {
             {
@@ -639,7 +641,7 @@ namespace MediaBrowser.Providers.TV
                                     {
                                     {
                                         using (var subtree = reader.ReadSubtree())
                                         using (var subtree = reader.ReadSubtree())
                                         {
                                         {
-                                            FetchDataFromSeriesNode(item, subtree, cancellationToken);
+                                            FetchDataFromSeriesNode(result, subtree, cancellationToken);
                                         }
                                         }
                                         break;
                                         break;
                                     }
                                     }
@@ -667,9 +669,9 @@ namespace MediaBrowser.Providers.TV
                 }
                 }
             }
             }
 
 
-            if (item.Status.HasValue && item.Status.Value == SeriesStatus.Ended && episiodeAirDates.Count > 0)
+            if (result.Item.Status.HasValue && result.Item.Status.Value == SeriesStatus.Ended && episiodeAirDates.Count > 0)
             {
             {
-                item.EndDate = episiodeAirDates.Max();
+                result.Item.EndDate = episiodeAirDates.Max();
             }
             }
         }
         }
 
 
@@ -861,8 +863,10 @@ namespace MediaBrowser.Providers.TV
             }
             }
         }
         }
 
 
-        private void FetchDataFromSeriesNode(Series item, XmlReader reader, CancellationToken cancellationToken)
+        private void FetchDataFromSeriesNode(MetadataResult<Series> result, XmlReader reader, CancellationToken cancellationToken)
         {
         {
+            Series item = result.Item;
+
             reader.MoveToContent();
             reader.MoveToContent();
 
 
             // Loop through each element
             // Loop through each element
@@ -886,6 +890,12 @@ namespace MediaBrowser.Providers.TV
                                 break;
                                 break;
                             }
                             }
 
 
+                        case "Language":
+                            {
+                                result.ResultLanguage = (reader.ReadElementContentAsString() ?? string.Empty).Trim();
+                                break;
+                            }
+
                         case "Airs_DayOfWeek":
                         case "Airs_DayOfWeek":
                             {
                             {
                                 var val = reader.ReadElementContentAsString();
                                 var val = reader.ReadElementContentAsString();

+ 14 - 8
MediaBrowser.Server.Implementations/Connect/ConnectManager.cs

@@ -403,6 +403,14 @@ namespace MediaBrowser.Server.Implementations.Connect
 
 
         public async Task<UserLinkResult> LinkUser(string userId, string connectUsername)
         public async Task<UserLinkResult> LinkUser(string userId, string connectUsername)
         {
         {
+            if (string.IsNullOrWhiteSpace(userId))
+            {
+                throw new ArgumentNullException("userId");
+            }
+            if (string.IsNullOrWhiteSpace(connectUsername))
+            {
+                throw new ArgumentNullException("connectUsername");
+            }
             if (string.IsNullOrWhiteSpace(ConnectServerId))
             if (string.IsNullOrWhiteSpace(ConnectServerId))
             {
             {
                 await UpdateConnectInfo().ConfigureAwait(false);
                 await UpdateConnectInfo().ConfigureAwait(false);
@@ -422,14 +430,6 @@ namespace MediaBrowser.Server.Implementations.Connect
 
 
         private async Task<UserLinkResult> LinkUserInternal(string userId, string connectUsername)
         private async Task<UserLinkResult> LinkUserInternal(string userId, string connectUsername)
         {
         {
-            if (string.IsNullOrWhiteSpace(userId))
-            {
-                throw new ArgumentNullException("userId");
-            }
-            if (string.IsNullOrWhiteSpace(connectUsername))
-            {
-                throw new ArgumentNullException("connectUsername");
-            }
             if (string.IsNullOrWhiteSpace(ConnectServerId))
             if (string.IsNullOrWhiteSpace(ConnectServerId))
             {
             {
                 throw new ArgumentNullException("ConnectServerId");
                 throw new ArgumentNullException("ConnectServerId");
@@ -446,6 +446,12 @@ namespace MediaBrowser.Server.Implementations.Connect
                 throw new ArgumentException("The Emby account has been disabled.");
                 throw new ArgumentException("The Emby account has been disabled.");
             }
             }
 
 
+            var existingUser = _userManager.Users.FirstOrDefault(i => string.Equals(i.ConnectUserId, connectUser.Id) && !string.IsNullOrWhiteSpace(i.ConnectAccessKey));
+            if (existingUser != null)
+            {
+                throw new InvalidOperationException("This connect user is already linked to local user " + existingUser.Name);
+            }
+
             var user = GetUser(userId);
             var user = GetUser(userId);
 
 
             if (!string.IsNullOrWhiteSpace(user.ConnectUserId))
             if (!string.IsNullOrWhiteSpace(user.ConnectUserId))

+ 2 - 2
MediaBrowser.Server.Implementations/Dto/DtoService.cs

@@ -1509,7 +1509,7 @@ namespace MediaBrowser.Server.Implementations.Dto
             }
             }
         }
         }
 
 
-        private string GetMappedPath(IHasMetadata item)
+        private string GetMappedPath(BaseItem item)
         {
         {
             var path = item.Path;
             var path = item.Path;
 
 
@@ -1517,7 +1517,7 @@ namespace MediaBrowser.Server.Implementations.Dto
 
 
             if (locationType == LocationType.FileSystem || locationType == LocationType.Offline)
             if (locationType == LocationType.FileSystem || locationType == LocationType.Offline)
             {
             {
-                path = _libraryManager.GetPathAfterNetworkSubstitution(path);
+                path = _libraryManager.GetPathAfterNetworkSubstitution(path, item);
             }
             }
 
 
             return path;
             return path;

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

@@ -33,7 +33,8 @@ namespace MediaBrowser.Server.Implementations.Library
 
 
                 // Synology
                 // Synology
                 "@eaDir",
                 "@eaDir",
-                "eaDir"
+                "eaDir",
+                "#recycle"
 
 
         };
         };
         
         

+ 98 - 42
MediaBrowser.Server.Implementations/Library/LibraryManager.cs

@@ -2527,8 +2527,29 @@ namespace MediaBrowser.Server.Implementations.Library
                 }).OrderBy(i => i.Path).ToList();
                 }).OrderBy(i => i.Path).ToList();
         }
         }
 
 
-        public string GetPathAfterNetworkSubstitution(string path)
+        public string GetPathAfterNetworkSubstitution(string path, BaseItem ownerItem)
         {
         {
+            if (ownerItem != null)
+            {
+                var libraryOptions = GetLibraryOptions(ownerItem);
+                if (libraryOptions != null)
+                {
+                    foreach (var pathInfo in libraryOptions.PathInfos)
+                    {
+                        if (string.IsNullOrWhiteSpace(pathInfo.NetworkPath))
+                        {
+                            continue;
+                        }
+
+                        var substitutionResult = SubstitutePathInternal(path, pathInfo.Path, pathInfo.NetworkPath);
+                        if (substitutionResult.Item2)
+                        {
+                            return substitutionResult.Item1;
+                        }
+                    }
+                }
+            }
+
             foreach (var map in ConfigurationManager.Configuration.PathSubstitutions)
             foreach (var map in ConfigurationManager.Configuration.PathSubstitutions)
             {
             {
                 path = SubstitutePath(path, map.From, map.To);
                 path = SubstitutePath(path, map.From, map.To);
@@ -2538,6 +2559,11 @@ namespace MediaBrowser.Server.Implementations.Library
         }
         }
 
 
         public string SubstitutePath(string path, string from, string to)
         public string SubstitutePath(string path, string from, string to)
+        {
+            return SubstitutePathInternal(path, from, to).Item1;
+        }
+
+        private Tuple<string, bool> SubstitutePathInternal(string path, string from, string to)
         {
         {
             if (string.IsNullOrWhiteSpace(path))
             if (string.IsNullOrWhiteSpace(path))
             {
             {
@@ -2552,7 +2578,11 @@ namespace MediaBrowser.Server.Implementations.Library
                 throw new ArgumentNullException("to");
                 throw new ArgumentNullException("to");
             }
             }
 
 
-            var newPath = path.Replace(from.Trim(), to.Trim(), StringComparison.OrdinalIgnoreCase);
+            from = from.Trim();
+            to = to.Trim();
+
+            var newPath = path.Replace(from, to, StringComparison.OrdinalIgnoreCase);
+            var changed = false;
 
 
             if (!string.Equals(newPath, path))
             if (!string.Equals(newPath, path))
             {
             {
@@ -2564,9 +2594,11 @@ namespace MediaBrowser.Server.Implementations.Library
                 {
                 {
                     newPath = newPath.Replace('/', '\\');
                     newPath = newPath.Replace('/', '\\');
                 }
                 }
+
+                changed = true;
             }
             }
 
 
-            return newPath;
+            return new Tuple<string, bool>(newPath, changed);
         }
         }
 
 
         private void SetExtraTypeFromFilename(Video item)
         private void SetExtraTypeFromFilename(Video item)
@@ -2695,7 +2727,7 @@ namespace MediaBrowser.Server.Implementations.Library
             throw new InvalidOperationException();
             throw new InvalidOperationException();
         }
         }
 
 
-        public void AddVirtualFolder(string name, string collectionType, string[] mediaPaths, LibraryOptions options, bool refreshLibrary)
+        public void AddVirtualFolder(string name, string collectionType, LibraryOptions options, bool refreshLibrary)
         {
         {
             if (string.IsNullOrWhiteSpace(name))
             if (string.IsNullOrWhiteSpace(name))
             {
             {
@@ -2713,12 +2745,13 @@ namespace MediaBrowser.Server.Implementations.Library
                 virtualFolderPath = Path.Combine(rootFolderPath, name);
                 virtualFolderPath = Path.Combine(rootFolderPath, name);
             }
             }
 
 
-            if (mediaPaths != null)
+            var mediaPathInfos = options.PathInfos;
+            if (mediaPathInfos != null)
             {
             {
-                var invalidpath = mediaPaths.FirstOrDefault(i => !_fileSystem.DirectoryExists(i));
+                var invalidpath = mediaPathInfos.FirstOrDefault(i => !_fileSystem.DirectoryExists(i.Path));
                 if (invalidpath != null)
                 if (invalidpath != null)
                 {
                 {
-                    throw new ArgumentException("The specified path does not exist: " + invalidpath + ".");
+                    throw new ArgumentException("The specified path does not exist: " + invalidpath.Path + ".");
                 }
                 }
             }
             }
 
 
@@ -2740,11 +2773,11 @@ namespace MediaBrowser.Server.Implementations.Library
 
 
                 CollectionFolder.SaveLibraryOptions(virtualFolderPath, options);
                 CollectionFolder.SaveLibraryOptions(virtualFolderPath, options);
 
 
-                if (mediaPaths != null)
+                if (mediaPathInfos != null)
                 {
                 {
-                    foreach (var path in mediaPaths)
+                    foreach (var path in mediaPathInfos)
                     {
                     {
-                        AddMediaPath(name, path);
+                        AddMediaPathInternal(name, path, false);
                     }
                     }
                 }
                 }
             }
             }
@@ -2770,6 +2803,61 @@ namespace MediaBrowser.Server.Implementations.Library
             }
             }
         }
         }
 
 
+        private const string ShortcutFileExtension = ".mblink";
+        private const string ShortcutFileSearch = "*" + ShortcutFileExtension;
+        public void AddMediaPath(string virtualFolderName, MediaPathInfo pathInfo)
+        {
+            AddMediaPathInternal(virtualFolderName, pathInfo, true);
+        }
+
+        private void AddMediaPathInternal(string virtualFolderName, MediaPathInfo pathInfo, bool saveLibraryOptions)
+        {
+            if (pathInfo == null)
+            {
+                throw new ArgumentNullException("path");
+            }
+
+            var path = pathInfo.Path;
+
+            if (string.IsNullOrWhiteSpace(path))
+            {
+                throw new ArgumentNullException("path");
+            }
+
+            if (!_fileSystem.DirectoryExists(path))
+            {
+                throw new DirectoryNotFoundException("The path does not exist.");
+            }
+
+            var rootFolderPath = ConfigurationManager.ApplicationPaths.DefaultUserViewsPath;
+            var virtualFolderPath = Path.Combine(rootFolderPath, virtualFolderName);
+
+            var shortcutFilename = _fileSystem.GetFileNameWithoutExtension(path);
+
+            var lnk = Path.Combine(virtualFolderPath, shortcutFilename + ShortcutFileExtension);
+
+            while (_fileSystem.FileExists(lnk))
+            {
+                shortcutFilename += "1";
+                lnk = Path.Combine(virtualFolderPath, shortcutFilename + ShortcutFileExtension);
+            }
+
+            _fileSystem.CreateShortcut(lnk, path);
+
+            RemoveContentTypeOverrides(path);
+
+            if (saveLibraryOptions)
+            {
+                var libraryOptions = CollectionFolder.GetLibraryOptions(virtualFolderPath);
+
+                var list = libraryOptions.PathInfos.ToList();
+                list.Add(pathInfo);
+                libraryOptions.PathInfos = list.ToArray();
+
+                CollectionFolder.SaveLibraryOptions(virtualFolderPath, libraryOptions);
+            }
+        }
+
         public void RemoveVirtualFolder(string name, bool refreshLibrary)
         public void RemoveVirtualFolder(string name, bool refreshLibrary)
         {
         {
             if (string.IsNullOrWhiteSpace(name))
             if (string.IsNullOrWhiteSpace(name))
@@ -2814,38 +2902,6 @@ namespace MediaBrowser.Server.Implementations.Library
             }
             }
         }
         }
 
 
-        private const string ShortcutFileExtension = ".mblink";
-        private const string ShortcutFileSearch = "*" + ShortcutFileExtension;
-        public void AddMediaPath(string virtualFolderName, string path)
-        {
-            if (string.IsNullOrWhiteSpace(path))
-            {
-                throw new ArgumentNullException("path");
-            }
-
-            if (!_fileSystem.DirectoryExists(path))
-            {
-                throw new DirectoryNotFoundException("The path does not exist.");
-            }
-
-            var rootFolderPath = ConfigurationManager.ApplicationPaths.DefaultUserViewsPath;
-            var virtualFolderPath = Path.Combine(rootFolderPath, virtualFolderName);
-
-            var shortcutFilename = _fileSystem.GetFileNameWithoutExtension(path);
-
-            var lnk = Path.Combine(virtualFolderPath, shortcutFilename + ShortcutFileExtension);
-
-            while (_fileSystem.FileExists(lnk))
-            {
-                shortcutFilename += "1";
-                lnk = Path.Combine(virtualFolderPath, shortcutFilename + ShortcutFileExtension);
-            }
-
-            _fileSystem.CreateShortcut(lnk, path);
-
-            RemoveContentTypeOverrides(path);
-        }
-
         private void RemoveContentTypeOverrides(string path)
         private void RemoveContentTypeOverrides(string path)
         {
         {
             if (string.IsNullOrWhiteSpace(path))
             if (string.IsNullOrWhiteSpace(path))

+ 7 - 1
MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs

@@ -143,9 +143,15 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
                     continue;
                     continue;
                 }
                 }
 
 
+                var mediaPathInfos = pathsToCreate.Select(i => new MediaPathInfo { Path = i }).ToArray();
+
+                var libraryOptions = new LibraryOptions
+                {
+                    PathInfos = mediaPathInfos
+                };
                 try
                 try
                 {
                 {
-                    _libraryManager.AddVirtualFolder(recordingFolder.Name, recordingFolder.CollectionType, pathsToCreate.ToArray(), new LibraryOptions(), true);
+                    _libraryManager.AddVirtualFolder(recordingFolder.Name, recordingFolder.CollectionType, libraryOptions, true);
                 }
                 }
                 catch (Exception ex)
                 catch (Exception ex)
                 {
                 {

+ 1 - 1
MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs

@@ -253,7 +253,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
             }
             }
 
 
             var durationParam = " -t " + _mediaEncoder.GetTimeParameter(duration.Ticks);
             var durationParam = " -t " + _mediaEncoder.GetTimeParameter(duration.Ticks);
-            var commandLineArgs = "-fflags +genpts -async 1 -vsync -1 -re -i \"{0}\"{4} -sn {2} -map_metadata -1 -threads 0 {3} -y \"{1}\"";
+            var commandLineArgs = "-fflags +genpts -async 1 -vsync -1 -i \"{0}\"{4} -sn {2} -map_metadata -1 -threads 0 {3} -y \"{1}\"";
 
 
             if (mediaSource.ReadAtNativeFramerate)
             if (mediaSource.ReadAtNativeFramerate)
             {
             {

+ 2 - 2
MediaBrowser.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs

@@ -171,7 +171,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings
                                 var data = images[imageIndex].data ?? new List<ScheduleDirect.ImageData>();
                                 var data = images[imageIndex].data ?? new List<ScheduleDirect.ImageData>();
                                 data = data.OrderByDescending(GetSizeOrder).ToList();
                                 data = data.OrderByDescending(GetSizeOrder).ToList();
 
 
-                                programEntry.primaryImage = GetProgramImage(ApiUrl, data, "Logo", true, 800);
+                                programEntry.primaryImage = GetProgramImage(ApiUrl, data, "Logo", true, 600);
                                 //programEntry.thumbImage = GetProgramImage(ApiUrl, data, "Iconic", false);
                                 //programEntry.thumbImage = GetProgramImage(ApiUrl, data, "Iconic", false);
                                 //programEntry.bannerImage = GetProgramImage(ApiUrl, data, "Banner", false) ??
                                 //programEntry.bannerImage = GetProgramImage(ApiUrl, data, "Banner", false) ??
                                 //    GetProgramImage(ApiUrl, data, "Banner-L1", false) ??
                                 //    GetProgramImage(ApiUrl, data, "Banner-L1", false) ??
@@ -485,7 +485,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings
                 }
                 }
             }
             }
 
 
-            if (!string.IsNullOrWhiteSpace(details.originalAirDate))
+            if (!string.IsNullOrWhiteSpace(details.originalAirDate) && (!info.IsSeries || info.IsRepeat))
             {
             {
                 info.OriginalAirDate = DateTime.Parse(details.originalAirDate);
                 info.OriginalAirDate = DateTime.Parse(details.originalAirDate);
             }
             }

+ 14 - 0
MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs

@@ -2837,6 +2837,20 @@ namespace MediaBrowser.Server.Implementations.LiveTv
                 feature = "embytvseriesrecordings";
                 feature = "embytvseriesrecordings";
             }
             }
 
 
+            if (string.Equals(feature, "dvr-l", StringComparison.OrdinalIgnoreCase))
+            {
+                var config = GetConfiguration();
+                if (config.TunerHosts.Count(i => i.IsEnabled) > 0 &&
+                    config.ListingProviders.Count(i => (i.EnableAllTuners || i.EnabledTuners.Length > 0) && string.Equals(i.Type, SchedulesDirect.TypeName, StringComparison.OrdinalIgnoreCase)) > 0)
+                {
+                    return Task.FromResult(new MBRegistrationRecord
+                    {
+                        IsRegistered = true,
+                        IsValid = true
+                    });
+                }
+            }
+
             if (string.Equals(feature, "dvr", StringComparison.OrdinalIgnoreCase))
             if (string.Equals(feature, "dvr", StringComparison.OrdinalIgnoreCase))
             {
             {
                 var config = GetConfiguration();
                 var config = GetConfiguration();

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

@@ -73,8 +73,8 @@
       <HintPath>..\packages\SimpleInjector.3.2.2\lib\net45\SimpleInjector.dll</HintPath>
       <HintPath>..\packages\SimpleInjector.3.2.2\lib\net45\SimpleInjector.dll</HintPath>
       <Private>True</Private>
       <Private>True</Private>
     </Reference>
     </Reference>
-    <Reference Include="SocketHttpListener, Version=1.0.6063.4624, Culture=neutral, processorArchitecture=MSIL">
-      <HintPath>..\packages\SocketHttpListener.1.0.0.39\lib\net45\SocketHttpListener.dll</HintPath>
+    <Reference Include="SocketHttpListener, Version=1.0.6109.26162, Culture=neutral, processorArchitecture=MSIL">
+      <HintPath>..\packages\SocketHttpListener.1.0.0.40\lib\net45\SocketHttpListener.dll</HintPath>
       <Private>True</Private>
       <Private>True</Private>
     </Reference>
     </Reference>
     <Reference Include="System" />
     <Reference Include="System" />

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

@@ -8,5 +8,5 @@
   <package id="morelinq" version="1.4.0" targetFramework="net45" />
   <package id="morelinq" version="1.4.0" targetFramework="net45" />
   <package id="Patterns.Logging" version="1.0.0.2" targetFramework="net45" />
   <package id="Patterns.Logging" version="1.0.0.2" targetFramework="net45" />
   <package id="SimpleInjector" version="3.2.2" targetFramework="net45" />
   <package id="SimpleInjector" version="3.2.2" targetFramework="net45" />
-  <package id="SocketHttpListener" version="1.0.0.39" targetFramework="net45" />
+  <package id="SocketHttpListener" version="1.0.0.40" targetFramework="net45" />
 </packages>
 </packages>

+ 1 - 1
MediaBrowser.WebDashboard/Api/PackageCreator.cs

@@ -346,7 +346,7 @@ namespace MediaBrowser.WebDashboard.Api
 
 
             if (string.Equals(mode, "cordova", StringComparison.OrdinalIgnoreCase))
             if (string.Equals(mode, "cordova", StringComparison.OrdinalIgnoreCase))
             {
             {
-                sb.Append("<meta http-equiv=\"Content-Security-Policy\" content=\"default-src * 'self' 'unsafe-inline' 'unsafe-eval' data: gap: file: filesystem:;\">");
+                sb.Append("<meta http-equiv=\"Content-Security-Policy\" content=\"default-src * 'self' 'unsafe-inline' 'unsafe-eval' data: gap: file: filesystem: ws: wss:;\">");
             }
             }
             else
             else
             {
             {

+ 0 - 6
MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj

@@ -470,9 +470,6 @@
     <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.5\jqm.widget.js">
     <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.5\jqm.widget.js">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.5\jquery.mobile.custom.icons.css">
-      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
-    </Content>
     <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.5\jquery.mobile.custom.theme.css">
     <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.5\jquery.mobile.custom.theme.css">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
@@ -977,9 +974,6 @@
     <Content Include="dashboard-ui\scripts\nowplayingpage.js">
     <Content Include="dashboard-ui\scripts\nowplayingpage.js">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>
-    <Content Include="dashboard-ui\scripts\ratingdialog.js">
-      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
-    </Content>
     <Content Include="dashboard-ui\scripts\episodes.js">
     <Content Include="dashboard-ui\scripts\episodes.js">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
     </Content>