Просмотр исходного кода

Merge pull request #2037 from MediaBrowser/beta

Beta
Luke 9 лет назад
Родитель
Сommit
2026a682ed
66 измененных файлов с 433 добавлено и 283 удалено
  1. 3 3
      MediaBrowser.Api/ApiEntryPoint.cs
  2. 5 2
      MediaBrowser.Api/ItemRefreshService.cs
  3. 22 9
      MediaBrowser.Api/Playback/BaseStreamingService.cs
  4. 17 3
      MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs
  5. 26 16
      MediaBrowser.Api/Playback/Progressive/ProgressiveStreamWriter.cs
  6. 3 3
      MediaBrowser.Api/Playback/Progressive/VideoService.cs
  7. 4 1
      MediaBrowser.Api/Playback/StreamState.cs
  8. 1 1
      MediaBrowser.Api/PluginService.cs
  9. 1 1
      MediaBrowser.Api/StartupWizardService.cs
  10. 13 5
      MediaBrowser.Api/VideosService.cs
  11. 1 1
      MediaBrowser.Common/Plugins/BasePlugin.cs
  12. 1 1
      MediaBrowser.Controller/Entities/AggregateFolder.cs
  13. 1 1
      MediaBrowser.Controller/Entities/BaseItem.cs
  14. 1 1
      MediaBrowser.Controller/Entities/CollectionFolder.cs
  15. 1 1
      MediaBrowser.Controller/Entities/Folder.cs
  16. 1 1
      MediaBrowser.Controller/Entities/User.cs
  17. 1 0
      MediaBrowser.Controller/Library/ILibraryManager.cs
  18. 1 0
      MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs
  19. 1 0
      MediaBrowser.Controller/Persistence/IItemRepository.cs
  20. 15 13
      MediaBrowser.Controller/Providers/DirectoryService.cs
  21. 2 1
      MediaBrowser.Controller/Providers/MetadataRefreshOptions.cs
  22. 1 2
      MediaBrowser.Dlna/DlnaManager.cs
  23. 3 3
      MediaBrowser.Dlna/Profiles/SamsungSmartTvProfile.cs
  24. 1 1
      MediaBrowser.Dlna/Profiles/Xml/Samsung Smart TV.xml
  25. 1 1
      MediaBrowser.LocalMetadata/BaseXmlProvider.cs
  26. 1 1
      MediaBrowser.LocalMetadata/Providers/SeriesXmlProvider.cs
  27. 3 1
      MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs
  28. 32 15
      MediaBrowser.MediaEncoding/Encoder/EncodingJobFactory.cs
  29. 1 1
      MediaBrowser.MediaEncoding/Encoder/FontConfigLoader.cs
  30. 2 2
      MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs
  31. 3 3
      MediaBrowser.MediaEncoding/Encoder/VideoEncoder.cs
  32. 2 1
      MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs
  33. 0 30
      MediaBrowser.Providers/Manager/MetadataService.cs
  34. 2 2
      MediaBrowser.Providers/Manager/ProviderManager.cs
  35. 49 17
      MediaBrowser.Providers/Music/AudioDbAlbumProvider.cs
  36. 47 14
      MediaBrowser.Providers/Music/AudioDbArtistProvider.cs
  37. 1 1
      MediaBrowser.Providers/Subtitles/SubtitleManager.cs
  38. 1 1
      MediaBrowser.Providers/TV/MissingEpisodeProvider.cs
  39. 5 6
      MediaBrowser.Server.Implementations/Connect/ConnectManager.cs
  40. 1 1
      MediaBrowser.Server.Implementations/Dto/DtoService.cs
  41. 1 1
      MediaBrowser.Server.Implementations/EntryPoints/ActivityLogEntryPoint.cs
  42. 1 1
      MediaBrowser.Server.Implementations/EntryPoints/ExternalPortForwarding.cs
  43. 1 1
      MediaBrowser.Server.Implementations/EntryPoints/UserDataChangeNotifier.cs
  44. 1 1
      MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs
  45. 1 1
      MediaBrowser.Server.Implementations/HttpServer/RangeRequestWriter.cs
  46. 17 6
      MediaBrowser.Server.Implementations/Library/LibraryManager.cs
  47. 19 15
      MediaBrowser.Server.Implementations/Library/Validators/ArtistsValidator.cs
  48. 9 8
      MediaBrowser.Server.Implementations/Library/Validators/GameGenresValidator.cs
  49. 9 8
      MediaBrowser.Server.Implementations/Library/Validators/GenresValidator.cs
  50. 10 8
      MediaBrowser.Server.Implementations/Library/Validators/MusicGenresValidator.cs
  51. 2 2
      MediaBrowser.Server.Implementations/Library/Validators/PeopleValidator.cs
  52. 7 9
      MediaBrowser.Server.Implementations/Library/Validators/StudiosValidator.cs
  53. 2 2
      MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs
  54. 2 2
      MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs
  55. 1 1
      MediaBrowser.Server.Implementations/LiveTv/EmbyTV/ItemDataProvider.cs
  56. 10 10
      MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs
  57. 1 1
      MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs
  58. 1 1
      MediaBrowser.Server.Implementations/LiveTv/TunerHosts/SatIp/Rtsp/RtspSession.cs
  59. 2 2
      MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj
  60. 1 1
      MediaBrowser.Server.Implementations/Notifications/SqliteNotificationsRepository.cs
  61. 41 23
      MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs
  62. 1 1
      MediaBrowser.Server.Implementations/packages.config
  63. 3 3
      MediaBrowser.Server.Startup.Common/ApplicationHost.cs
  64. 7 7
      MediaBrowser.Tests/ConsistencyTests/StringUsageReporter.cs
  65. 5 0
      MediaBrowser.sln
  66. 1 1
      SharedVersion.cs

+ 3 - 3
MediaBrowser.Api/ApiEntryPoint.cs

@@ -349,7 +349,7 @@ namespace MediaBrowser.Api
                 return;
             }
 
-            var timerDuration = 1000;
+            var timerDuration = 10000;
 
             if (job.Type != TranscodingJobType.Progressive)
             {
@@ -559,13 +559,13 @@ namespace MediaBrowser.Api
             {
 
             }
-            catch (IOException ex)
+            catch (IOException)
             {
                 //Logger.ErrorException("Error deleting partial stream file(s) {0}", ex, path);
 
                 DeletePartialStreamFiles(path, jobType, retryCount + 1, 500);
             }
-            catch (Exception ex)
+            catch
             {
                 //Logger.ErrorException("Error deleting partial stream file(s) {0}", ex, path);
             }

+ 5 - 2
MediaBrowser.Api/ItemRefreshService.cs

@@ -5,6 +5,7 @@ using MediaBrowser.Controller.Providers;
 using ServiceStack;
 using System.Threading;
 using CommonIO;
+using MediaBrowser.Model.Logging;
 
 namespace MediaBrowser.Api
 {
@@ -39,12 +40,14 @@ namespace MediaBrowser.Api
         private readonly ILibraryManager _libraryManager;
         private readonly IProviderManager _providerManager;
         private readonly IFileSystem _fileSystem;
+        private readonly ILogger _logger;
 
-        public ItemRefreshService(ILibraryManager libraryManager, IProviderManager providerManager, IFileSystem fileSystem)
+        public ItemRefreshService(ILibraryManager libraryManager, IProviderManager providerManager, IFileSystem fileSystem, ILogger logger)
         {
             _libraryManager = libraryManager;
             _providerManager = providerManager;
             _fileSystem = fileSystem;
+            _logger = logger;
         }
 
         /// <summary>
@@ -69,7 +72,7 @@ namespace MediaBrowser.Api
 
         private MetadataRefreshOptions GetRefreshOptions(BaseRefreshRequest request)
         {
-            return new MetadataRefreshOptions(new DirectoryService(_fileSystem))
+            return new MetadataRefreshOptions(new DirectoryService(_logger, _fileSystem))
             {
                 MetadataRefreshMode = request.MetadataRefreshMode,
                 ImageRefreshMode = request.ImageRefreshMode,

+ 22 - 9
MediaBrowser.Api/Playback/BaseStreamingService.cs

@@ -286,28 +286,41 @@ namespace MediaBrowser.Api.Playback
 
         protected string GetH264Encoder(StreamState state)
         {
+            var defaultEncoder = "libx264";
+
             // Only use alternative encoders for video files.
             // When using concat with folder rips, if the mfx session fails to initialize, ffmpeg will be stuck retrying and will not exit gracefully
             // Since transcoding of folder rips is expiremental anyway, it's not worth adding additional variables such as this.
             if (state.VideoType == VideoType.VideoFile)
             {
-                if (string.Equals(ApiEntryPoint.Instance.GetEncodingOptions().HardwareAccelerationType, "qsv", StringComparison.OrdinalIgnoreCase) ||
-                    string.Equals(ApiEntryPoint.Instance.GetEncodingOptions().HardwareAccelerationType, "h264_qsv", StringComparison.OrdinalIgnoreCase))
+                var hwType = ApiEntryPoint.Instance.GetEncodingOptions().HardwareAccelerationType;
+
+                if (string.Equals(hwType, "qsv", StringComparison.OrdinalIgnoreCase) ||
+                    string.Equals(hwType, "h264_qsv", StringComparison.OrdinalIgnoreCase))
                 {
-                    return "h264_qsv";
+                    return GetAvailableEncoder("h264_qsv", defaultEncoder);
                 }
 
-                if (string.Equals(ApiEntryPoint.Instance.GetEncodingOptions().HardwareAccelerationType, "nvenc", StringComparison.OrdinalIgnoreCase))
+                if (string.Equals(hwType, "nvenc", StringComparison.OrdinalIgnoreCase))
                 {
-                    return "h264_nvenc";
+                    return GetAvailableEncoder("h264_nvenc", defaultEncoder);
                 }
-                if (string.Equals(ApiEntryPoint.Instance.GetEncodingOptions().HardwareAccelerationType, "h264_omx", StringComparison.OrdinalIgnoreCase))
+                if (string.Equals(hwType, "h264_omx", StringComparison.OrdinalIgnoreCase))
                 {
-                    return "h264_omx";
+                    return GetAvailableEncoder("h264_omx", defaultEncoder);
                 }
             }
 
-            return "libx264";
+            return defaultEncoder;
+        }
+
+        private string GetAvailableEncoder(string preferredEncoder, string defaultEncoder)
+        {
+            if (MediaEncoder.SupportsEncoder(preferredEncoder))
+            {
+                return preferredEncoder;
+            }
+            return defaultEncoder;
         }
 
         /// <summary>
@@ -1080,7 +1093,7 @@ namespace MediaBrowser.Api.Playback
             //process.BeginOutputReadLine();
 
             // Important - don't await the log task or we won't be able to kill ffmpeg when the user stops playback
-            Task.Run(() => StartStreamingLog(transcodingJob, state, process.StandardError.BaseStream, state.LogFileStream));
+            var task = Task.Run(() => StartStreamingLog(transcodingJob, state, process.StandardError.BaseStream, state.LogFileStream));
 
             // Wait for the file to exist before proceeeding
             while (!FileSystem.FileExists(state.WaitForPath ?? outputPath) && !transcodingJob.HasExited)

+ 17 - 3
MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs

@@ -142,7 +142,8 @@ namespace MediaBrowser.Api.Playback.Progressive
             var outputPath = state.OutputFilePath;
             var outputPathExists = FileSystem.FileExists(outputPath);
 
-            var isTranscodeCached = outputPathExists && !ApiEntryPoint.Instance.HasActiveTranscodingJob(outputPath, TranscodingJobType.Progressive);
+            var transcodingJob = ApiEntryPoint.Instance.GetTranscodingJob(outputPath, TranscodingJobType.Progressive);
+            var isTranscodeCached = outputPathExists && transcodingJob != null;
 
             AddDlnaHeaders(state, responseHeaders, request.Static || isTranscodeCached);
 
@@ -159,6 +160,7 @@ namespace MediaBrowser.Api.Playback.Progressive
                         ContentType = contentType,
                         IsHeadRequest = isHeadRequest,
                         Path = state.MediaPath
+
                     }).ConfigureAwait(false);
                 }
             }
@@ -170,13 +172,25 @@ namespace MediaBrowser.Api.Playback.Progressive
 
                 try
                 {
+                    if (transcodingJob != null)
+                    {
+                        ApiEntryPoint.Instance.OnTranscodeBeginRequest(transcodingJob);
+                    }
+
                     return await ResultFactory.GetStaticFileResult(Request, new StaticFileResultOptions
                     {
                         ResponseHeaders = responseHeaders,
                         ContentType = contentType,
                         IsHeadRequest = isHeadRequest,
                         Path = outputPath,
-                        FileShare = FileShare.ReadWrite
+                        FileShare = FileShare.ReadWrite,
+                        OnComplete = () =>
+                        {
+                            if (transcodingJob != null)
+                            {
+                                ApiEntryPoint.Instance.OnTranscodeEndRequest(transcodingJob);
+                            }
+                        }
 
                     }).ConfigureAwait(false);
                 }
@@ -348,7 +362,7 @@ namespace MediaBrowser.Api.Playback.Progressive
                     outputHeaders[item.Key] = item.Value;
                 }
 
-                Func<Stream,Task> streamWriter = stream => new ProgressiveFileCopier(FileSystem, job, Logger).StreamFile(outputPath, stream, CancellationToken.None);
+                Func<Stream, Task> streamWriter = stream => new ProgressiveFileCopier(FileSystem, job, Logger).StreamFile(outputPath, stream, CancellationToken.None);
 
                 return ResultFactory.GetAsyncStreamWriter(streamWriter, outputHeaders);
             }

+ 26 - 16
MediaBrowser.Api/Playback/Progressive/ProgressiveStreamWriter.cs

@@ -27,31 +27,41 @@ namespace MediaBrowser.Api.Playback.Progressive
 
         public async Task StreamFile(string path, Stream outputStream, CancellationToken cancellationToken)
         {
-            var eofCount = 0;
-
-            using (var fs = _fileSystem.GetFileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, true))
+            try
             {
-                while (eofCount < 15)
+                var eofCount = 0;
+
+                using (var fs = _fileSystem.GetFileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, true))
                 {
-                    var bytesRead = await CopyToAsyncInternal(fs, outputStream, BufferSize, cancellationToken).ConfigureAwait(false);
+                    while (eofCount < 15)
+                    {
+                        var bytesRead = await CopyToAsyncInternal(fs, outputStream, BufferSize, cancellationToken).ConfigureAwait(false);
 
-                    //var position = fs.Position;
-                    //_logger.Debug("Streamed {0} bytes to position {1} from file {2}", bytesRead, position, path);
+                        //var position = fs.Position;
+                        //_logger.Debug("Streamed {0} bytes to position {1} from file {2}", bytesRead, position, path);
 
-                    if (bytesRead == 0)
-                    {
-                        if (_job == null || _job.HasExited)
+                        if (bytesRead == 0)
                         {
-                            eofCount++;
+                            if (_job == null || _job.HasExited)
+                            {
+                                eofCount++;
+                            }
+                            await Task.Delay(100, cancellationToken).ConfigureAwait(false);
+                        }
+                        else
+                        {
+                            eofCount = 0;
                         }
-                        await Task.Delay(100, cancellationToken).ConfigureAwait(false);
-                    }
-                    else
-                    {
-                        eofCount = 0;
                     }
                 }
             }
+            finally
+            {
+                if (_job != null)
+                {
+                    ApiEntryPoint.Instance.OnTranscodeEndRequest(_job);
+                }
+            }
         }
 
         private async Task<int> CopyToAsyncInternal(Stream source, Stream destination, Int32 bufferSize, CancellationToken cancellationToken)

+ 3 - 3
MediaBrowser.Api/Playback/Progressive/VideoService.cs

@@ -149,11 +149,11 @@ namespace MediaBrowser.Api.Playback.Progressive
                 {
                     args += " -copyts -avoid_negative_ts disabled -start_at_zero";
                 }
-                
+
                 return args;
             }
 
-            var keyFrameArg = string.Format(" -force_key_frames expr:gte(t,n_forced*{0})",
+            var keyFrameArg = string.Format(" -force_key_frames \"expr:gte(t,n_forced*{0})\"",
                 5.ToString(UsCulture));
 
             args += keyFrameArg;
@@ -237,4 +237,4 @@ namespace MediaBrowser.Api.Playback.Progressive
             return args;
         }
     }
-}
+}

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

@@ -80,7 +80,10 @@ namespace MediaBrowser.Api.Playback
                     {
                         return 10;
                     }
-                    if (userAgent.IndexOf("cfnetwork", StringComparison.OrdinalIgnoreCase) != -1)
+                    if (userAgent.IndexOf("cfnetwork", StringComparison.OrdinalIgnoreCase) != -1 ||
+                        userAgent.IndexOf("ipad", StringComparison.OrdinalIgnoreCase) != -1 ||
+                        userAgent.IndexOf("iphone", StringComparison.OrdinalIgnoreCase) != -1 ||
+                        userAgent.IndexOf("ipod", StringComparison.OrdinalIgnoreCase) != -1)
                     {
                         return 10;
                     }

+ 1 - 1
MediaBrowser.Api/PluginService.cs

@@ -227,7 +227,7 @@ namespace MediaBrowser.Api
                         .ToList();
                 }
             }
-            catch (Exception ex)
+            catch
             {
                 //Logger.ErrorException("Error getting plugin list", ex);
                 // Play it safe here

+ 1 - 1
MediaBrowser.Api/StartupWizardService.cs

@@ -117,7 +117,7 @@ namespace MediaBrowser.Api
             config.EnableStandaloneMusicKeys = true;
             config.EnableCaseSensitiveItemIds = true;
             //config.EnableFolderView = true;
-            config.SchemaVersion = 108;
+            config.SchemaVersion = 109;
         }
 
         public void Post(UpdateStartupConfiguration request)

+ 13 - 5
MediaBrowser.Api/VideosService.cs

@@ -11,6 +11,7 @@ using System.Linq;
 using System.Threading;
 using System.Threading.Tasks;
 using CommonIO;
+using MediaBrowser.Model.Dto;
 
 namespace MediaBrowser.Api
 {
@@ -81,11 +82,18 @@ namespace MediaBrowser.Api
 
             var dtoOptions = GetDtoOptions(request);
 
-            var video = (Video)item;
-
-            var items = video.GetAdditionalParts()
-                         .Select(i => _dtoService.GetBaseItemDto(i, dtoOptions, user, video))
-                         .ToArray();
+            var video = item as Video;
+            BaseItemDto[] items;
+            if (video != null)
+            {
+                items = video.GetAdditionalParts()
+                    .Select(i => _dtoService.GetBaseItemDto(i, dtoOptions, user, video))
+                    .ToArray();
+            }
+            else
+            {
+                items = new BaseItemDto[] { };
+            }
 
             var result = new ItemsResult
             {

+ 1 - 1
MediaBrowser.Common/Plugins/BasePlugin.cs

@@ -211,7 +211,7 @@ namespace MediaBrowser.Common.Plugins
             {
                 return (TConfigurationType)Activator.CreateInstance(typeof(TConfigurationType));
             }
-            catch (Exception ex)
+            catch
             {
                 return (TConfigurationType)Activator.CreateInstance(typeof(TConfigurationType));
             }

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

@@ -76,7 +76,7 @@ namespace MediaBrowser.Controller.Entities
             {
                 var locations = PhysicalLocations.ToList();
 
-                var newLocations = CreateResolveArgs(new DirectoryService(BaseItem.FileSystem), false).PhysicalLocations.ToList();
+                var newLocations = CreateResolveArgs(new DirectoryService(Logger, FileSystem), false).PhysicalLocations.ToList();
 
                 if (!locations.SequenceEqual(newLocations))
                 {

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

@@ -1003,7 +1003,7 @@ namespace MediaBrowser.Controller.Entities
 
         public Task RefreshMetadata(CancellationToken cancellationToken)
         {
-            return RefreshMetadata(new MetadataRefreshOptions(new DirectoryService(FileSystem)), cancellationToken);
+            return RefreshMetadata(new MetadataRefreshOptions(new DirectoryService(Logger, FileSystem)), cancellationToken);
         }
 
         /// <summary>

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

@@ -82,7 +82,7 @@ namespace MediaBrowser.Controller.Entities
             {
                 var locations = PhysicalLocations.ToList();
 
-                var newLocations = CreateResolveArgs(new DirectoryService(BaseItem.FileSystem), false).PhysicalLocations.ToList();
+                var newLocations = CreateResolveArgs(new DirectoryService(Logger, FileSystem), false).PhysicalLocations.ToList();
 
                 if (!locations.SequenceEqual(newLocations))
                 {

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

@@ -278,7 +278,7 @@ namespace MediaBrowser.Controller.Entities
 
         public Task ValidateChildren(IProgress<double> progress, CancellationToken cancellationToken)
         {
-            return ValidateChildren(progress, cancellationToken, new MetadataRefreshOptions(new DirectoryService(FileSystem)));
+            return ValidateChildren(progress, cancellationToken, new MetadataRefreshOptions(new DirectoryService(Logger, FileSystem)));
         }
 
         /// <summary>

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

@@ -213,7 +213,7 @@ namespace MediaBrowser.Controller.Entities
 
             Name = newName;
 
-			return RefreshMetadata(new MetadataRefreshOptions(new DirectoryService(FileSystem))
+			return RefreshMetadata(new MetadataRefreshOptions(new DirectoryService(Logger, FileSystem))
             {
                 ReplaceAllMetadata = true,
                 ImageRefreshMode = ImageRefreshMode.FullRefresh,

+ 1 - 0
MediaBrowser.Controller/Library/ILibraryManager.cs

@@ -562,5 +562,6 @@ namespace MediaBrowser.Controller.Library
         QueryResult<Tuple<BaseItem, ItemCounts>> GetStudios(InternalItemsQuery query);
         QueryResult<Tuple<BaseItem, ItemCounts>> GetArtists(InternalItemsQuery query);
         QueryResult<Tuple<BaseItem, ItemCounts>> GetAlbumArtists(InternalItemsQuery query);
+        QueryResult<Tuple<BaseItem, ItemCounts>> GetAllArtists(InternalItemsQuery query);
     }
 }

+ 1 - 0
MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs

@@ -133,5 +133,6 @@ namespace MediaBrowser.Controller.MediaEncoding
         Task Init();
 
         Task UpdateEncoderPath(string path, string pathType);
+        bool SupportsEncoder(string encoder);
     }
 }

+ 1 - 0
MediaBrowser.Controller/Persistence/IItemRepository.cs

@@ -169,6 +169,7 @@ namespace MediaBrowser.Controller.Persistence
         QueryResult<Tuple<BaseItem, ItemCounts>> GetStudios(InternalItemsQuery query);
         QueryResult<Tuple<BaseItem, ItemCounts>> GetArtists(InternalItemsQuery query);
         QueryResult<Tuple<BaseItem, ItemCounts>> GetAlbumArtists(InternalItemsQuery query);
+        QueryResult<Tuple<BaseItem, ItemCounts>> GetAllArtists(InternalItemsQuery query);
     }
 }
 

+ 15 - 13
MediaBrowser.Controller/Providers/DirectoryService.cs

@@ -16,13 +16,16 @@ namespace MediaBrowser.Controller.Providers
         private readonly ConcurrentDictionary<string, Dictionary<string, FileSystemMetadata>> _cache =
             new ConcurrentDictionary<string, Dictionary<string, FileSystemMetadata>>(StringComparer.OrdinalIgnoreCase);
 
-		public DirectoryService(ILogger logger, IFileSystem fileSystem)
+        private readonly ConcurrentDictionary<string, FileSystemMetadata> _fileCache =
+        new ConcurrentDictionary<string, FileSystemMetadata>(StringComparer.OrdinalIgnoreCase);
+
+        public DirectoryService(ILogger logger, IFileSystem fileSystem)
         {
             _logger = logger;
 			_fileSystem = fileSystem;
         }
 
-		public DirectoryService(IFileSystem fileSystem)
+        public DirectoryService(IFileSystem fileSystem)
             : this(new NullLogger(), fileSystem)
         {
         }
@@ -100,20 +103,19 @@ namespace MediaBrowser.Controller.Providers
 
         public FileSystemMetadata GetFile(string path)
         {
-            var directory = Path.GetDirectoryName(path);
-
-            if (string.IsNullOrWhiteSpace(directory))
+            FileSystemMetadata file;
+            if (!_fileCache.TryGetValue(path, out file))
             {
-                _logger.Debug("Parent path is null for {0}", path);
-                return null;
-            }
-
-            var dict = GetFileSystemDictionary(directory, false);
+                file = _fileSystem.GetFileInfo(path);
 
-            FileSystemMetadata entry;
-            dict.TryGetValue(path, out entry);
+                if (file != null)
+                {
+                    _fileCache.TryAdd(path, file);
+                }
+            }
 
-            return entry;
+            return file;
+            //return _fileSystem.GetFileInfo(path);
         }
 
         public IEnumerable<FileSystemMetadata> GetDirectories(string path)

+ 2 - 1
MediaBrowser.Controller/Providers/MetadataRefreshOptions.cs

@@ -1,5 +1,6 @@
 using System.Linq;
 using CommonIO;
+using MediaBrowser.Model.Logging;
 using MediaBrowser.Model.Providers;
 
 namespace MediaBrowser.Controller.Providers
@@ -19,7 +20,7 @@ namespace MediaBrowser.Controller.Providers
         public bool ForceSave { get; set; }
 
         public MetadataRefreshOptions(IFileSystem fileSystem)
-			: this(new DirectoryService(fileSystem))
+			: this(new DirectoryService(new NullLogger(), fileSystem))
         {
         }
 

+ 1 - 2
MediaBrowser.Dlna/DlnaManager.cs

@@ -248,8 +248,7 @@ namespace MediaBrowser.Dlna
                         //_logger.Debug("IsMatch-Substring value: {0} testValue: {1} isMatch: {2}", value, header.Value, isMatch);
                         return isMatch;
                     case HeaderMatchType.Regex:
-                        // Reports of IgnoreCase not working on linux so try it a couple different ways.
-                        return Regex.IsMatch(value, header.Value, RegexOptions.IgnoreCase) || Regex.IsMatch(value.ToUpper(), header.Value.ToUpper(), RegexOptions.IgnoreCase);
+                        return Regex.IsMatch(value, header.Value, RegexOptions.IgnoreCase);
                     default:
                         throw new ArgumentException("Unrecognized HeaderMatchType");
                 }

+ 3 - 3
MediaBrowser.Dlna/Profiles/SamsungSmartTvProfile.cs

@@ -21,8 +21,8 @@ namespace MediaBrowser.Dlna.Profiles
                     new HttpHeaderInfo
                     {
                         Name = "User-Agent",
-                        Value = @".*(SEC_HHP_\[TV\] [A-Z]{2}\d{2}J[A-Z]?\d{3,4})*.",
-                        Match = HeaderMatchType.Regex
+                        Value = @"SEC_",
+                        Match = HeaderMatchType.Substring
                     }
                 }
             };
@@ -349,4 +349,4 @@ namespace MediaBrowser.Dlna.Profiles
             };
         }
     }
-}
+}

+ 1 - 1
MediaBrowser.Dlna/Profiles/Xml/Samsung Smart TV.xml

@@ -4,7 +4,7 @@
   <Identification>
     <ModelUrl>samsung.com</ModelUrl>
     <Headers>
-      <HttpHeaderInfo name="User-Agent" value=".*(SEC_HHP_\[TV\] [A-Z]{2}\d{2}J[A-Z]?\d{3,4})*." match="Regex" />
+      <HttpHeaderInfo name="User-Agent" value="SEC_" match="Substring" />
     </Headers>
   </Identification>
   <Manufacturer>Emby</Manufacturer>

+ 1 - 1
MediaBrowser.LocalMetadata/BaseXmlProvider.cs

@@ -75,7 +75,7 @@ namespace MediaBrowser.LocalMetadata
             }
         }
 
-        public int Order
+        public  virtual int Order
         {
             get
             {

+ 1 - 1
MediaBrowser.LocalMetadata/Providers/SeriesXmlProvider.cs

@@ -31,7 +31,7 @@ namespace MediaBrowser.LocalMetadata.Providers
             return directoryService.GetFile(Path.Combine(info.Path, "series.xml"));
         }
 
-        public int Order
+        public override int Order
         {
             get
             {

+ 3 - 1
MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs

@@ -86,6 +86,8 @@ namespace MediaBrowser.MediaEncoding.Encoder
                 "srt",
                 "h264_nvenc",
                 "h264_qsv",
+                "h264_omx",
+                "h264_vaapi",
                 "ac3"
             };
 
@@ -155,4 +157,4 @@ namespace MediaBrowser.MediaEncoding.Encoder
             }
         }
     }
-}
+}

+ 32 - 15
MediaBrowser.MediaEncoding/Encoder/EncodingJobFactory.cs

@@ -522,10 +522,8 @@ namespace MediaBrowser.MediaEncoding.Encoder
         /// <summary>
         /// Gets the name of the output video codec
         /// </summary>
-        /// <param name="state">The state.</param>
-        /// <param name="options">The options.</param>
         /// <returns>System.String.</returns>
-        internal static string GetVideoEncoder(EncodingJob state, EncodingOptions options)
+        internal static string GetVideoEncoder(IMediaEncoder mediaEncoder, EncodingJob state, EncodingOptions options)
         {
             var codec = state.OutputVideoCodec;
 
@@ -533,7 +531,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
             {
                 if (string.Equals(codec, "h264", StringComparison.OrdinalIgnoreCase))
                 {
-                    return GetH264Encoder(state, options);
+                    return GetH264Encoder(mediaEncoder, state, options);
                 }
                 if (string.Equals(codec, "vpx", StringComparison.OrdinalIgnoreCase))
                 {
@@ -554,24 +552,43 @@ namespace MediaBrowser.MediaEncoding.Encoder
             return "copy";
         }
 
-        internal static string GetH264Encoder(EncodingJob state, EncodingOptions options)
+        private static string GetAvailableEncoder(IMediaEncoder mediaEncoder, string preferredEncoder, string defaultEncoder)
         {
-            if (string.Equals(options.HardwareAccelerationType, "qsv", StringComparison.OrdinalIgnoreCase) ||
-                string.Equals(options.HardwareAccelerationType, "h264_qsv", StringComparison.OrdinalIgnoreCase))
+            if (mediaEncoder.SupportsEncoder(preferredEncoder))
             {
-                return "h264_qsv";
+                return preferredEncoder;
             }
+            return defaultEncoder;
+        }
 
-            if (string.Equals(options.HardwareAccelerationType, "nvenc", StringComparison.OrdinalIgnoreCase))
-            {
-                return "h264_nvenc";
-            }
-            if (string.Equals(options.HardwareAccelerationType, "h264_omx", StringComparison.OrdinalIgnoreCase))
+        internal static string GetH264Encoder(IMediaEncoder mediaEncoder, EncodingJob state, EncodingOptions options)
+        {
+            var defaultEncoder = "libx264";
+
+            // Only use alternative encoders for video files.
+            // When using concat with folder rips, if the mfx session fails to initialize, ffmpeg will be stuck retrying and will not exit gracefully
+            // Since transcoding of folder rips is expiremental anyway, it's not worth adding additional variables such as this.
+            if (state.VideoType == VideoType.VideoFile)
             {
-                return "h264_omx";
+                var hwType = options.HardwareAccelerationType;
+
+                if (string.Equals(hwType, "qsv", StringComparison.OrdinalIgnoreCase) ||
+                    string.Equals(hwType, "h264_qsv", StringComparison.OrdinalIgnoreCase))
+                {
+                    return GetAvailableEncoder(mediaEncoder, "h264_qsv", defaultEncoder);
+                }
+
+                if (string.Equals(hwType, "nvenc", StringComparison.OrdinalIgnoreCase))
+                {
+                    return GetAvailableEncoder(mediaEncoder, "h264_nvenc", defaultEncoder);
+                }
+                if (string.Equals(hwType, "h264_omx", StringComparison.OrdinalIgnoreCase))
+                {
+                    return GetAvailableEncoder(mediaEncoder, "h264_omx", defaultEncoder);
+                }
             }
 
-            return "libx264";
+            return defaultEncoder;
         }
 
         internal static bool CanStreamCopyVideo(EncodingJobOptions request, MediaStream videoStream)

+ 1 - 1
MediaBrowser.MediaEncoding/Encoder/FontConfigLoader.cs

@@ -58,7 +58,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
                 else
                 {
                     // Kick this off, but no need to wait on it
-                    Task.Run(async () =>
+                    var task = Task.Run(async () =>
                     {
                         await DownloadFontFile(fontsDirectory, fontFilename, new Progress<double>()).ConfigureAwait(false);
 

+ 2 - 2
MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs

@@ -392,9 +392,9 @@ namespace MediaBrowser.MediaEncoding.Encoder
             //_logger.Info("Supported decoders: {0}", string.Join(",", list.ToArray()));
         }
 
-        public bool SupportsEncoder(string decoder)
+        public bool SupportsEncoder(string encoder)
         {
-            return _encoders.Contains(decoder, StringComparer.OrdinalIgnoreCase);
+            return _encoders.Contains(encoder, StringComparer.OrdinalIgnoreCase);
         }
 
         public bool SupportsDecoder(string decoder)

+ 3 - 3
MediaBrowser.MediaEncoding/Encoder/VideoEncoder.cs

@@ -21,7 +21,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
         protected override async Task<string> GetCommandLineArguments(EncodingJob state)
         {
             // Get the output codec name
-            var videoCodec = EncodingJobFactory.GetVideoEncoder(state, GetEncodingOptions());
+            var videoCodec = EncodingJobFactory.GetVideoEncoder(MediaEncoder, state, GetEncodingOptions());
 
             var format = string.Empty;
             var keyFrame = string.Empty;
@@ -84,7 +84,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
                 return args;
             }
 
-            var keyFrameArg = string.Format(" -force_key_frames expr:gte(t,n_forced*{0})",
+            var keyFrameArg = string.Format(" -force_key_frames \"expr:gte(t,n_forced*{0})\"",
                 5.ToString(UsCulture));
 
             args += keyFrameArg;
@@ -192,4 +192,4 @@ namespace MediaBrowser.MediaEncoding.Encoder
             get { return true; }
         }
     }
-}
+}

+ 2 - 1
MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs

@@ -398,7 +398,8 @@ namespace MediaBrowser.MediaEncoding.Probing
             // These are mp4 chapters
             if (string.Equals(streamInfo.codec_name, "mov_text", StringComparison.OrdinalIgnoreCase))
             {
-                return null;
+                // Edit: but these are also sometimes subtitles?
+                //return null;
             }
 
             var stream = new MediaStream

+ 0 - 30
MediaBrowser.Providers/Manager/MetadataService.cs

@@ -349,9 +349,6 @@ namespace MediaBrowser.Providers.Manager
 
             if (!runAllProviders)
             {
-                // Avoid implicitly captured closure
-                var currentItem = item;
-
                 var providersWithChanges = providers
                     .Where(i =>
                     {
@@ -361,12 +358,6 @@ namespace MediaBrowser.Providers.Manager
                             return HasChanged(item, hasFileChangeMonitor, options.DirectoryService);
                         }
 
-                        var hasChangeMonitor = i as IHasChangeMonitor;
-                        if (hasChangeMonitor != null)
-                        {
-                            return HasChanged(item, hasChangeMonitor, currentItem.DateLastSaved, options.DirectoryService);
-                        }
-
                         return false;
                     })
                     .ToList();
@@ -726,27 +717,6 @@ namespace MediaBrowser.Providers.Manager
                 return false;
             }
         }
-
-        private bool HasChanged(IHasMetadata item, IHasChangeMonitor changeMonitor, DateTime date, IDirectoryService directoryService)
-        {
-            try
-            {
-                var hasChanged = changeMonitor.HasChanged(item, directoryService, date);
-
-                //if (hasChanged)
-                //{
-                //    Logger.Debug("{0} reports change to {1} since {2}", changeMonitor.GetType().Name,
-                //        item.Path ?? item.Name, date);
-                //}
-
-                return hasChanged;
-            }
-            catch (Exception ex)
-            {
-                Logger.ErrorException("Error in {0}.HasChanged", ex, changeMonitor.GetType().Name);
-                return false;
-            }
-        }
     }
 
     public class RefreshResult

+ 2 - 2
MediaBrowser.Providers/Manager/ProviderManager.cs

@@ -298,7 +298,7 @@ namespace MediaBrowser.Providers.Manager
         {
             var options = GetMetadataOptions(item);
 
-			return GetImageProviders(item, options, new ImageRefreshOptions(new DirectoryService(_fileSystem)), includeDisabled).OfType<IRemoteImageProvider>();
+			return GetImageProviders(item, options, new ImageRefreshOptions(new DirectoryService(_logger, _fileSystem)), includeDisabled).OfType<IRemoteImageProvider>();
         }
 
         private bool CanRefresh(IMetadataProvider provider, IHasMetadata item, MetadataOptions options, bool includeDisabled, bool checkIsOwnedItem)
@@ -488,7 +488,7 @@ namespace MediaBrowser.Providers.Manager
                 ItemType = typeof(T).Name
             };
 
-			var imageProviders = GetImageProviders(dummy, options, new ImageRefreshOptions(new DirectoryService(_fileSystem)), true).ToList();
+			var imageProviders = GetImageProviders(dummy, options, new ImageRefreshOptions(new DirectoryService(_logger, _fileSystem)), true).ToList();
 
             AddMetadataPlugins(summary.Plugins, dummy, options);
             AddImagePlugins(summary.Plugins, dummy, imageProviders);

+ 49 - 17
MediaBrowser.Providers/Music/AudioDbAlbumProvider.cs

@@ -61,14 +61,14 @@ namespace MediaBrowser.Providers.Music
                 {
                     result.Item = new MusicAlbum();
                     result.HasMetadata = true;
-                    ProcessResult(result.Item, obj.album[0]);
+                    ProcessResult(result.Item, obj.album[0], info.MetadataLanguage);
                 }
             }
 
             return result;
         }
 
-        private void ProcessResult(MusicAlbum item, Album result)
+        private void ProcessResult(MusicAlbum item, Album result, string preferredLanguage)
         {
             if (!string.IsNullOrWhiteSpace(result.strArtist))
             {
@@ -91,7 +91,39 @@ namespace MediaBrowser.Providers.Music
             item.SetProviderId(MetadataProviders.MusicBrainzAlbumArtist, result.strMusicBrainzArtistID);
             item.SetProviderId(MetadataProviders.MusicBrainzReleaseGroup, result.strMusicBrainzID);
 
-            item.Overview = (result.strDescriptionEN ?? string.Empty).StripHtml();
+            string overview = null;
+
+            if (string.Equals(preferredLanguage, "de", StringComparison.OrdinalIgnoreCase))
+            {
+                overview = result.strDescriptionDE;
+            }
+            else if (string.Equals(preferredLanguage, "fr", StringComparison.OrdinalIgnoreCase))
+            {
+                overview = result.strDescriptionFR;
+            }
+            else if (string.Equals(preferredLanguage, "nl", StringComparison.OrdinalIgnoreCase))
+            {
+                overview = result.strDescriptionNL;
+            }
+            else if (string.Equals(preferredLanguage, "ru", StringComparison.OrdinalIgnoreCase))
+            {
+                overview = result.strDescriptionRU;
+            }
+            else if (string.Equals(preferredLanguage, "it", StringComparison.OrdinalIgnoreCase))
+            {
+                overview = result.strDescriptionIT;
+            }
+            else if ((preferredLanguage ?? string.Empty).StartsWith("pt", StringComparison.OrdinalIgnoreCase))
+            {
+                overview = result.strDescriptionPT;
+            }
+
+            if (string.IsNullOrWhiteSpace(overview))
+            {
+                overview = result.strDescriptionEN;
+            }
+
+            item.Overview = (overview ?? string.Empty).StripHtml();
         }
 
         public string Name
@@ -186,20 +218,20 @@ namespace MediaBrowser.Providers.Music
             public string strAlbumThumb { get; set; }
             public string strAlbumCDart { get; set; }
             public string strDescriptionEN { get; set; }
-            public object strDescriptionDE { get; set; }
-            public object strDescriptionFR { get; set; }
-            public object strDescriptionCN { get; set; }
-            public object strDescriptionIT { get; set; }
-            public object strDescriptionJP { get; set; }
-            public object strDescriptionRU { get; set; }
-            public object strDescriptionES { get; set; }
-            public object strDescriptionPT { get; set; }
-            public object strDescriptionSE { get; set; }
-            public object strDescriptionNL { get; set; }
-            public object strDescriptionHU { get; set; }
-            public object strDescriptionNO { get; set; }
-            public object strDescriptionIL { get; set; }
-            public object strDescriptionPL { get; set; }
+            public string strDescriptionDE { get; set; }
+            public string strDescriptionFR { get; set; }
+            public string strDescriptionCN { get; set; }
+            public string strDescriptionIT { get; set; }
+            public string strDescriptionJP { get; set; }
+            public string strDescriptionRU { get; set; }
+            public string strDescriptionES { get; set; }
+            public string strDescriptionPT { get; set; }
+            public string strDescriptionSE { get; set; }
+            public string strDescriptionNL { get; set; }
+            public string strDescriptionHU { get; set; }
+            public string strDescriptionNO { get; set; }
+            public string strDescriptionIL { get; set; }
+            public string strDescriptionPL { get; set; }
             public object intLoved { get; set; }
             public object intScore { get; set; }
             public string strReview { get; set; }

+ 47 - 14
MediaBrowser.Providers/Music/AudioDbArtistProvider.cs

@@ -61,17 +61,16 @@ namespace MediaBrowser.Providers.Music
                 {
                     result.Item = new MusicArtist();
                     result.HasMetadata = true;
-                    ProcessResult(result.Item, obj.artists[0]);
+                    ProcessResult(result.Item, obj.artists[0], info.MetadataLanguage);
                 }
             }
 
             return result;
         }
 
-        private void ProcessResult(MusicArtist item, Artist result)
+        private void ProcessResult(MusicArtist item, Artist result, string preferredLanguage)
         {
             item.HomePageUrl = result.strWebsite;
-            item.Overview = (result.strBiographyEN ?? string.Empty).StripHtml();
 
             if (!string.IsNullOrEmpty(result.strGenre))
             {
@@ -80,6 +79,40 @@ namespace MediaBrowser.Providers.Music
 
             item.SetProviderId(MetadataProviders.AudioDbArtist, result.idArtist);
             item.SetProviderId(MetadataProviders.MusicBrainzArtist, result.strMusicBrainzID);
+
+            string overview = null;
+
+            if (string.Equals(preferredLanguage, "de", StringComparison.OrdinalIgnoreCase))
+            {
+                overview = result.strBiographyDE;
+            }
+            else if (string.Equals(preferredLanguage, "fr", StringComparison.OrdinalIgnoreCase))
+            {
+                overview = result.strBiographyFR;
+            }
+            else if (string.Equals(preferredLanguage, "nl", StringComparison.OrdinalIgnoreCase))
+            {
+                overview = result.strBiographyNL;
+            }
+            else if (string.Equals(preferredLanguage, "ru", StringComparison.OrdinalIgnoreCase))
+            {
+                overview = result.strBiographyRU;
+            }
+            else if (string.Equals(preferredLanguage, "it", StringComparison.OrdinalIgnoreCase))
+            {
+                overview = result.strBiographyIT;
+            }
+            else if ((preferredLanguage ?? string.Empty).StartsWith("pt", StringComparison.OrdinalIgnoreCase))
+            {
+                overview = result.strBiographyPT;
+            }
+
+            if (string.IsNullOrWhiteSpace(overview))
+            {
+                overview = result.strBiographyEN;
+            }
+
+            item.Overview = (overview ?? string.Empty).StripHtml();
         }
 
         public string Name
@@ -180,18 +213,18 @@ namespace MediaBrowser.Providers.Music
             public string strBiographyEN { get; set; }
             public string strBiographyDE { get; set; }
             public string strBiographyFR { get; set; }
-            public object strBiographyCN { get; set; }
+            public string strBiographyCN { get; set; }
             public string strBiographyIT { get; set; }
-            public object strBiographyJP { get; set; }
-            public object strBiographyRU { get; set; }
-            public object strBiographyES { get; set; }
-            public object strBiographyPT { get; set; }
-            public object strBiographySE { get; set; }
-            public object strBiographyNL { get; set; }
-            public object strBiographyHU { get; set; }
-            public object strBiographyNO { get; set; }
-            public object strBiographyIL { get; set; }
-            public object strBiographyPL { get; set; }
+            public string strBiographyJP { get; set; }
+            public string strBiographyRU { get; set; }
+            public string strBiographyES { get; set; }
+            public string strBiographyPT { get; set; }
+            public string strBiographySE { get; set; }
+            public string strBiographyNL { get; set; }
+            public string strBiographyHU { get; set; }
+            public string strBiographyNO { get; set; }
+            public string strBiographyIL { get; set; }
+            public string strBiographyPL { get; set; }
             public string strGender { get; set; }
             public string intMembers { get; set; }
             public string strCountry { get; set; }

+ 1 - 1
MediaBrowser.Providers/Subtitles/SubtitleManager.cs

@@ -254,7 +254,7 @@ namespace MediaBrowser.Providers.Subtitles
                 _monitor.ReportFileSystemChangeComplete(path, false);
             }
 
-            return _libraryManager.GetItemById(itemId).RefreshMetadata(new MetadataRefreshOptions(new DirectoryService(_fileSystem))
+            return _libraryManager.GetItemById(itemId).RefreshMetadata(new MetadataRefreshOptions(new DirectoryService(_logger, _fileSystem))
             {
                 ImageRefreshMode = ImageRefreshMode.ValidationOnly,
                 MetadataRefreshMode = MetadataRefreshMode.ValidationOnly

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

@@ -133,7 +133,7 @@ namespace MediaBrowser.Providers.TV
             {
                 foreach (var series in group)
                 {
-                    var directoryService = new DirectoryService(_fileSystem);
+                    var directoryService = new DirectoryService(_logger, _fileSystem);
 
                     await series.RefreshMetadata(new MetadataRefreshOptions(directoryService), cancellationToken).ConfigureAwait(false);
 

+ 5 - 6
MediaBrowser.Server.Implementations/Connect/ConnectManager.cs

@@ -65,12 +65,11 @@ namespace MediaBrowser.Server.Implementations.Connect
 
                 if (!string.IsNullOrWhiteSpace(address))
                 {
-                    try
-                    {
-                        address = new Uri(address).Host;
-                    }
-                    catch
+                    Uri newUri;
+
+                    if (Uri.TryCreate(address, UriKind.Absolute, out newUri))
                     {
+                        address = newUri.Host;
                     }
                 }
 
@@ -151,7 +150,7 @@ namespace MediaBrowser.Server.Implementations.Connect
         {
             DiscoveredWanIpAddress = address;
 
-            UpdateConnectInfo();
+            var task = UpdateConnectInfo();
         }
 
         private async Task UpdateConnectInfo()

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

@@ -1620,7 +1620,7 @@ namespace MediaBrowser.Server.Implementations.Dto
             {
                 size = _imageProcessor.GetImageSize(imageInfo);
             }
-            catch (Exception ex)
+            catch
             {
                 //_logger.ErrorException("Failed to determine primary image aspect ratio for {0}", ex, path);
                 return null;

+ 1 - 1
MediaBrowser.Server.Implementations/EntryPoints/ActivityLogEntryPoint.cs

@@ -29,7 +29,7 @@ namespace MediaBrowser.Server.Implementations.EntryPoints
         private readonly IInstallationManager _installationManager;
 
         //private readonly ILogManager _logManager;
-        private readonly ILogger _logger;
+        //private readonly ILogger _logger;
         private readonly ISessionManager _sessionManager;
         private readonly ITaskManager _taskManager;
         private readonly IActivityManager _activityManager;

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

@@ -165,7 +165,7 @@ namespace MediaBrowser.Server.Implementations.EntryPoints
 
                 CreateRules(device);
             }
-            catch (Exception ex)
+            catch
             {
                 // I think it could be a good idea to log the exception because 
                 //   you are using permanent portmapping here (never expire) and that means that next time

+ 1 - 1
MediaBrowser.Server.Implementations/EntryPoints/UserDataChangeNotifier.cs

@@ -92,7 +92,7 @@ namespace MediaBrowser.Server.Implementations.EntryPoints
                 var changes = _changedItems.ToList();
                 _changedItems.Clear();
 
-                SendNotifications(changes, CancellationToken.None);
+                var task = SendNotifications(changes, CancellationToken.None);
 
                 if (UpdateTimer != null)
                 {

+ 1 - 1
MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs

@@ -251,7 +251,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer
 
                 httpRes.Close();
             }
-            catch (Exception errorEx)
+            catch
             {
                 //_logger.ErrorException("Error this.ProcessRequest(context)(Exception while writing error to the response)", errorEx);
             }

+ 1 - 1
MediaBrowser.Server.Implementations/HttpServer/RangeRequestWriter.cs

@@ -191,7 +191,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer
                     }
                 }
             }
-            catch (IOException ex)
+            catch (IOException)
             {
                 throw;
             }

+ 17 - 6
MediaBrowser.Server.Implementations/Library/LibraryManager.cs

@@ -923,14 +923,14 @@ namespace MediaBrowser.Server.Implementations.Library
 
             if (type == typeof(Person))
             {
-                var subFolderIndex = 0;
-
-                while (!char.IsLetterOrDigit(validFilename[subFolderIndex]))
+                foreach (char c in validFilename)
                 {
-                    subFolderIndex++;
+                    if (char.IsLetterOrDigit(c))
+                    {
+                        subFolderPrefix = c.ToString();
+                        break;
+                    }
                 }
-
-                subFolderPrefix = validFilename.Substring(subFolderIndex, 1);
             }
 
             var fullPath = string.IsNullOrEmpty(subFolderPrefix) ?
@@ -1385,6 +1385,17 @@ namespace MediaBrowser.Server.Implementations.Library
             return ItemRepository.GetMusicGenres(query);
         }
 
+        public QueryResult<Tuple<BaseItem, ItemCounts>> GetAllArtists(InternalItemsQuery query)
+        {
+            if (query.User != null)
+            {
+                AddUserToQuery(query, query.User);
+            }
+
+            SetTopParentOrAncestorIds(query);
+            return ItemRepository.GetAllArtists(query);
+        }
+
         public QueryResult<Tuple<BaseItem, ItemCounts>> GetArtists(InternalItemsQuery query)
         {
             if (query.User != null)

+ 19 - 15
MediaBrowser.Server.Implementations/Library/Validators/ArtistsValidator.cs

@@ -6,6 +6,7 @@ using System.IO;
 using System.Linq;
 using System.Threading;
 using System.Threading.Tasks;
+using MediaBrowser.Controller.Entities;
 
 namespace MediaBrowser.Server.Implementations.Library.Validators
 {
@@ -43,36 +44,39 @@ namespace MediaBrowser.Server.Implementations.Library.Validators
         /// <returns>Task.</returns>
         public async Task Run(IProgress<double> progress, CancellationToken cancellationToken)
         {
-            var allSongs = _libraryManager.RootFolder
-                .GetRecursiveChildren(i => !i.IsFolder && i is IHasArtist)
-                .Cast<IHasArtist>()
+            var items = _libraryManager.GetAllArtists(new InternalItemsQuery())
+                .Items
+                .Select(i => i.Item1)
                 .ToList();
 
-            var allArtists = _libraryManager.GetArtists(allSongs).ToList();
-
             var numComplete = 0;
-            var numArtists = allArtists.Count;
+            var count = items.Count;
 
-            foreach (var artistItem in allArtists)
+            foreach (var item in items)
             {
-                cancellationToken.ThrowIfCancellationRequested();
-
                 try
                 {
-                    await artistItem.RefreshMetadata(cancellationToken).ConfigureAwait(false);
+                    await item.RefreshMetadata(cancellationToken).ConfigureAwait(false);
                 }
-                catch (IOException ex)
+                catch (OperationCanceledException)
                 {
-                    _logger.ErrorException("Error validating Artist {0}", ex, artistItem.Name);
+                    // Don't clutter the log
+                    break;
+                }
+                catch (Exception ex)
+                {
+                    _logger.ErrorException("Error refreshing {0}", ex, item.Name);
                 }
 
-                // Update progress
                 numComplete++;
                 double percent = numComplete;
-                percent /= numArtists;
+                percent /= count;
+                percent *= 100;
 
-                progress.Report(100 * percent);
+                progress.Report(percent);
             }
+
+            progress.Report(100);
         }
     }
 }

+ 9 - 8
MediaBrowser.Server.Implementations/Library/Validators/GameGenresValidator.cs

@@ -34,21 +34,22 @@ namespace MediaBrowser.Server.Implementations.Library.Validators
         /// <returns>Task.</returns>
         public async Task Run(IProgress<double> progress, CancellationToken cancellationToken)
         {
-            var items = _libraryManager.RootFolder.GetRecursiveChildren(i => i is Game)
-                .SelectMany(i => i.Genres)
-                .DistinctNames()
+            var items = _libraryManager.GetGameGenres(new InternalItemsQuery
+            {
+                IncludeItemTypes = new[] { typeof(Game).Name }
+            })
+                .Items
+                .Select(i => i.Item1)
                 .ToList();
 
             var numComplete = 0;
             var count = items.Count;
 
-            foreach (var name in items)
+            foreach (var item in items)
             {
                 try
                 {
-                    var itemByName = _libraryManager.GetGameGenre(name);
-
-                    await itemByName.RefreshMetadata(cancellationToken).ConfigureAwait(false);
+                    await item.RefreshMetadata(cancellationToken).ConfigureAwait(false);
                 }
                 catch (OperationCanceledException)
                 {
@@ -57,7 +58,7 @@ namespace MediaBrowser.Server.Implementations.Library.Validators
                 }
                 catch (Exception ex)
                 {
-                    _logger.ErrorException("Error refreshing {0}", ex, name);
+                    _logger.ErrorException("Error refreshing {0}", ex, item.Name);
                 }
 
                 numComplete++;

+ 9 - 8
MediaBrowser.Server.Implementations/Library/Validators/GenresValidator.cs

@@ -35,21 +35,22 @@ namespace MediaBrowser.Server.Implementations.Library.Validators
         /// <returns>Task.</returns>
         public async Task Run(IProgress<double> progress, CancellationToken cancellationToken)
         {
-            var items = _libraryManager.RootFolder.GetRecursiveChildren(i => !(i is IHasMusicGenres) && !(i is Game))
-                .SelectMany(i => i.Genres)
-                .DistinctNames()
+            var items = _libraryManager.GetGenres(new InternalItemsQuery
+            {
+                ExcludeItemTypes = new[] { typeof(Audio).Name, typeof(MusicArtist).Name, typeof(MusicAlbum).Name, typeof(MusicVideo).Name, typeof(Game).Name }
+            })
+                .Items
+                .Select(i => i.Item1)
                 .ToList();
 
             var numComplete = 0;
             var count = items.Count;
 
-            foreach (var name in items)
+            foreach (var item in items)
             {
                 try
                 {
-                    var itemByName = _libraryManager.GetGenre(name);
-
-                    await itemByName.RefreshMetadata(cancellationToken).ConfigureAwait(false);
+                    await item.RefreshMetadata(cancellationToken).ConfigureAwait(false);
                 }
                 catch (OperationCanceledException)
                 {
@@ -58,7 +59,7 @@ namespace MediaBrowser.Server.Implementations.Library.Validators
                 }
                 catch (Exception ex)
                 {
-                    _logger.ErrorException("Error refreshing {0}", ex, name);
+                    _logger.ErrorException("Error refreshing {0}", ex, item.Name);
                 }
 
                 numComplete++;

+ 10 - 8
MediaBrowser.Server.Implementations/Library/Validators/MusicGenresValidator.cs

@@ -5,6 +5,7 @@ using System;
 using System.Linq;
 using System.Threading;
 using System.Threading.Tasks;
+using MediaBrowser.Controller.Entities;
 
 namespace MediaBrowser.Server.Implementations.Library.Validators
 {
@@ -34,21 +35,22 @@ namespace MediaBrowser.Server.Implementations.Library.Validators
         /// <returns>Task.</returns>
         public async Task Run(IProgress<double> progress, CancellationToken cancellationToken)
         {
-            var items = _libraryManager.RootFolder.GetRecursiveChildren(i => i is IHasMusicGenres)
-                .SelectMany(i => i.Genres)
-                .DistinctNames()
+            var items = _libraryManager.GetMusicGenres(new InternalItemsQuery
+            {
+                IncludeItemTypes = new[] { typeof(Audio).Name, typeof(MusicArtist).Name, typeof(MusicAlbum).Name, typeof(MusicVideo).Name }
+            })
+                .Items
+                .Select(i => i.Item1)
                 .ToList();
 
             var numComplete = 0;
             var count = items.Count;
 
-            foreach (var name in items)
+            foreach (var item in items)
             {
                 try
                 {
-                    var itemByName = _libraryManager.GetMusicGenre(name);
-
-                    await itemByName.RefreshMetadata(cancellationToken).ConfigureAwait(false);
+                    await item.RefreshMetadata(cancellationToken).ConfigureAwait(false);
                 }
                 catch (OperationCanceledException)
                 {
@@ -57,7 +59,7 @@ namespace MediaBrowser.Server.Implementations.Library.Validators
                 }
                 catch (Exception ex)
                 {
-                    _logger.ErrorException("Error refreshing {0}", ex, name);
+                    _logger.ErrorException("Error refreshing {0}", ex, item.Name);
                 }
 
                 numComplete++;

+ 2 - 2
MediaBrowser.Server.Implementations/Library/Validators/PeopleValidator.cs

@@ -125,7 +125,6 @@ namespace MediaBrowser.Server.Implementations.Library.Validators
 
                     var hasMetdata = !string.IsNullOrWhiteSpace(item.Overview);
                     var performFullRefresh = !hasMetdata && (DateTime.UtcNow - item.DateLastRefreshed).TotalDays >= 90;
-                    performFullRefresh = false;
 
                     var defaultMetadataRefreshMode = performFullRefresh
                         ? MetadataRefreshMode.FullRefresh
@@ -138,7 +137,8 @@ namespace MediaBrowser.Server.Implementations.Library.Validators
                     var options = new MetadataRefreshOptions(_fileSystem)
                     {
                         MetadataRefreshMode = person.Value ? defaultMetadataRefreshMode : MetadataRefreshMode.ValidationOnly,
-                        ImageRefreshMode = person.Value ? imageRefreshMode : ImageRefreshMode.ValidationOnly
+                        ImageRefreshMode = person.Value ? imageRefreshMode : ImageRefreshMode.ValidationOnly,
+                        ForceSave = performFullRefresh
                     };
 
                     await item.RefreshMetadata(options, cancellationToken).ConfigureAwait(false);

+ 7 - 9
MediaBrowser.Server.Implementations/Library/Validators/StudiosValidator.cs

@@ -1,10 +1,10 @@
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Model.Logging;
 using System;
-using System.Collections.Generic;
 using System.Linq;
 using System.Threading;
 using System.Threading.Tasks;
+using MediaBrowser.Controller.Entities;
 
 namespace MediaBrowser.Server.Implementations.Library.Validators
 {
@@ -34,21 +34,19 @@ namespace MediaBrowser.Server.Implementations.Library.Validators
         /// <returns>Task.</returns>
         public async Task Run(IProgress<double> progress, CancellationToken cancellationToken)
         {
-            var items = _libraryManager.RootFolder.GetRecursiveChildren(i => true)
-                .SelectMany(i => i.Studios)
-                .DistinctNames()
+            var items = _libraryManager.GetStudios(new InternalItemsQuery())
+                .Items
+                .Select(i => i.Item1)
                 .ToList();
 
             var numComplete = 0;
             var count = items.Count;
 
-            foreach (var name in items)
+            foreach (var item in items)
             {
                 try
                 {
-                    var itemByName = _libraryManager.GetStudio(name);
-
-                    await itemByName.RefreshMetadata(cancellationToken).ConfigureAwait(false);
+                    await item.RefreshMetadata(cancellationToken).ConfigureAwait(false);
                 }
                 catch (OperationCanceledException)
                 {
@@ -57,7 +55,7 @@ namespace MediaBrowser.Server.Implementations.Library.Validators
                 }
                 catch (Exception ex)
                 {
-                    _logger.ErrorException("Error refreshing {0}", ex, name);
+                    _logger.ErrorException("Error refreshing {0}", ex, item.Name);
                 }
 
                 numComplete++;

+ 2 - 2
MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs

@@ -55,8 +55,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
 
         public static EmbyTV Current;
 
-        public event EventHandler DataSourceChanged;
-        public event EventHandler<RecordingStatusChangedEventArgs> RecordingStatusChanged;
+        public event EventHandler DataSourceChanged { add { } remove { } }
+        public event EventHandler<RecordingStatusChangedEventArgs> RecordingStatusChanged { add { } remove { } }
 
         private readonly ConcurrentDictionary<string, ActiveRecordingInfo> _activeRecordings =
             new ConcurrentDictionary<string, ActiveRecordingInfo>(StringComparer.OrdinalIgnoreCase);

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

@@ -191,7 +191,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
             {
                 var maxBitrate = 25000000;
                 videoArgs = string.Format(
-                        "-codec:v:0 libx264 -force_key_frames expr:gte(t,n_forced*5) {0} -pix_fmt yuv420p -preset superfast -crf 23 -b:v {1} -maxrate {1} -bufsize ({1}*2) -vsync -1 -profile:v high -level 41",
+                        "-codec:v:0 libx264 -force_key_frames \"expr:gte(t,n_forced*5)\" {0} -pix_fmt yuv420p -preset superfast -crf 23 -b:v {1} -maxrate {1} -bufsize ({1}*2) -vsync -1 -profile:v high -level 41",
                         GetOutputSizeParam(),
                         maxBitrate.ToString(CultureInfo.InvariantCulture));
             }
@@ -354,4 +354,4 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
             }
         }
     }
-}
+}

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

@@ -52,7 +52,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
             catch (FileNotFoundException)
             {
             }
-            catch (DirectoryNotFoundException ex)
+            catch (DirectoryNotFoundException)
             {
             }
             catch (IOException ex)

+ 10 - 10
MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs

@@ -133,7 +133,10 @@ namespace MediaBrowser.Server.Implementations.LiveTv
 
         void service_DataSourceChanged(object sender, EventArgs e)
         {
-            _taskManager.CancelIfRunningAndQueue<RefreshChannelsScheduledTask>();
+            if (!_isDisposed)
+            {
+                _taskManager.CancelIfRunningAndQueue<RefreshChannelsScheduledTask>();
+            }
         }
 
         public async Task<QueryResult<LiveTvChannel>> GetInternalChannels(LiveTvChannelQuery query, CancellationToken cancellationToken)
@@ -1238,7 +1241,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
             var programs = new List<Guid>();
             var channels = new List<Guid>();
 
-            var guideDays = GetGuideDays(list.Count);
+            var guideDays = GetGuideDays();
 
             _logger.Info("Refreshing guide with {0} days of guide data", guideDays);
 
@@ -1326,7 +1329,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
         }
 
         private const int MaxGuideDays = 14;
-        private double GetGuideDays(int channelCount)
+        private double GetGuideDays()
         {
             var config = GetConfiguration();
 
@@ -1335,13 +1338,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
                 return Math.Max(1, Math.Min(config.GuideDays.Value, MaxGuideDays));
             }
 
-            var programsPerDay = channelCount * 48;
-
-            const int maxPrograms = 24000;
-
-            var days = Math.Round((double)maxPrograms / programsPerDay);
-
-            return Math.Max(3, Math.Min(days, MaxGuideDays));
+            return 7;
         }
 
         private async Task<IEnumerable<Tuple<string, ChannelInfo>>> GetChannels(ILiveTvService service, CancellationToken cancellationToken)
@@ -2309,6 +2306,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv
         }
 
         private readonly object _disposeLock = new object();
+        private bool _isDisposed = false;
         /// <summary>
         /// Releases unmanaged and - optionally - managed resources.
         /// </summary>
@@ -2317,6 +2315,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv
         {
             if (dispose)
             {
+                _isDisposed = true;
+
                 lock (_disposeLock)
                 {
                     foreach (var stream in _openStreams.Values.ToList())

+ 1 - 1
MediaBrowser.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs

@@ -431,7 +431,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.HdHomerun
                     list.Add(await GetMediaSource(info, hdhrId, "mobile").ConfigureAwait(false));
                 }
             }
-            catch (Exception ex)
+            catch
             {
 
             }

+ 1 - 1
MediaBrowser.Server.Implementations/LiveTv/TunerHosts/SatIp/Rtsp/RtspSession.cs

@@ -649,7 +649,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.SatIp.Rtsp
 
         #region Public Events
 
-        public event PropertyChangedEventHandler PropertyChanged;
+        ////public event PropertyChangedEventHandler PropertyChanged;
 
         #endregion
 

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

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

+ 1 - 1
MediaBrowser.Server.Implementations/Notifications/SqliteNotificationsRepository.cs

@@ -22,7 +22,7 @@ namespace MediaBrowser.Server.Implementations.Notifications
 
         public event EventHandler<NotificationUpdateEventArgs> NotificationAdded;
         public event EventHandler<NotificationReadEventArgs> NotificationsMarkedRead;
-        public event EventHandler<NotificationUpdateEventArgs> NotificationUpdated;
+        ////public event EventHandler<NotificationUpdateEventArgs> NotificationUpdated;
 
         public async Task Initialize()
         {

+ 41 - 23
MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs

@@ -95,7 +95,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
         private IDbCommand _updateInheritedRatingCommand;
         private IDbCommand _updateInheritedTagsCommand;
 
-        public const int LatestSchemaVersion = 108;
+        public const int LatestSchemaVersion = 109;
 
         /// <summary>
         /// Initializes a new instance of the <see cref="SqliteItemRepository"/> class.
@@ -915,7 +915,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
                     }
                     else
                     {
-                        _saveItemCommand.GetParameter(index++).Value = item.Name.RemoveDiacritics();
+                        _saveItemCommand.GetParameter(index++).Value = GetCleanValue(item.Name);
                     }
 
                     _saveItemCommand.GetParameter(index++).Value = item.PresentationUniqueKey;
@@ -2763,13 +2763,13 @@ namespace MediaBrowser.Server.Implementations.Persistence
             if (!string.IsNullOrWhiteSpace(query.Name))
             {
                 whereClauses.Add("CleanName=@Name");
-                cmd.Parameters.Add(cmd, "@Name", DbType.String).Value = query.Name.RemoveDiacritics();
+                cmd.Parameters.Add(cmd, "@Name", DbType.String).Value = GetCleanValue(query.Name);
             }
 
             if (!string.IsNullOrWhiteSpace(query.NameContains))
             {
                 whereClauses.Add("CleanName like @NameContains");
-                cmd.Parameters.Add(cmd, "@NameContains", DbType.String).Value = "%" + query.NameContains.RemoveDiacritics() + "%";
+                cmd.Parameters.Add(cmd, "@NameContains", DbType.String).Value = "%" + GetCleanValue(query.NameContains) + "%";
             }
             if (!string.IsNullOrWhiteSpace(query.NameStartsWith))
             {
@@ -2877,7 +2877,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
                 foreach (var artist in query.ArtistNames)
                 {
                     clauses.Add("@ArtistName" + index + " in (select CleanValue from itemvalues where ItemId=Guid and Type <= 1)");
-                    cmd.Parameters.Add(cmd, "@ArtistName" + index, DbType.String).Value = artist.RemoveDiacritics();
+                    cmd.Parameters.Add(cmd, "@ArtistName" + index, DbType.String).Value = GetCleanValue(artist);
                     index++;
                 }
                 var clause = "(" + string.Join(" OR ", clauses.ToArray()) + ")";
@@ -2894,7 +2894,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
                     if (artistItem != null)
                     {
                         clauses.Add("@ExcludeArtistName" + index + " not in (select CleanValue from itemvalues where ItemId=Guid and Type <= 1)");
-                        cmd.Parameters.Add(cmd, "@ExcludeArtistName" + index, DbType.String).Value = artistItem.Name.RemoveDiacritics();
+                        cmd.Parameters.Add(cmd, "@ExcludeArtistName" + index, DbType.String).Value = GetCleanValue(artistItem.Name);
                         index++;
                     }
                 }
@@ -2915,7 +2915,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
                 foreach (var item in query.Genres)
                 {
                     clauses.Add("@Genre" + index + " in (select CleanValue from itemvalues where ItemId=Guid and Type=2)");
-                    cmd.Parameters.Add(cmd, "@Genre" + index, DbType.String).Value = item.RemoveDiacritics();
+                    cmd.Parameters.Add(cmd, "@Genre" + index, DbType.String).Value = GetCleanValue(item);
                     index++;
                 }
                 var clause = "(" + string.Join(" OR ", clauses.ToArray()) + ")";
@@ -2929,7 +2929,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
                 foreach (var item in query.Tags)
                 {
                     clauses.Add("@Tag" + index + " in (select CleanValue from itemvalues where ItemId=Guid and Type=4)");
-                    cmd.Parameters.Add(cmd, "@Tag" + index, DbType.String).Value = item.RemoveDiacritics();
+                    cmd.Parameters.Add(cmd, "@Tag" + index, DbType.String).Value = GetCleanValue(item);
                     index++;
                 }
                 var clause = "(" + string.Join(" OR ", clauses.ToArray()) + ")";
@@ -2949,7 +2949,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
                 foreach (var item in query.Studios)
                 {
                     clauses.Add("@Studio" + index + " in (select CleanValue from itemvalues where ItemId=Guid and Type=3)");
-                    cmd.Parameters.Add(cmd, "@Studio" + index, DbType.String).Value = item.RemoveDiacritics();
+                    cmd.Parameters.Add(cmd, "@Studio" + index, DbType.String).Value = GetCleanValue(item);
                     index++;
                 }
                 var clause = "(" + string.Join(" OR ", clauses.ToArray()) + ")";
@@ -2963,7 +2963,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
                 foreach (var item in query.Keywords)
                 {
                     clauses.Add("@Keyword" + index + " in (select CleanValue from itemvalues where ItemId=Guid and Type=5)");
-                    cmd.Parameters.Add(cmd, "@Keyword" + index, DbType.String).Value = item.RemoveDiacritics();
+                    cmd.Parameters.Add(cmd, "@Keyword" + index, DbType.String).Value = GetCleanValue(item);
                     index++;
                 }
                 var clause = "(" + string.Join(" OR ", clauses.ToArray()) + ")";
@@ -3298,6 +3298,16 @@ namespace MediaBrowser.Server.Implementations.Persistence
             return whereClauses;
         }
 
+        private string GetCleanValue(string value)
+        {
+            if (string.IsNullOrWhiteSpace(value))
+            {
+                return value;
+            }
+
+            return value.RemoveDiacritics().ToLower();
+        }
+
         private bool EnableGroupByPresentationUniqueKey(InternalItemsQuery query)
         {
             if (!query.GroupByPresentationUniqueKey)
@@ -3817,37 +3827,42 @@ namespace MediaBrowser.Server.Implementations.Persistence
             }
         }
 
+        public QueryResult<Tuple<BaseItem, ItemCounts>> GetAllArtists(InternalItemsQuery query)
+        {
+            return GetItemValues(query, new[] { 0, 1 }, typeof(MusicArtist).FullName);
+        }
+
         public QueryResult<Tuple<BaseItem, ItemCounts>> GetArtists(InternalItemsQuery query)
         {
-            return GetItemValues(query, 0, typeof(MusicArtist).FullName);
+            return GetItemValues(query, new[] { 0 }, typeof(MusicArtist).FullName);
         }
 
         public QueryResult<Tuple<BaseItem, ItemCounts>> GetAlbumArtists(InternalItemsQuery query)
         {
-            return GetItemValues(query, 1, typeof(MusicArtist).FullName);
+            return GetItemValues(query, new[] { 1 }, typeof(MusicArtist).FullName);
         }
 
         public QueryResult<Tuple<BaseItem, ItemCounts>> GetStudios(InternalItemsQuery query)
         {
-            return GetItemValues(query, 3, typeof(Studio).FullName);
+            return GetItemValues(query, new[] { 3 }, typeof(Studio).FullName);
         }
 
         public QueryResult<Tuple<BaseItem, ItemCounts>> GetGenres(InternalItemsQuery query)
         {
-            return GetItemValues(query, 2, typeof(Genre).FullName);
+            return GetItemValues(query, new[] { 2 }, typeof(Genre).FullName);
         }
 
         public QueryResult<Tuple<BaseItem, ItemCounts>> GetGameGenres(InternalItemsQuery query)
         {
-            return GetItemValues(query, 2, typeof(GameGenre).FullName);
+            return GetItemValues(query, new[] { 2 }, typeof(GameGenre).FullName);
         }
 
         public QueryResult<Tuple<BaseItem, ItemCounts>> GetMusicGenres(InternalItemsQuery query)
         {
-            return GetItemValues(query, 2, typeof(MusicGenre).FullName);
+            return GetItemValues(query, new[] { 2 }, typeof(MusicGenre).FullName);
         }
 
-        private QueryResult<Tuple<BaseItem, ItemCounts>> GetItemValues(InternalItemsQuery query, int itemValueType, string returnType)
+        private QueryResult<Tuple<BaseItem, ItemCounts>> GetItemValues(InternalItemsQuery query, int[] itemValueTypes, string returnType)
         {
             if (query == null)
             {
@@ -3863,6 +3878,10 @@ namespace MediaBrowser.Server.Implementations.Persistence
 
             var now = DateTime.UtcNow;
 
+            var typeClause = itemValueTypes.Length == 1 ?
+                ("Type=" + itemValueTypes[0].ToString(CultureInfo.InvariantCulture)) :
+                ("Type in (" + string.Join(",", itemValueTypes.Select(i => i.ToString(CultureInfo.InvariantCulture)).ToArray()) + ")");
+
             using (var cmd = _connection.CreateCommand())
             {
                 var itemCountColumns = new List<Tuple<string, string>>();
@@ -3887,7 +3906,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
                     };
                     var whereClauses = GetWhereClauses(typeSubQuery, cmd, "itemTypes");
 
-                    whereClauses.Add("guid in (select ItemId from ItemValues where ItemValues.CleanValue=A.CleanName AND Type=@ItemValueType)");
+                    whereClauses.Add("guid in (select ItemId from ItemValues where ItemValues.CleanValue=A.CleanName AND " + typeClause + ")");
 
                     var typeWhereText = whereClauses.Count == 0 ?
                         string.Empty :
@@ -3929,12 +3948,12 @@ namespace MediaBrowser.Server.Implementations.Persistence
 
                 if (typesToCount.Count == 0)
                 {
-                    whereText += " And CleanName In (Select CleanValue from ItemValues where Type=@ItemValueType AND ItemId in (select guid from TypedBaseItems" + innerWhereText + "))";
+                    whereText += " And CleanName In (Select CleanValue from ItemValues where " + typeClause + " AND ItemId in (select guid from TypedBaseItems" + innerWhereText + "))";
                 }
                 else
                 {
                     //whereText += " And itemTypes not null";
-                    whereText += " And CleanName In (Select CleanValue from ItemValues where Type=@ItemValueType AND ItemId in (select guid from TypedBaseItems" + innerWhereText + "))";
+                    whereText += " And CleanName In (Select CleanValue from ItemValues where " + typeClause + " AND ItemId in (select guid from TypedBaseItems" + innerWhereText + "))";
                 }
 
                 var outerQuery = new InternalItemsQuery(query.User)
@@ -3964,7 +3983,6 @@ namespace MediaBrowser.Server.Implementations.Persistence
                 cmd.CommandText += " group by PresentationUniqueKey";
 
                 cmd.Parameters.Add(cmd, "@SelectType", DbType.String).Value = returnType;
-                cmd.Parameters.Add(cmd, "@ItemValueType", DbType.Int32).Value = itemValueType;
 
                 if (EnableJoinUserData(query))
                 {
@@ -4016,7 +4034,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
                     ? (CommandBehavior.SequentialAccess | CommandBehavior.SingleResult)
                     : CommandBehavior.SequentialAccess;
 
-                //Logger.Debug("GetItemValues: " + cmd.CommandText);
+                Logger.Debug("GetItemValues: " + cmd.CommandText);
 
                 using (var reader = cmd.ExecuteReader(commandBehavior))
                 {
@@ -4260,7 +4278,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
                 }
                 else
                 {
-                    _saveItemValuesCommand.GetParameter(3).Value = pair.Item2.RemoveDiacritics();
+                    _saveItemValuesCommand.GetParameter(3).Value = GetCleanValue(pair.Item2);
                 }
                 _saveItemValuesCommand.Transaction = transaction;
 

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

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

+ 3 - 3
MediaBrowser.Server.Startup.Common/ApplicationHost.cs

@@ -606,7 +606,7 @@ namespace MediaBrowser.Server.Startup.Common
                 {
                     return new ImageMagickEncoder(LogManager.GetLogger("ImageMagick"), ApplicationPaths, HttpClient, FileSystemManager, ServerConfigurationManager);
                 }
-                catch (Exception ex)
+                catch
                 {
                     Logger.Error("Error loading ImageMagick. Will revert to GDI.");
                 }
@@ -616,7 +616,7 @@ namespace MediaBrowser.Server.Startup.Common
             {
                 return new GDIImageEncoder(FileSystemManager, LogManager.GetLogger("GDI"));
             }
-            catch (Exception ex)
+            catch
             {
                 Logger.Error("Error loading GDI. Will revert to NullImageEncoder.");
             }
@@ -1412,7 +1412,7 @@ namespace MediaBrowser.Server.Startup.Common
             {
                 return new Uri(externalDns).Host;
             }
-            catch (Exception e)
+            catch
             {
                 return externalDns;
             }

+ 7 - 7
MediaBrowser.Tests/ConsistencyTests/StringUsageReporter.cs

@@ -71,7 +71,7 @@ namespace MediaBrowser.Tests.ConsistencyTests
         /// <summary>
         /// List of file extension to search.
         /// </summary>
-        public static string[] TargetExtensions = new[] { "js", "html" };
+        public static string[] TargetExtensions = new[] { ".js", ".html" };
 
         /// <summary>
         /// List of paths to exclude from search.
@@ -96,11 +96,11 @@ namespace MediaBrowser.Tests.ConsistencyTests
             }
         }
 
-        [TestMethod]
-        public void ReportStringUsage()
-        {
-            this.CheckDashboardStrings(false);
-        }
+        //[TestMethod]
+        //public void ReportStringUsage()
+        //{
+        //    this.CheckDashboardStrings(false);
+        //}
 
         [TestMethod]
         public void ReportUnusedStrings()
@@ -135,7 +135,7 @@ namespace MediaBrowser.Tests.ConsistencyTests
 
             var allFiles = rootFolderInfo.GetFiles("*", SearchOption.AllDirectories);
 
-            var filteredFiles1 = allFiles.Where(f => TargetExtensions.Any(e => f.Name.EndsWith(e)));
+            var filteredFiles1 = allFiles.Where(f => TargetExtensions.Any(e => string.Equals(e, f.Extension, StringComparison.OrdinalIgnoreCase)));
             var filteredFiles2 = filteredFiles1.Where(f => !ExcludePaths.Any(p => f.FullName.Contains(p)));
 
             var selectedFiles = filteredFiles2.OrderBy(f => f.FullName).ToList();

+ 5 - 0
MediaBrowser.sln

@@ -13,6 +13,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
 		Performance3.psess = Performance3.psess
 		Performance4.psess = Performance4.psess
 		Performance5.psess = Performance5.psess
+		Performance6.psess = Performance6.psess
+		Performance7.psess = Performance7.psess
 	EndProjectSection
 EndProject
 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget (2)", ".nuget (2)", "{E60FB157-87E2-4A41-8B04-27EA49B63B4D}"
@@ -63,6 +65,9 @@ EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Emby.Drawing", "Emby.Drawing\Emby.Drawing.csproj", "{08FFF49B-F175-4807-A2B5-73B0EBD9F716}"
 EndProject
 Global
+	GlobalSection(Performance) = preSolution
+		HasPerformanceSessions = true
+	EndGlobalSection
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 		Debug|Any CPU = Debug|Any CPU
 		Debug|Mixed Platforms = Debug|Mixed Platforms

+ 1 - 1
SharedVersion.cs

@@ -1,4 +1,4 @@
 using System.Reflection;
 
 //[assembly: AssemblyVersion("3.1.*")]
-[assembly: AssemblyVersion("3.0.6030")]
+[assembly: AssemblyVersion("3.1.95")]