diff options
223 files changed, 830 insertions, 3633 deletions
diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index eca16ad38..5e3455fba 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -15,6 +15,7 @@ - [cvium](https://github.com/cvium) - [wtayl0r](https://github.com/wtayl0r) - [TtheCreator](https://github.com/Tthecreator) + - [dkanada](https://github.com/dkanada) - [LogicalPhallacy](https://github.com/LogicalPhallacy/) - [RazeLighter777](https://github.com/RazeLighter777) diff --git a/Dockerfile b/Dockerfile index c79d6f8ee..37388fda9 100644 --- a/Dockerfile +++ b/Dockerfile @@ -23,4 +23,4 @@ COPY --from=ffmpeg / / COPY --from=builder /jellyfin /jellyfin EXPOSE 8096 VOLUME /config /media -ENTRYPOINT dotnet /jellyfin/jellyfin.dll -programdata /config +ENTRYPOINT dotnet /jellyfin/jellyfin.dll --datadir /config diff --git a/Dockerfile.arm b/Dockerfile.arm index 657cb4ac6..039274197 100644 --- a/Dockerfile.arm +++ b/Dockerfile.arm @@ -21,4 +21,4 @@ RUN apt-get update \ COPY --from=builder /jellyfin /jellyfin EXPOSE 8096 VOLUME /config /media -ENTRYPOINT dotnet /jellyfin/jellyfin.dll -programdata /config +ENTRYPOINT dotnet /jellyfin/jellyfin.dll --datadir /config diff --git a/Dockerfile.arm64 b/Dockerfile.arm64 index 979dfc1dc..06ba21b91 100644 --- a/Dockerfile.arm64 +++ b/Dockerfile.arm64 @@ -30,4 +30,4 @@ COPY --from=qemu_extract qemu-* /usr/bin COPY --from=builder /jellyfin /jellyfin EXPOSE 8096 VOLUME /config /media -ENTRYPOINT dotnet /jellyfin/jellyfin.dll -programdata /config +ENTRYPOINT dotnet /jellyfin/jellyfin.dll --datadir /config diff --git a/Emby.Dlna/Api/DlnaServerService.cs b/Emby.Dlna/Api/DlnaServerService.cs index 01c9fe50f..68bf80163 100644 --- a/Emby.Dlna/Api/DlnaServerService.cs +++ b/Emby.Dlna/Api/DlnaServerService.cs @@ -236,7 +236,9 @@ namespace Emby.Dlna.Api public object Get(GetIcon request) { - var contentType = "image/" + Path.GetExtension(request.Filename).TrimStart('.').ToLower(); + var contentType = "image/" + Path.GetExtension(request.Filename) + .TrimStart('.') + .ToLowerInvariant(); var cacheLength = TimeSpan.FromDays(365); var cacheKey = Request.RawUrl.GetMD5(); diff --git a/Emby.Dlna/ContentDirectory/ControlHandler.cs b/Emby.Dlna/ContentDirectory/ControlHandler.cs index 2d8bb87f9..bed4d885c 100644 --- a/Emby.Dlna/ContentDirectory/ControlHandler.cs +++ b/Emby.Dlna/ContentDirectory/ControlHandler.cs @@ -454,7 +454,7 @@ namespace Emby.Dlna.ContentDirectory User = user, Recursive = true, IsMissing = false, - ExcludeItemTypes = new[] { typeof(Game).Name, typeof(Book).Name }, + ExcludeItemTypes = new[] { typeof(Book).Name }, IsFolder = isFolder, MediaTypes = mediaTypes.ToArray(), DtoOptions = GetDtoOptions() @@ -523,7 +523,7 @@ namespace Emby.Dlna.ContentDirectory Limit = limit, StartIndex = startIndex, IsVirtualItem = false, - ExcludeItemTypes = new[] { typeof(Game).Name, typeof(Book).Name }, + ExcludeItemTypes = new[] { typeof(Book).Name }, IsPlaceHolder = false, DtoOptions = GetDtoOptions() }; diff --git a/Emby.Dlna/Didl/DidlBuilder.cs b/Emby.Dlna/Didl/DidlBuilder.cs index e4a9cbfc6..f6d923a1f 100644 --- a/Emby.Dlna/Didl/DidlBuilder.cs +++ b/Emby.Dlna/Didl/DidlBuilder.cs @@ -265,7 +265,7 @@ namespace Emby.Dlna.Didl // <sec:CaptionInfo sec:type="srt">http://192.168.1.3:9999/video.srt</sec:CaptionInfo> writer.WriteStartElement("sec", "CaptionInfoEx", null); - writer.WriteAttributeString("sec", "type", null, info.Format.ToLower()); + writer.WriteAttributeString("sec", "type", null, info.Format.ToLowerInvariant()); writer.WriteString(info.Url); writer.WriteFullEndElement(); @@ -282,7 +282,7 @@ namespace Emby.Dlna.Didl else { writer.WriteStartElement(string.Empty, "res", NS_DIDL); - var protocolInfo = string.Format("http-get:*:text/{0}:*", info.Format.ToLower()); + var protocolInfo = string.Format("http-get:*:text/{0}:*", info.Format.ToLowerInvariant()); writer.WriteAttributeString("protocolInfo", protocolInfo); writer.WriteString(info.Url); @@ -808,7 +808,7 @@ namespace Emby.Dlna.Didl { writer.WriteString(_profile.RequiresPlainFolders ? "object.container.storageFolder" : "object.container.genre.musicGenre"); } - else if (item is Genre || item is GameGenre) + else if (item is Genre) { writer.WriteString(_profile.RequiresPlainFolders ? "object.container.storageFolder" : "object.container.genre"); } @@ -844,7 +844,7 @@ namespace Emby.Dlna.Didl // var type = types.FirstOrDefault(i => string.Equals(i, actor.Type, StringComparison.OrdinalIgnoreCase) || string.Equals(i, actor.Role, StringComparison.OrdinalIgnoreCase)) // ?? PersonType.Actor; - // AddValue(writer, "upnp", type.ToLower(), actor.Name, NS_UPNP); + // AddValue(writer, "upnp", type.ToLowerInvariant(), actor.Name, NS_UPNP); // index++; @@ -1147,7 +1147,7 @@ namespace Emby.Dlna.Didl if (stubType.HasValue) { - id = stubType.Value.ToString().ToLower() + "_" + id; + id = stubType.Value.ToString().ToLowerInvariant() + "_" + id; } return id; diff --git a/Emby.Dlna/DlnaManager.cs b/Emby.Dlna/DlnaManager.cs index fd7b408fd..a43888270 100644 --- a/Emby.Dlna/DlnaManager.cs +++ b/Emby.Dlna/DlnaManager.cs @@ -300,7 +300,7 @@ namespace Emby.Dlna profile = ReserializeProfile(tempProfile); - profile.Id = path.ToLower().GetMD5().ToString("N"); + profile.Id = path.ToLowerInvariant().GetMD5().ToString("N"); _profiles[path] = new Tuple<InternalProfileInfo, DeviceProfile>(GetInternalProfileInfo(_fileSystem.GetFileInfo(path), type), profile); @@ -352,7 +352,7 @@ namespace Emby.Dlna Info = new DeviceProfileInfo { - Id = file.FullName.ToLower().GetMD5().ToString("N"), + Id = file.FullName.ToLowerInvariant().GetMD5().ToString("N"), Name = _fileSystem.GetFileNameWithoutExtension(file), Type = type } @@ -506,7 +506,7 @@ namespace Emby.Dlna ? ImageFormat.Png : ImageFormat.Jpg; - var resource = GetType().Namespace + ".Images." + filename.ToLower(); + var resource = GetType().Namespace + ".Images." + filename.ToLowerInvariant(); return new ImageStream { diff --git a/Emby.Dlna/Main/DlnaEntryPoint.cs b/Emby.Dlna/Main/DlnaEntryPoint.cs index 1ab6014eb..ad90da49b 100644 --- a/Emby.Dlna/Main/DlnaEntryPoint.cs +++ b/Emby.Dlna/Main/DlnaEntryPoint.cs @@ -263,7 +263,7 @@ namespace Emby.Dlna.Main var fullService = "urn:schemas-upnp-org:device:MediaServer:1"; - _logger.LogInformation("Registering publisher for {0} on {1}", fullService, address.ToString()); + _logger.LogInformation("Registering publisher for {0} on {1}", fullService, address); var descriptorUri = "/dlna/" + udn + "/description.xml"; var uri = new Uri(_appHost.GetLocalApiUrl(address) + descriptorUri); diff --git a/Emby.Dlna/PlayTo/Device.cs b/Emby.Dlna/PlayTo/Device.cs index 68aa0a6a7..85a522d1c 100644 --- a/Emby.Dlna/PlayTo/Device.cs +++ b/Emby.Dlna/PlayTo/Device.cs @@ -902,54 +902,75 @@ namespace Emby.Dlna.PlayTo var name = document.Descendants(uPnpNamespaces.ud.GetName("friendlyName")).FirstOrDefault(); if (name != null && !string.IsNullOrWhiteSpace(name.Value)) + { friendlyNames.Add(name.Value); + } var room = document.Descendants(uPnpNamespaces.ud.GetName("roomName")).FirstOrDefault(); if (room != null && !string.IsNullOrWhiteSpace(room.Value)) + { friendlyNames.Add(room.Value); + } - deviceProperties.Name = string.Join(" ", friendlyNames.ToArray()); + deviceProperties.Name = string.Join(" ", friendlyNames); var model = document.Descendants(uPnpNamespaces.ud.GetName("modelName")).FirstOrDefault(); if (model != null) + { deviceProperties.ModelName = model.Value; + } var modelNumber = document.Descendants(uPnpNamespaces.ud.GetName("modelNumber")).FirstOrDefault(); if (modelNumber != null) + { deviceProperties.ModelNumber = modelNumber.Value; + } var uuid = document.Descendants(uPnpNamespaces.ud.GetName("UDN")).FirstOrDefault(); if (uuid != null) + { deviceProperties.UUID = uuid.Value; + } var manufacturer = document.Descendants(uPnpNamespaces.ud.GetName("manufacturer")).FirstOrDefault(); if (manufacturer != null) + { deviceProperties.Manufacturer = manufacturer.Value; + } var manufacturerUrl = document.Descendants(uPnpNamespaces.ud.GetName("manufacturerURL")).FirstOrDefault(); if (manufacturerUrl != null) + { deviceProperties.ManufacturerUrl = manufacturerUrl.Value; + } var presentationUrl = document.Descendants(uPnpNamespaces.ud.GetName("presentationURL")).FirstOrDefault(); if (presentationUrl != null) + { deviceProperties.PresentationUrl = presentationUrl.Value; + } var modelUrl = document.Descendants(uPnpNamespaces.ud.GetName("modelURL")).FirstOrDefault(); if (modelUrl != null) + { deviceProperties.ModelUrl = modelUrl.Value; + } var serialNumber = document.Descendants(uPnpNamespaces.ud.GetName("serialNumber")).FirstOrDefault(); if (serialNumber != null) + { deviceProperties.SerialNumber = serialNumber.Value; + } var modelDescription = document.Descendants(uPnpNamespaces.ud.GetName("modelDescription")).FirstOrDefault(); if (modelDescription != null) + { deviceProperties.ModelDescription = modelDescription.Value; + } deviceProperties.BaseUrl = string.Format("http://{0}:{1}", url.Host, url.Port); var icon = document.Descendants(uPnpNamespaces.ud.GetName("icon")).FirstOrDefault(); - if (icon != null) { deviceProperties.Icon = CreateIcon(icon); @@ -958,12 +979,16 @@ namespace Emby.Dlna.PlayTo foreach (var services in document.Descendants(uPnpNamespaces.ud.GetName("serviceList"))) { if (services == null) + { continue; + } var servicesList = services.Descendants(uPnpNamespaces.ud.GetName("service")); if (servicesList == null) + { continue; + } foreach (var element in servicesList) { @@ -1065,13 +1090,10 @@ namespace Emby.Dlna.PlayTo private void OnPlaybackStart(uBaseObject mediaInfo) { - if (PlaybackStart != null) + PlaybackStart?.Invoke(this, new PlaybackStartEventArgs { - PlaybackStart.Invoke(this, new PlaybackStartEventArgs - { - MediaInfo = mediaInfo - }); - } + MediaInfo = mediaInfo + }); } private void OnPlaybackProgress(uBaseObject mediaInfo) @@ -1082,36 +1104,28 @@ namespace Emby.Dlna.PlayTo return; } - if (PlaybackProgress != null) + PlaybackProgress?.Invoke(this, new PlaybackProgressEventArgs { - PlaybackProgress.Invoke(this, new PlaybackProgressEventArgs - { - MediaInfo = mediaInfo - }); - } + MediaInfo = mediaInfo + }); } private void OnPlaybackStop(uBaseObject mediaInfo) { - if (PlaybackStopped != null) + + PlaybackStopped?.Invoke(this, new PlaybackStoppedEventArgs { - PlaybackStopped.Invoke(this, new PlaybackStoppedEventArgs - { - MediaInfo = mediaInfo - }); - } + MediaInfo = mediaInfo + }); } private void OnMediaChanged(uBaseObject old, uBaseObject newMedia) { - if (MediaChanged != null) + MediaChanged?.Invoke(this, new MediaChangedEventArgs { - MediaChanged.Invoke(this, new MediaChangedEventArgs - { - OldMediaInfo = old, - NewMediaInfo = newMedia - }); - } + OldMediaInfo = old, + NewMediaInfo = newMedia + }); } #region IDisposable diff --git a/Emby.Dlna/Server/DescriptionXmlBuilder.cs b/Emby.Dlna/Server/DescriptionXmlBuilder.cs index e0ecbee43..03d8f80ab 100644 --- a/Emby.Dlna/Server/DescriptionXmlBuilder.cs +++ b/Emby.Dlna/Server/DescriptionXmlBuilder.cs @@ -107,19 +107,19 @@ namespace Emby.Dlna.Server '&' }; - private static readonly string[] s_escapeStringPairs = new string[] -{ - "<", - "<", - ">", - ">", - "\"", - """, - "'", - "'", - "&", - "&" -}; + private static readonly string[] s_escapeStringPairs = new[] + { + "<", + "<", + ">", + ">", + "\"", + """, + "'", + "'", + "&", + "&" + }; private static string GetEscapeSequence(char c) { @@ -133,7 +133,7 @@ namespace Emby.Dlna.Server return result; } } - return c.ToString(); + return c.ToString(CultureInfo.InvariantCulture); } /// <summary>Replaces invalid XML characters in a string with their valid XML equivalent.</summary> @@ -145,6 +145,7 @@ namespace Emby.Dlna.Server { return null; } + StringBuilder stringBuilder = null; int length = str.Length; int num = 0; @@ -230,9 +231,9 @@ namespace Emby.Dlna.Server var serverName = new string(characters); - var name = (_profile.FriendlyName ?? string.Empty).Replace("${HostName}", serverName, StringComparison.OrdinalIgnoreCase); + var name = _profile.FriendlyName?.Replace("${HostName}", serverName, StringComparison.OrdinalIgnoreCase); - return name; + return name ?? string.Empty; } private void AppendIconList(StringBuilder builder) @@ -295,65 +296,62 @@ namespace Emby.Dlna.Server } private IEnumerable<DeviceIcon> GetIcons() - { - var list = new List<DeviceIcon>(); - - list.Add(new DeviceIcon - { - MimeType = "image/png", - Depth = "24", - Width = 240, - Height = 240, - Url = "icons/logo240.png" - }); - - list.Add(new DeviceIcon - { - MimeType = "image/jpeg", - Depth = "24", - Width = 240, - Height = 240, - Url = "icons/logo240.jpg" - }); - - list.Add(new DeviceIcon - { - MimeType = "image/png", - Depth = "24", - Width = 120, - Height = 120, - Url = "icons/logo120.png" - }); - - list.Add(new DeviceIcon - { - MimeType = "image/jpeg", - Depth = "24", - Width = 120, - Height = 120, - Url = "icons/logo120.jpg" - }); - - list.Add(new DeviceIcon - { - MimeType = "image/png", - Depth = "24", - Width = 48, - Height = 48, - Url = "icons/logo48.png" - }); - - list.Add(new DeviceIcon + => new[] { - MimeType = "image/jpeg", - Depth = "24", - Width = 48, - Height = 48, - Url = "icons/logo48.jpg" - }); - - return list; - } + new DeviceIcon + { + MimeType = "image/png", + Depth = "24", + Width = 240, + Height = 240, + Url = "icons/logo240.png" + }, + + new DeviceIcon + { + MimeType = "image/jpeg", + Depth = "24", + Width = 240, + Height = 240, + Url = "icons/logo240.jpg" + }, + + new DeviceIcon + { + MimeType = "image/png", + Depth = "24", + Width = 120, + Height = 120, + Url = "icons/logo120.png" + }, + + new DeviceIcon + { + MimeType = "image/jpeg", + Depth = "24", + Width = 120, + Height = 120, + Url = "icons/logo120.jpg" + }, + + new DeviceIcon + { + MimeType = "image/png", + Depth = "24", + Width = 48, + Height = 48, + Url = "icons/logo48.png" + }, + + new DeviceIcon + { + MimeType = "image/jpeg", + Depth = "24", + Width = 48, + Height = 48, + Url = "icons/logo48.jpg" + } + }; private IEnumerable<DeviceService> GetServices() { diff --git a/Emby.Drawing/ImageProcessor.cs b/Emby.Drawing/ImageProcessor.cs index 4901561eb..f229d9a0b 100644 --- a/Emby.Drawing/ImageProcessor.cs +++ b/Emby.Drawing/ImageProcessor.cs @@ -144,7 +144,7 @@ namespace Emby.Drawing private static readonly string[] TransparentImageTypes = new string[] { ".png", ".webp", ".gif" }; public bool SupportsTransparency(string path) - => TransparentImageTypes.Contains(Path.GetExtension(path).ToLower()); + => TransparentImageTypes.Contains(Path.GetExtension(path).ToLowerInvariant()); public async Task<(string path, string mimeType, DateTime dateModified)> ProcessImage(ImageProcessingOptions options) { @@ -374,7 +374,7 @@ namespace Emby.Drawing filename += "v=" + Version; - return GetCachePath(ResizedImageCachePath, filename, "." + format.ToString().ToLower()); + return GetCachePath(ResizedImageCachePath, filename, "." + format.ToString().ToLowerInvariant()); } public ImageDimensions GetImageSize(BaseItem item, ItemImageInfo info) diff --git a/Emby.IsoMounting/IsoMounter/LinuxIsoManager.cs b/Emby.IsoMounting/IsoMounter/LinuxIsoManager.cs index c5564fd61..a6fc53953 100644 --- a/Emby.IsoMounting/IsoMounter/LinuxIsoManager.cs +++ b/Emby.IsoMounting/IsoMounter/LinuxIsoManager.cs @@ -121,7 +121,7 @@ namespace IsoMounter path, Path.GetExtension(path), EnvironmentInfo.OperatingSystem, - ExecutablesAvailable.ToString() + ExecutablesAvailable ); if (ExecutablesAvailable) @@ -183,7 +183,7 @@ namespace IsoMounter _logger.LogInformation( "[{0}] Disposing [{1}].", Name, - disposing.ToString() + disposing ); if (disposing) @@ -229,9 +229,8 @@ namespace IsoMounter var uid = getuid(); _logger.LogDebug( - "[{0}] Our current UID is [{1}], GetUserId() returned [{2}].", + "[{0}] GetUserId() returned [{2}].", Name, - uid.ToString(), uid ); diff --git a/Emby.Notifications/CoreNotificationTypes.cs b/Emby.Notifications/CoreNotificationTypes.cs index 158898084..8cc14fa01 100644 --- a/Emby.Notifications/CoreNotificationTypes.cs +++ b/Emby.Notifications/CoreNotificationTypes.cs @@ -75,11 +75,6 @@ namespace Emby.Notifications new NotificationTypeInfo { - Type = NotificationType.GamePlayback.ToString() - }, - - new NotificationTypeInfo - { Type = NotificationType.VideoPlayback.ToString() }, @@ -90,11 +85,6 @@ namespace Emby.Notifications new NotificationTypeInfo { - Type = NotificationType.GamePlaybackStopped.ToString() - }, - - new NotificationTypeInfo - { Type = NotificationType.VideoPlaybackStopped.ToString() }, diff --git a/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs b/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs index efe8f98ec..54b70d3b5 100644 --- a/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs +++ b/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs @@ -207,10 +207,6 @@ namespace Emby.Server.Implementations.Activity { return NotificationType.AudioPlayback.ToString(); } - if (string.Equals(mediaType, MediaType.Game, StringComparison.OrdinalIgnoreCase)) - { - return NotificationType.GamePlayback.ToString(); - } if (string.Equals(mediaType, MediaType.Video, StringComparison.OrdinalIgnoreCase)) { return NotificationType.VideoPlayback.ToString(); @@ -225,10 +221,6 @@ namespace Emby.Server.Implementations.Activity { return NotificationType.AudioPlaybackStopped.ToString(); } - if (string.Equals(mediaType, MediaType.Game, StringComparison.OrdinalIgnoreCase)) - { - return NotificationType.GamePlaybackStopped.ToString(); - } if (string.Equals(mediaType, MediaType.Video, StringComparison.OrdinalIgnoreCase)) { return NotificationType.VideoPlaybackStopped.ToString(); diff --git a/Emby.Server.Implementations/AppBase/BaseApplicationPaths.cs b/Emby.Server.Implementations/AppBase/BaseApplicationPaths.cs index e4a2cd9df..701c04f9e 100644 --- a/Emby.Server.Implementations/AppBase/BaseApplicationPaths.cs +++ b/Emby.Server.Implementations/AppBase/BaseApplicationPaths.cs @@ -16,12 +16,14 @@ namespace Emby.Server.Implementations.AppBase string programDataPath, string appFolderPath, string logDirectoryPath = null, - string configurationDirectoryPath = null) + string configurationDirectoryPath = null, + string cacheDirectoryPath = null) { ProgramDataPath = programDataPath; ProgramSystemPath = appFolderPath; LogDirectoryPath = logDirectoryPath; ConfigurationDirectoryPath = configurationDirectoryPath; + CachePath = cacheDirectoryPath; } public string ProgramDataPath { get; private set; } diff --git a/Emby.Server.Implementations/AppBase/BaseConfigurationManager.cs b/Emby.Server.Implementations/AppBase/BaseConfigurationManager.cs index 90b43bc59..460809e93 100644 --- a/Emby.Server.Implementations/AppBase/BaseConfigurationManager.cs +++ b/Emby.Server.Implementations/AppBase/BaseConfigurationManager.cs @@ -217,7 +217,7 @@ namespace Emby.Server.Implementations.AppBase private string GetConfigurationFile(string key) { - return Path.Combine(CommonApplicationPaths.ConfigurationDirectoryPath, key.ToLower() + ".xml"); + return Path.Combine(CommonApplicationPaths.ConfigurationDirectoryPath, key.ToLowerInvariant() + ".xml"); } public object GetConfiguration(string key) diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs index 1b86cfe3b..a43faaa2e 100644 --- a/Emby.Server.Implementations/ApplicationHost.cs +++ b/Emby.Server.Implementations/ApplicationHost.cs @@ -140,7 +140,7 @@ namespace Emby.Server.Implementations return false; } - if (StartupOptions.ContainsOption("-service")) + if (StartupOptions.IsService) { return false; } @@ -342,7 +342,7 @@ namespace Emby.Server.Implementations protected IHttpResultFactory HttpResultFactory { get; private set; } protected IAuthService AuthService { get; private set; } - public StartupOptions StartupOptions { get; private set; } + public IStartupOptions StartupOptions { get; private set; } internal IImageEncoder ImageEncoder { get; private set; } @@ -363,7 +363,7 @@ namespace Emby.Server.Implementations /// </summary> public ApplicationHost(ServerApplicationPaths applicationPaths, ILoggerFactory loggerFactory, - StartupOptions options, + IStartupOptions options, IFileSystem fileSystem, IEnvironmentInfo environmentInfo, IImageEncoder imageEncoder, @@ -903,7 +903,7 @@ namespace Emby.Server.Implementations PlaylistManager = new PlaylistManager(LibraryManager, FileSystemManager, LibraryMonitor, LoggerFactory, UserManager, ProviderManager); RegisterSingleInstance(PlaylistManager); - LiveTvManager = new LiveTvManager(this, ServerConfigurationManager, LoggerFactory, ItemRepository, ImageProcessor, UserDataManager, DtoService, UserManager, LibraryManager, TaskManager, LocalizationManager, JsonSerializer, ProviderManager, FileSystemManager, () => ChannelManager); + LiveTvManager = new LiveTvManager(this, ServerConfigurationManager, LoggerFactory, ItemRepository, ImageProcessor, UserDataManager, DtoService, UserManager, LibraryManager, TaskManager, LocalizationManager, JsonSerializer, FileSystemManager, () => ChannelManager); RegisterSingleInstance(LiveTvManager); UserViewManager = new UserViewManager(LibraryManager, LocalizationManager, UserManager, ChannelManager, LiveTvManager, ServerConfigurationManager); @@ -1670,7 +1670,6 @@ namespace Emby.Server.Implementations var minRequiredVersions = new Dictionary<string, Version>(StringComparer.OrdinalIgnoreCase) { - { "GameBrowser.dll", new Version(3, 1) }, { "moviethemesongs.dll", new Version(1, 6) }, { "themesongs.dll", new Version(1, 2) } }; @@ -1746,7 +1745,7 @@ namespace Emby.Server.Implementations EncoderLocationType = MediaEncoder.EncoderLocationType, SystemArchitecture = EnvironmentInfo.SystemArchitecture, SystemUpdateLevel = SystemUpdateLevel, - PackageName = StartupOptions.GetOption("-package") + PackageName = StartupOptions.PackageName }; } diff --git a/Emby.Server.Implementations/Collections/CollectionImageProvider.cs b/Emby.Server.Implementations/Collections/CollectionImageProvider.cs index 6642d1ef4..6aeadda2f 100644 --- a/Emby.Server.Implementations/Collections/CollectionImageProvider.cs +++ b/Emby.Server.Implementations/Collections/CollectionImageProvider.cs @@ -70,7 +70,8 @@ namespace Emby.Server.Implementations.Collections return null; }) .Where(i => i != null) - .DistinctBy(i => i.Id) + .GroupBy(x => x.Id) + .Select(x => x.First()) .OrderBy(i => Guid.NewGuid()) .ToList(); } diff --git a/Emby.Server.Implementations/Data/SqliteItemRepository.cs b/Emby.Server.Implementations/Data/SqliteItemRepository.cs index 3de4da444..3014e482d 100644 --- a/Emby.Server.Implementations/Data/SqliteItemRepository.cs +++ b/Emby.Server.Implementations/Data/SqliteItemRepository.cs @@ -1239,10 +1239,6 @@ namespace Emby.Server.Implementations.Data { return false; } - else if (type == typeof(GameGenre)) - { - return false; - } else if (type == typeof(Genre)) { return false; @@ -3905,7 +3901,7 @@ namespace Emby.Server.Implementations.Data // lowercase this because SortName is stored as lowercase if (statement != null) { - statement.TryBind("@NameStartsWithOrGreater", query.NameStartsWithOrGreater.ToLower()); + statement.TryBind("@NameStartsWithOrGreater", query.NameStartsWithOrGreater.ToLowerInvariant()); } } if (!string.IsNullOrWhiteSpace(query.NameLessThan)) @@ -3914,7 +3910,7 @@ namespace Emby.Server.Implementations.Data // lowercase this because SortName is stored as lowercase if (statement != null) { - statement.TryBind("@NameLessThan", query.NameLessThan.ToLower()); + statement.TryBind("@NameLessThan", query.NameLessThan.ToLowerInvariant()); } } @@ -4789,10 +4785,6 @@ namespace Emby.Server.Implementations.Data { list.Add(typeof(MusicGenre).Name); } - if (IsTypeInQuery(typeof(GameGenre).Name, query)) - { - list.Add(typeof(GameGenre).Name); - } if (IsTypeInQuery(typeof(MusicArtist).Name, query)) { list.Add(typeof(MusicArtist).Name); @@ -4822,7 +4814,7 @@ namespace Emby.Server.Implementations.Data return value; } - return value.RemoveDiacritics().ToLower(); + return value.RemoveDiacritics().ToLowerInvariant(); } private bool EnableGroupByPresentationUniqueKey(InternalItemsQuery query) @@ -4891,9 +4883,6 @@ namespace Emby.Server.Implementations.Data typeof(Book), typeof(CollectionFolder), typeof(Folder), - typeof(Game), - typeof(GameGenre), - typeof(GameSystem), typeof(Genre), typeof(Person), typeof(Photo), @@ -5251,11 +5240,6 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type return GetItemValues(query, new[] { 2 }, typeof(Genre).FullName); } - public QueryResult<Tuple<BaseItem, ItemCounts>> GetGameGenres(InternalItemsQuery query) - { - return GetItemValues(query, new[] { 2 }, typeof(GameGenre).FullName); - } - public QueryResult<Tuple<BaseItem, ItemCounts>> GetMusicGenres(InternalItemsQuery query) { return GetItemValues(query, new[] { 2 }, typeof(MusicGenre).FullName); @@ -5276,14 +5260,9 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type return GetItemValueNames(new[] { 2 }, new List<string> { "Audio", "MusicVideo", "MusicAlbum", "MusicArtist" }, new List<string>()); } - public List<string> GetGameGenreNames() - { - return GetItemValueNames(new[] { 2 }, new List<string> { "Game" }, new List<string>()); - } - public List<string> GetGenreNames() { - return GetItemValueNames(new[] { 2 }, new List<string>(), new List<string> { "Audio", "MusicVideo", "MusicAlbum", "MusicArtist", "Game", "GameSystem" }); + return GetItemValueNames(new[] { 2 }, new List<string>(), new List<string> { "Audio", "MusicVideo", "MusicAlbum", "MusicArtist" }); } private List<string> GetItemValueNames(int[] itemValueTypes, List<string> withItemTypes, List<string> excludeItemTypes) @@ -5652,10 +5631,6 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type { counts.SongCount = value; } - else if (string.Equals(typeName, typeof(Game).FullName, StringComparison.OrdinalIgnoreCase)) - { - counts.GameCount = value; - } else if (string.Equals(typeName, typeof(Trailer).FullName, StringComparison.OrdinalIgnoreCase)) { counts.TrailerCount = value; diff --git a/Emby.Server.Implementations/Diagnostics/CommonProcess.cs b/Emby.Server.Implementations/Diagnostics/CommonProcess.cs index 55539eafc..78b22bda3 100644 --- a/Emby.Server.Implementations/Diagnostics/CommonProcess.cs +++ b/Emby.Server.Implementations/Diagnostics/CommonProcess.cs @@ -105,7 +105,7 @@ namespace Emby.Server.Implementations.Diagnostics { return _process.WaitForExit(timeMs); } - + public Task<bool> WaitForExitAsync(int timeMs) { //Note: For this function to work correctly, the option EnableRisingEvents needs to be set to true. diff --git a/Emby.Server.Implementations/Dto/DtoService.cs b/Emby.Server.Implementations/Dto/DtoService.cs index d0a7de11d..f5634690f 100644 --- a/Emby.Server.Implementations/Dto/DtoService.cs +++ b/Emby.Server.Implementations/Dto/DtoService.cs @@ -374,10 +374,6 @@ namespace Emby.Server.Implementations.Dto dto.MusicVideoCount = taggedItems.Count(i => i is MusicVideo); dto.SongCount = taggedItems.Count(i => i is Audio); } - else if (item is GameGenre) - { - dto.GameCount = taggedItems.Count(i => i is Game); - } else { // This populates them all and covers Genre, Person, Studio, Year @@ -385,7 +381,6 @@ namespace Emby.Server.Implementations.Dto dto.ArtistCount = taggedItems.Count(i => i is MusicArtist); dto.AlbumCount = taggedItems.Count(i => i is MusicAlbum); dto.EpisodeCount = taggedItems.Count(i => i is Episode); - dto.GameCount = taggedItems.Count(i => i is Game); dto.MovieCount = taggedItems.Count(i => i is Movie); dto.TrailerCount = taggedItems.Count(i => i is Trailer); dto.MusicVideoCount = taggedItems.Count(i => i is MusicVideo); @@ -532,17 +527,6 @@ namespace Emby.Server.Implementations.Dto dto.Album = item.Album; } - private static void SetGameProperties(BaseItemDto dto, Game item) - { - dto.GameSystem = item.GameSystem; - dto.MultiPartGameFiles = item.MultiPartGameFiles; - } - - private static void SetGameSystemProperties(BaseItemDto dto, GameSystem item) - { - dto.GameSystem = item.GameSystemName; - } - private string[] GetImageTags(BaseItem item, List<ItemImageInfo> images) { return images @@ -636,7 +620,8 @@ namespace Emby.Server.Implementations.Dto } }).Where(i => i != null) - .DistinctBy(i => i.Name, StringComparer.OrdinalIgnoreCase) + .GroupBy(i => i.Name, StringComparer.OrdinalIgnoreCase) + .Select(x => x.First()) .ToDictionary(i => i.Name, StringComparer.OrdinalIgnoreCase); for (var i = 0; i < people.Count; i++) @@ -698,11 +683,6 @@ namespace Emby.Server.Implementations.Dto return _libraryManager.GetMusicGenreId(name); } - if (owner is Game || owner is GameSystem) - { - return _libraryManager.GetGameGenreId(name); - } - return _libraryManager.GetGenreId(name); } @@ -1206,20 +1186,6 @@ namespace Emby.Server.Implementations.Dto } } - var game = item as Game; - - if (game != null) - { - SetGameProperties(dto, game); - } - - var gameSystem = item as GameSystem; - - if (gameSystem != null) - { - SetGameSystemProperties(dto, gameSystem); - } - var musicVideo = item as MusicVideo; if (musicVideo != null) { diff --git a/Emby.Server.Implementations/Emby.Server.Implementations.csproj b/Emby.Server.Implementations/Emby.Server.Implementations.csproj index 3aa617b02..92e3172f1 100644 --- a/Emby.Server.Implementations/Emby.Server.Implementations.csproj +++ b/Emby.Server.Implementations/Emby.Server.Implementations.csproj @@ -1,4 +1,4 @@ -<Project Sdk="Microsoft.NET.Sdk"> +<Project Sdk="Microsoft.NET.Sdk"> <ItemGroup> <ProjectReference Include="..\Emby.Naming\Emby.Naming.csproj" /> diff --git a/Emby.Server.Implementations/EntryPoints/LibraryChangedNotifier.cs b/Emby.Server.Implementations/EntryPoints/LibraryChangedNotifier.cs index 7a8b09cf7..a670a289c 100644 --- a/Emby.Server.Implementations/EntryPoints/LibraryChangedNotifier.cs +++ b/Emby.Server.Implementations/EntryPoints/LibraryChangedNotifier.cs @@ -277,14 +277,21 @@ namespace Emby.Server.Implementations.EntryPoints lock (_libraryChangedSyncLock) { // Remove dupes in case some were saved multiple times - var foldersAddedTo = _foldersAddedTo.DistinctBy(i => i.Id).ToList(); + var foldersAddedTo = _foldersAddedTo + .GroupBy(x => x.Id) + .Select(x => x.First()) + .ToList(); - var foldersRemovedFrom = _foldersRemovedFrom.DistinctBy(i => i.Id).ToList(); + var foldersRemovedFrom = _foldersRemovedFrom + .GroupBy(x => x.Id) + .Select(x => x.First()) + .ToList(); var itemsUpdated = _itemsUpdated - .Where(i => !_itemsAdded.Contains(i)) - .DistinctBy(i => i.Id) - .ToList(); + .Where(i => !_itemsAdded.Contains(i)) + .GroupBy(x => x.Id) + .Select(x => x.First()) + .ToList(); SendChangeNotifications(_itemsAdded.ToList(), itemsUpdated, _itemsRemoved.ToList(), foldersAddedTo, foldersRemovedFrom, CancellationToken.None); diff --git a/Emby.Server.Implementations/EntryPoints/StartupWizard.cs b/Emby.Server.Implementations/EntryPoints/StartupWizard.cs index 05c8b07ab..bb96120f4 100644 --- a/Emby.Server.Implementations/EntryPoints/StartupWizard.cs +++ b/Emby.Server.Implementations/EntryPoints/StartupWizard.cs @@ -47,7 +47,7 @@ namespace Emby.Server.Implementations.EntryPoints { var options = ((ApplicationHost)_appHost).StartupOptions; - if (!options.ContainsOption("-noautorunwebapp")) + if (!options.NoAutoRunWebApp) { BrowserLauncher.OpenWebApp(_appHost); } diff --git a/Emby.Server.Implementations/EntryPoints/UserDataChangeNotifier.cs b/Emby.Server.Implementations/EntryPoints/UserDataChangeNotifier.cs index 9e71ffceb..69784e410 100644 --- a/Emby.Server.Implementations/EntryPoints/UserDataChangeNotifier.cs +++ b/Emby.Server.Implementations/EntryPoints/UserDataChangeNotifier.cs @@ -121,7 +121,8 @@ namespace Emby.Server.Implementations.EntryPoints var user = _userManager.GetUserById(userId); var dtoList = changedItems - .DistinctBy(i => i.Id) + .GroupBy(x => x.Id) + .Select(x => x.First()) .Select(i => { var dto = _userDataManager.GetUserDataDto(i, user); diff --git a/Emby.Server.Implementations/FFMpeg/FFMpegLoader.cs b/Emby.Server.Implementations/FFMpeg/FFMpegLoader.cs index 79a42f294..6167d1eaa 100644 --- a/Emby.Server.Implementations/FFMpeg/FFMpegLoader.cs +++ b/Emby.Server.Implementations/FFMpeg/FFMpegLoader.cs @@ -28,10 +28,10 @@ namespace Emby.Server.Implementations.FFMpeg _ffmpegInstallInfo = ffmpegInstallInfo; } - public FFMpegInfo GetFFMpegInfo(StartupOptions options) + public FFMpegInfo GetFFMpegInfo(IStartupOptions options) { - var customffMpegPath = options.GetOption("-ffmpeg"); - var customffProbePath = options.GetOption("-ffprobe"); + var customffMpegPath = options.FFmpegPath; + var customffProbePath = options.FFprobePath; if (!string.IsNullOrWhiteSpace(customffMpegPath) && !string.IsNullOrWhiteSpace(customffProbePath)) { diff --git a/Emby.Server.Implementations/HttpClientManager/HttpClientManager.cs b/Emby.Server.Implementations/HttpClientManager/HttpClientManager.cs index a61247fd1..6ea1bd08e 100644 --- a/Emby.Server.Implementations/HttpClientManager/HttpClientManager.cs +++ b/Emby.Server.Implementations/HttpClientManager/HttpClientManager.cs @@ -264,7 +264,7 @@ namespace Emby.Server.Implementations.HttpClientManager } var url = options.Url; - var urlHash = url.ToLower().GetMD5().ToString("N"); + var urlHash = url.ToLowerInvariant().GetMD5().ToString("N"); var responseCachePath = Path.Combine(_appPaths.CachePath, "httpclient", urlHash); @@ -374,11 +374,11 @@ namespace Emby.Server.Implementations.HttpClientManager { if (options.LogRequestAsDebug) { - _logger.LogDebug("HttpClientManager {0}: {1}", httpMethod.ToUpper(), options.Url); + _logger.LogDebug("HttpClientManager {0}: {1}", httpMethod.ToUpper(CultureInfo.CurrentCulture), options.Url); } else { - _logger.LogInformation("HttpClientManager {0}: {1}", httpMethod.ToUpper(), options.Url); + _logger.LogInformation("HttpClientManager {0}: {1}", httpMethod.ToUpper(CultureInfo.CurrentCulture), options.Url); } } diff --git a/Emby.Server.Implementations/HttpServer/HttpResultFactory.cs b/Emby.Server.Implementations/HttpServer/HttpResultFactory.cs index 0ad4d8406..7445fd3c2 100644 --- a/Emby.Server.Implementations/HttpServer/HttpResultFactory.cs +++ b/Emby.Server.Implementations/HttpServer/HttpResultFactory.cs @@ -394,7 +394,7 @@ namespace Emby.Server.Implementations.HttpServer { return contentType == null ? null - : contentType.Split(';')[0].ToLower().Trim(); + : contentType.Split(';')[0].ToLowerInvariant().Trim(); } private static string SerializeToXmlString(object from) diff --git a/Emby.Server.Implementations/IO/FileRefresher.cs b/Emby.Server.Implementations/IO/FileRefresher.cs index 12532a497..1cac0ba5c 100644 --- a/Emby.Server.Implementations/IO/FileRefresher.cs +++ b/Emby.Server.Implementations/IO/FileRefresher.cs @@ -146,8 +146,8 @@ namespace Emby.Server.Implementations.IO .Distinct(StringComparer.OrdinalIgnoreCase) .Select(GetAffectedBaseItem) .Where(item => item != null) - .DistinctBy(i => i.Id) - .ToList(); + .GroupBy(x => x.Id) + .Select(x => x.First()); foreach (var item in itemsToRefresh) { diff --git a/Emby.Server.Implementations/IO/LibraryMonitor.cs b/Emby.Server.Implementations/IO/LibraryMonitor.cs index dad81c195..ed5fddb52 100644 --- a/Emby.Server.Implementations/IO/LibraryMonitor.cs +++ b/Emby.Server.Implementations/IO/LibraryMonitor.cs @@ -601,20 +601,26 @@ namespace Emby.Server.Implementations.IO /// </summary> public void Dispose() { - _disposed = true; Dispose(true); } /// <summary> /// Releases unmanaged and - optionally - managed resources. /// </summary> - /// <param name="dispose"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param> - protected virtual void Dispose(bool dispose) + /// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param> + protected virtual void Dispose(bool disposing) { - if (dispose) + if (_disposed) + { + return; + } + + if (disposing) { Stop(); } + + _disposed = true; } } diff --git a/Emby.Server.Implementations/IStartupOptions.cs b/Emby.Server.Implementations/IStartupOptions.cs new file mode 100644 index 000000000..24aaa76c0 --- /dev/null +++ b/Emby.Server.Implementations/IStartupOptions.cs @@ -0,0 +1,40 @@ +namespace Emby.Server.Implementations +{ + public interface IStartupOptions + { + /// <summary> + /// --ffmpeg + /// </summary> + string FFmpegPath { get; } + + /// <summary> + /// --ffprobe + /// </summary> + string FFprobePath { get; } + + /// <summary> + /// --service + /// </summary> + bool IsService { get; } + + /// <summary> + /// --noautorunwebapp + /// </summary> + bool NoAutoRunWebApp { get; } + + /// <summary> + /// --package-name + /// </summary> + string PackageName { get; } + + /// <summary> + /// --restartpath + /// </summary> + string RestartPath { get; } + + /// <summary> + /// --restartargs + /// </summary> + string RestartArgs { get; } + } +} diff --git a/Emby.Server.Implementations/Images/BaseDynamicImageProvider.cs b/Emby.Server.Implementations/Images/BaseDynamicImageProvider.cs index 9705d54c9..109c21f18 100644 --- a/Emby.Server.Implementations/Images/BaseDynamicImageProvider.cs +++ b/Emby.Server.Implementations/Images/BaseDynamicImageProvider.cs @@ -215,7 +215,7 @@ namespace Emby.Server.Implementations.Images { return CreateSquareCollage(item, itemsWithImages, outputPath); } - if (item is Playlist || item is MusicGenre || item is Genre || item is GameGenre || item is PhotoAlbum) + if (item is Playlist || item is MusicGenre || item is Genre || item is PhotoAlbum) { return CreateSquareCollage(item, itemsWithImages, outputPath); } diff --git a/Emby.Server.Implementations/Library/LibraryManager.cs b/Emby.Server.Implementations/Library/LibraryManager.cs index f96a211ec..064006ebd 100644 --- a/Emby.Server.Implementations/Library/LibraryManager.cs +++ b/Emby.Server.Implementations/Library/LibraryManager.cs @@ -512,7 +512,7 @@ namespace Emby.Server.Implementations.Library if (forceCaseInsensitive || !ConfigurationManager.Configuration.EnableCaseSensitiveItemIds) { - key = key.ToLower(); + key = key.ToLowerInvariant(); } key = type.FullName + key; @@ -869,11 +869,6 @@ namespace Emby.Server.Implementations.Library return GetItemByNameId<MusicGenre>(MusicGenre.GetPath, name); } - public Guid GetGameGenreId(string name) - { - return GetItemByNameId<GameGenre>(GameGenre.GetPath, name); - } - /// <summary> /// Gets a Genre /// </summary> @@ -895,16 +890,6 @@ namespace Emby.Server.Implementations.Library } /// <summary> - /// Gets the game genre. - /// </summary> - /// <param name="name">The name.</param> - /// <returns>Task{GameGenre}.</returns> - public GameGenre GetGameGenre(string name) - { - return CreateItemByName<GameGenre>(GameGenre.GetPath, name, new DtoOptions(true)); - } - - /// <summary> /// Gets a Year /// </summary> /// <param name="value">The value.</param> @@ -1370,17 +1355,6 @@ namespace Emby.Server.Implementations.Library return ItemRepository.GetGenres(query); } - public QueryResult<Tuple<BaseItem, ItemCounts>> GetGameGenres(InternalItemsQuery query) - { - if (query.User != null) - { - AddUserToQuery(query, query.User); - } - - SetTopParentOrAncestorIds(query); - return ItemRepository.GetGameGenres(query); - } - public QueryResult<Tuple<BaseItem, ItemCounts>> GetMusicGenres(InternalItemsQuery query) { if (query.User != null) diff --git a/Emby.Server.Implementations/Library/SearchEngine.cs b/Emby.Server.Implementations/Library/SearchEngine.cs index 71638b197..9c7f7dfcb 100644 --- a/Emby.Server.Implementations/Library/SearchEngine.cs +++ b/Emby.Server.Implementations/Library/SearchEngine.cs @@ -99,14 +99,12 @@ namespace Emby.Server.Implementations.Library if (!query.IncludeMedia) { AddIfMissing(includeItemTypes, typeof(Genre).Name); - AddIfMissing(includeItemTypes, typeof(GameGenre).Name); AddIfMissing(includeItemTypes, typeof(MusicGenre).Name); } } else { AddIfMissing(excludeItemTypes, typeof(Genre).Name); - AddIfMissing(excludeItemTypes, typeof(GameGenre).Name); AddIfMissing(excludeItemTypes, typeof(MusicGenre).Name); } diff --git a/Emby.Server.Implementations/Library/UserManager.cs b/Emby.Server.Implementations/Library/UserManager.cs index 05fce4542..b33ae72b7 100644 --- a/Emby.Server.Implementations/Library/UserManager.cs +++ b/Emby.Server.Implementations/Library/UserManager.cs @@ -23,7 +23,6 @@ using MediaBrowser.Controller.Providers; using MediaBrowser.Controller.Security; using MediaBrowser.Controller.Session; using MediaBrowser.Model.Configuration; -using MediaBrowser.Model.Connect; using MediaBrowser.Model.Cryptography; using MediaBrowser.Model.Dto; using MediaBrowser.Model.Entities; @@ -211,11 +210,8 @@ namespace Emby.Server.Implementations.Library { foreach (var user in users) { - if (!user.ConnectLinkType.HasValue || user.ConnectLinkType.Value == UserLinkType.LinkedUser) - { - user.Policy.IsAdministrator = true; - UpdateUserPolicy(user, user.Policy, false); - } + user.Policy.IsAdministrator = true; + UpdateUserPolicy(user, user.Policy, false); } } } @@ -273,13 +269,9 @@ namespace Emby.Server.Implementations.Library if (user != null) { - // Authenticate using local credentials if not a guest - if (!user.ConnectLinkType.HasValue || user.ConnectLinkType.Value != UserLinkType.Guest) - { - var authResult = await AuthenticateLocalUser(username, password, hashedPassword, user, remoteEndPoint).ConfigureAwait(false); - authenticationProvider = authResult.Item1; - success = authResult.Item2; - } + var authResult = await AuthenticateLocalUser(username, password, hashedPassword, user, remoteEndPoint).ConfigureAwait(false); + authenticationProvider = authResult.Item1; + success = authResult.Item2; } else { @@ -554,9 +546,6 @@ namespace Emby.Server.Implementations.Library LastActivityDate = user.LastActivityDate, LastLoginDate = user.LastLoginDate, Configuration = user.Configuration, - ConnectLinkType = user.ConnectLinkType, - ConnectUserId = user.ConnectUserId, - ConnectUserName = user.ConnectUserName, ServerId = _appHost.SystemId, Policy = user.Policy }; @@ -815,11 +804,6 @@ namespace Emby.Server.Implementations.Library throw new ArgumentNullException(nameof(user)); } - if (user.ConnectLinkType.HasValue && user.ConnectLinkType.Value == UserLinkType.Guest) - { - throw new ArgumentException("Passwords for guests cannot be changed."); - } - await GetAuthenticationProvider(user).ChangePassword(user, newPassword).ConfigureAwait(false); UpdateUser(user); @@ -926,11 +910,6 @@ namespace Emby.Server.Implementations.Library null : GetUserByName(enteredUsername); - if (user != null && user.ConnectLinkType.HasValue && user.ConnectLinkType.Value == UserLinkType.Guest) - { - throw new ArgumentException("Unable to process forgot password request for guests."); - } - var action = ForgotPasswordAction.InNetworkRequired; string pinFile = null; DateTime? expirationDate = null; @@ -975,10 +954,7 @@ namespace Emby.Server.Implementations.Library _lastPin = null; _lastPasswordPinCreationResult = null; - var users = Users.Where(i => !i.ConnectLinkType.HasValue || i.ConnectLinkType.Value != UserLinkType.Guest) - .ToList(); - - foreach (var user in users) + foreach (var user in Users) { await ResetPassword(user).ConfigureAwait(false); diff --git a/Emby.Server.Implementations/Library/UserViewManager.cs b/Emby.Server.Implementations/Library/UserViewManager.cs index 9fa859bde..e9ce682ee 100644 --- a/Emby.Server.Implementations/Library/UserViewManager.cs +++ b/Emby.Server.Implementations/Library/UserViewManager.cs @@ -308,9 +308,6 @@ namespace Emby.Server.Implementations.Library mediaTypes.Add(MediaType.Book); mediaTypes.Add(MediaType.Audio); break; - case CollectionType.Games: - mediaTypes.Add(MediaType.Game); - break; case CollectionType.Music: mediaTypes.Add(MediaType.Audio); break; @@ -336,7 +333,6 @@ namespace Emby.Server.Implementations.Library typeof(Person).Name, typeof(Studio).Name, typeof(Year).Name, - typeof(GameGenre).Name, typeof(MusicGenre).Name, typeof(Genre).Name diff --git a/Emby.Server.Implementations/Library/Validators/GameGenresPostScanTask.cs b/Emby.Server.Implementations/Library/Validators/GameGenresPostScanTask.cs deleted file mode 100644 index 2b067951d..000000000 --- a/Emby.Server.Implementations/Library/Validators/GameGenresPostScanTask.cs +++ /dev/null @@ -1,45 +0,0 @@ -using System; -using System.Threading; -using System.Threading.Tasks; -using MediaBrowser.Controller.Library; -using MediaBrowser.Controller.Persistence; -using Microsoft.Extensions.Logging; - -namespace Emby.Server.Implementations.Library.Validators -{ - /// <summary> - /// Class GameGenresPostScanTask - /// </summary> - public class GameGenresPostScanTask : ILibraryPostScanTask - { - /// <summary> - /// The _library manager - /// </summary> - private readonly ILibraryManager _libraryManager; - private readonly ILogger _logger; - private readonly IItemRepository _itemRepo; - - /// <summary> - /// Initializes a new instance of the <see cref="GameGenresPostScanTask" /> class. - /// </summary> - /// <param name="libraryManager">The library manager.</param> - /// <param name="logger">The logger.</param> - public GameGenresPostScanTask(ILibraryManager libraryManager, ILogger logger, IItemRepository itemRepo) - { - _libraryManager = libraryManager; - _logger = logger; - _itemRepo = itemRepo; - } - - /// <summary> - /// Runs the specified progress. - /// </summary> - /// <param name="progress">The progress.</param> - /// <param name="cancellationToken">The cancellation token.</param> - /// <returns>Task.</returns> - public Task Run(IProgress<double> progress, CancellationToken cancellationToken) - { - return new GameGenresValidator(_libraryManager, _logger, _itemRepo).Run(progress, cancellationToken); - } - } -} diff --git a/Emby.Server.Implementations/Library/Validators/GameGenresValidator.cs b/Emby.Server.Implementations/Library/Validators/GameGenresValidator.cs deleted file mode 100644 index f5ffa1e45..000000000 --- a/Emby.Server.Implementations/Library/Validators/GameGenresValidator.cs +++ /dev/null @@ -1,72 +0,0 @@ -using System; -using System.Threading; -using System.Threading.Tasks; -using MediaBrowser.Controller.Library; -using MediaBrowser.Controller.Persistence; -using Microsoft.Extensions.Logging; - -namespace Emby.Server.Implementations.Library.Validators -{ - class GameGenresValidator - { - /// <summary> - /// The _library manager - /// </summary> - private readonly ILibraryManager _libraryManager; - - /// <summary> - /// The _logger - /// </summary> - private readonly ILogger _logger; - private readonly IItemRepository _itemRepo; - - public GameGenresValidator(ILibraryManager libraryManager, ILogger logger, IItemRepository itemRepo) - { - _libraryManager = libraryManager; - _logger = logger; - _itemRepo = itemRepo; - } - - /// <summary> - /// Runs the specified progress. - /// </summary> - /// <param name="progress">The progress.</param> - /// <param name="cancellationToken">The cancellation token.</param> - /// <returns>Task.</returns> - public async Task Run(IProgress<double> progress, CancellationToken cancellationToken) - { - var names = _itemRepo.GetGameGenreNames(); - - var numComplete = 0; - var count = names.Count; - - foreach (var name in names) - { - try - { - var item = _libraryManager.GetGameGenre(name); - - await item.RefreshMetadata(cancellationToken).ConfigureAwait(false); - } - catch (OperationCanceledException) - { - // Don't clutter the log - throw; - } - catch (Exception ex) - { - _logger.LogError(ex, "Error refreshing {GenreName}", name); - } - - numComplete++; - double percent = numComplete; - percent /= count; - percent *= 100; - - progress.Report(percent); - } - - progress.Report(100); - } - } -} diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs index 6a2a46c9f..bce9c240d 100644 --- a/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs +++ b/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs @@ -35,7 +35,6 @@ using MediaBrowser.Model.Providers; using MediaBrowser.Model.Querying; using MediaBrowser.Model.Reflection; using MediaBrowser.Model.Serialization; -using MediaBrowser.Model.System; using MediaBrowser.Model.Threading; using Microsoft.Extensions.Logging; @@ -275,7 +274,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV foreach (var timer in seriesTimers) { - await UpdateTimersForSeriesTimer(timer, false, true).ConfigureAwait(false); + UpdateTimersForSeriesTimer(timer, false, true); } } @@ -763,12 +762,12 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV _timerProvider.AddOrUpdate(timer, false); } - await UpdateTimersForSeriesTimer(info, true, false).ConfigureAwait(false); + UpdateTimersForSeriesTimer(info, true, false); return info.Id; } - public async Task UpdateSeriesTimerAsync(SeriesTimerInfo info, CancellationToken cancellationToken) + public Task UpdateSeriesTimerAsync(SeriesTimerInfo info, CancellationToken cancellationToken) { var instance = _seriesTimerProvider.GetAll().FirstOrDefault(i => string.Equals(i.Id, info.Id, StringComparison.OrdinalIgnoreCase)); @@ -792,8 +791,10 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV _seriesTimerProvider.Update(instance); - await UpdateTimersForSeriesTimer(instance, true, true).ConfigureAwait(false); + UpdateTimersForSeriesTimer(instance, true, true); } + + return Task.CompletedTask; } public Task UpdateTimerAsync(TimerInfo updatedTimer, CancellationToken cancellationToken) @@ -2193,7 +2194,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV if (lockData) { - writer.WriteElementString("lockdata", true.ToString().ToLower()); + writer.WriteElementString("lockdata", true.ToString(CultureInfo.InvariantCulture).ToLowerInvariant()); } if (item.CriticRating.HasValue) @@ -2346,10 +2347,9 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV } } - private async Task UpdateTimersForSeriesTimer(SeriesTimerInfo seriesTimer, bool updateTimerSettings, bool deleteInvalidTimers) + private void UpdateTimersForSeriesTimer(SeriesTimerInfo seriesTimer, bool updateTimerSettings, bool deleteInvalidTimers) { - var allTimers = GetTimersForSeries(seriesTimer) - .ToList(); + var allTimers = GetTimersForSeries(seriesTimer).ToList(); var enabledTimersForSeries = new List<TimerInfo>(); diff --git a/Emby.Server.Implementations/LiveTv/LiveTvDtoService.cs b/Emby.Server.Implementations/LiveTv/LiveTvDtoService.cs index 724e8afdf..1144c9ab1 100644 --- a/Emby.Server.Implementations/LiveTv/LiveTvDtoService.cs +++ b/Emby.Server.Implementations/LiveTv/LiveTvDtoService.cs @@ -399,7 +399,7 @@ namespace Emby.Server.Implementations.LiveTv { var name = serviceName + externalId + InternalVersionNumber; - return _libraryManager.GetNewItemId(name.ToLower(), typeof(LiveTvChannel)); + return _libraryManager.GetNewItemId(name.ToLowerInvariant(), typeof(LiveTvChannel)); } private const string ServiceName = "Emby"; @@ -407,21 +407,21 @@ namespace Emby.Server.Implementations.LiveTv { var name = ServiceName + externalId + InternalVersionNumber; - return name.ToLower().GetMD5().ToString("N"); + return name.ToLowerInvariant().GetMD5().ToString("N"); } public Guid GetInternalSeriesTimerId(string externalId) { var name = ServiceName + externalId + InternalVersionNumber; - return name.ToLower().GetMD5(); + return name.ToLowerInvariant().GetMD5(); } public Guid GetInternalProgramId(string externalId) { var name = ServiceName + externalId + InternalVersionNumber; - return _libraryManager.GetNewItemId(name.ToLower(), typeof(LiveTvProgram)); + return _libraryManager.GetNewItemId(name.ToLowerInvariant(), typeof(LiveTvProgram)); } public async Task<TimerInfo> GetTimerInfo(TimerInfoDto dto, bool isNew, LiveTvManager liveTv, CancellationToken cancellationToken) diff --git a/Emby.Server.Implementations/LiveTv/LiveTvManager.cs b/Emby.Server.Implementations/LiveTv/LiveTvManager.cs index 575cb1c77..c3437bcda 100644 --- a/Emby.Server.Implementations/LiveTv/LiveTvManager.cs +++ b/Emby.Server.Implementations/LiveTv/LiveTvManager.cs @@ -6,7 +6,6 @@ using System.Threading.Tasks; using Emby.Server.Implementations.Library; using MediaBrowser.Common.Configuration; using MediaBrowser.Common.Extensions; -using MediaBrowser.Common.Net; using MediaBrowser.Common.Progress; using MediaBrowser.Controller; using MediaBrowser.Controller.Channels; @@ -24,7 +23,6 @@ using MediaBrowser.Controller.Sorting; using MediaBrowser.Model.Dto; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Events; -using MediaBrowser.Model.Extensions; using MediaBrowser.Model.Globalization; using MediaBrowser.Model.IO; using MediaBrowser.Model.LiveTv; @@ -48,7 +46,6 @@ namespace Emby.Server.Implementations.LiveTv private readonly ILibraryManager _libraryManager; private readonly ITaskManager _taskManager; private readonly IJsonSerializer _jsonSerializer; - private readonly IProviderManager _providerManager; private readonly Func<IChannelManager> _channelManager; private readonly IDtoService _dtoService; @@ -85,7 +82,6 @@ namespace Emby.Server.Implementations.LiveTv ITaskManager taskManager, ILocalizationManager localization, IJsonSerializer jsonSerializer, - IProviderManager providerManager, IFileSystem fileSystem, Func<IChannelManager> channelManager) { @@ -97,7 +93,6 @@ namespace Emby.Server.Implementations.LiveTv _taskManager = taskManager; _localization = localization; _jsonSerializer = jsonSerializer; - _providerManager = providerManager; _fileSystem = fileSystem; _dtoService = dtoService; _userDataManager = userDataManager; @@ -2469,7 +2464,8 @@ namespace Emby.Server.Implementations.LiveTv .Where(i => i != null) .Where(i => i.IsVisibleStandalone(user)) .SelectMany(i => _libraryManager.GetCollectionFolders(i)) - .DistinctBy(i => i.Id) + .GroupBy(x => x.Id) + .Select(x => x.First()) .OrderBy(i => i.SortName) .ToList(); diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/SharedHttpStream.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/SharedHttpStream.cs index 716417ccb..4eff9252e 100644 --- a/Emby.Server.Implementations/LiveTv/TunerHosts/SharedHttpStream.cs +++ b/Emby.Server.Implementations/LiveTv/TunerHosts/SharedHttpStream.cs @@ -94,7 +94,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts var now = DateTime.UtcNow; - StartStreaming(response, taskCompletionSource, LiveStreamCancellationTokenSource.Token); + var _ = StartStreaming(response, taskCompletionSource, LiveStreamCancellationTokenSource.Token); //OpenedMediaSource.Protocol = MediaProtocol.File; //OpenedMediaSource.Path = tempFile; diff --git a/Emby.Server.Implementations/Localization/Core/ar.json b/Emby.Server.Implementations/Localization/Core/ar.json index ec2c3f237..eb145b4fe 100644 --- a/Emby.Server.Implementations/Localization/Core/ar.json +++ b/Emby.Server.Implementations/Localization/Core/ar.json @@ -14,7 +14,6 @@ "FailedLoginAttemptWithUserName": "عملية تسجيل الدخول فشلت من {0}", "Favorites": "المفضلات", "Folders": "المجلدات", - "Games": "الألعاب", "Genres": "أنواع الأفلام", "HeaderAlbumArtists": "فنانو الألبومات", "HeaderCameraUploads": "Camera Uploads", @@ -51,8 +50,6 @@ "NotificationOptionAudioPlayback": "بدأ تشغيل المقطع الصوتي", "NotificationOptionAudioPlaybackStopped": "تم إيقاف تشغيل المقطع الصوتي", "NotificationOptionCameraImageUploaded": "تم رقع صورة الكاميرا", - "NotificationOptionGamePlayback": "تم تشغيل اللعبة", - "NotificationOptionGamePlaybackStopped": "تم إيقاف تشغيل اللعبة", "NotificationOptionInstallationFailed": "عملية التنصيب فشلت", "NotificationOptionNewLibraryContent": "تم إضافة محتوى جديد", "NotificationOptionPluginError": "فشل في الملحق", diff --git a/Emby.Server.Implementations/Localization/Core/bg-BG.json b/Emby.Server.Implementations/Localization/Core/bg-BG.json index ba6c98555..a71dc9346 100644 --- a/Emby.Server.Implementations/Localization/Core/bg-BG.json +++ b/Emby.Server.Implementations/Localization/Core/bg-BG.json @@ -14,7 +14,6 @@ "FailedLoginAttemptWithUserName": "Failed login attempt from {0}", "Favorites": "Любими", "Folders": "Папки", - "Games": "Игри", "Genres": "Жанрове", "HeaderAlbumArtists": "Изпълнители на албуми", "HeaderCameraUploads": "Camera Uploads", @@ -51,8 +50,6 @@ "NotificationOptionAudioPlayback": "Възпроизвеждането на звук започна", "NotificationOptionAudioPlaybackStopped": "Възпроизвеждането на звук е спряно", "NotificationOptionCameraImageUploaded": "Изображението от фотоапарата е качено", - "NotificationOptionGamePlayback": "Възпроизвеждането на играта започна", - "NotificationOptionGamePlaybackStopped": "Възпроизвеждането на играта е спряна", "NotificationOptionInstallationFailed": "Неуспешно инсталиране", "NotificationOptionNewLibraryContent": "Добавено е ново съдържание", "NotificationOptionPluginError": "Грешка в приставка", diff --git a/Emby.Server.Implementations/Localization/Core/ca.json b/Emby.Server.Implementations/Localization/Core/ca.json index a818b78de..74406a064 100644 --- a/Emby.Server.Implementations/Localization/Core/ca.json +++ b/Emby.Server.Implementations/Localization/Core/ca.json @@ -14,7 +14,6 @@ "FailedLoginAttemptWithUserName": "Intent de connexió fallit des de {0}", "Favorites": "Preferits", "Folders": "Directoris", - "Games": "Jocs", "Genres": "Gèneres", "HeaderAlbumArtists": "Album Artists", "HeaderCameraUploads": "Camera Uploads", @@ -51,8 +50,6 @@ "NotificationOptionAudioPlayback": "Audio playback started", "NotificationOptionAudioPlaybackStopped": "Audio playback stopped", "NotificationOptionCameraImageUploaded": "Camera image uploaded", - "NotificationOptionGamePlayback": "Game playback started", - "NotificationOptionGamePlaybackStopped": "Game playback stopped", "NotificationOptionInstallationFailed": "Installation failure", "NotificationOptionNewLibraryContent": "New content added", "NotificationOptionPluginError": "Un component ha fallat", diff --git a/Emby.Server.Implementations/Localization/Core/cs.json b/Emby.Server.Implementations/Localization/Core/cs.json index e066051a8..a8b4a4424 100644 --- a/Emby.Server.Implementations/Localization/Core/cs.json +++ b/Emby.Server.Implementations/Localization/Core/cs.json @@ -14,7 +14,6 @@ "FailedLoginAttemptWithUserName": "Neúspěšný pokus o přihlášení z {0}", "Favorites": "Oblíbené", "Folders": "Složky", - "Games": "Hry", "Genres": "Žánry", "HeaderAlbumArtists": "Umělci alba", "HeaderCameraUploads": "Camera Uploads", @@ -51,8 +50,6 @@ "NotificationOptionAudioPlayback": "Přehrávání audia zahájeno", "NotificationOptionAudioPlaybackStopped": "Přehrávání audia ukončeno", "NotificationOptionCameraImageUploaded": "Kamerový záznam nahrán", - "NotificationOptionGamePlayback": "Spuštění hry zahájeno", - "NotificationOptionGamePlaybackStopped": "Hra ukončena", "NotificationOptionInstallationFailed": "Chyba instalace", "NotificationOptionNewLibraryContent": "Přidán nový obsah", "NotificationOptionPluginError": "Chyba zásuvného modulu", diff --git a/Emby.Server.Implementations/Localization/Core/da.json b/Emby.Server.Implementations/Localization/Core/da.json index 30581c389..7004d44db 100644 --- a/Emby.Server.Implementations/Localization/Core/da.json +++ b/Emby.Server.Implementations/Localization/Core/da.json @@ -14,7 +14,6 @@ "FailedLoginAttemptWithUserName": "Fejlet loginforsøg fra {0}", "Favorites": "Favoritter", "Folders": "Mapper", - "Games": "Spil", "Genres": "Genre", "HeaderAlbumArtists": "Albumkunstnere", "HeaderCameraUploads": "Camera Uploads", @@ -51,8 +50,6 @@ "NotificationOptionAudioPlayback": "Audioafspilning påbegyndt", "NotificationOptionAudioPlaybackStopped": "Audioafspilning stoppet", "NotificationOptionCameraImageUploaded": "Kamerabillede uploadet", - "NotificationOptionGamePlayback": "Afspilning af Spil påbegyndt", - "NotificationOptionGamePlaybackStopped": "Afspilning af Spil stoppet", "NotificationOptionInstallationFailed": "Installationsfejl", "NotificationOptionNewLibraryContent": "Nyt indhold tilføjet", "NotificationOptionPluginError": "Pluginfejl", diff --git a/Emby.Server.Implementations/Localization/Core/de.json b/Emby.Server.Implementations/Localization/Core/de.json index 98cb07663..7bd2e90fe 100644 --- a/Emby.Server.Implementations/Localization/Core/de.json +++ b/Emby.Server.Implementations/Localization/Core/de.json @@ -14,7 +14,6 @@ "FailedLoginAttemptWithUserName": "Fehlgeschlagener Anmeldeversuch von {0}", "Favorites": "Favoriten", "Folders": "Verzeichnisse", - "Games": "Spiele", "Genres": "Genres", "HeaderAlbumArtists": "Album-Künstler", "HeaderCameraUploads": "Kamera Uploads", @@ -51,8 +50,6 @@ "NotificationOptionAudioPlayback": "Audiowiedergabe gestartet", "NotificationOptionAudioPlaybackStopped": "Audiowiedergabe gestoppt", "NotificationOptionCameraImageUploaded": "Kamera Bild hochgeladen", - "NotificationOptionGamePlayback": "Spielwiedergabe gestartet", - "NotificationOptionGamePlaybackStopped": "Spielwiedergabe gestoppt", "NotificationOptionInstallationFailed": "Installationsfehler", "NotificationOptionNewLibraryContent": "Neuer Inhalt hinzugefügt", "NotificationOptionPluginError": "Plugin Fehler", diff --git a/Emby.Server.Implementations/Localization/Core/el.json b/Emby.Server.Implementations/Localization/Core/el.json index ba687a089..91ca34edc 100644 --- a/Emby.Server.Implementations/Localization/Core/el.json +++ b/Emby.Server.Implementations/Localization/Core/el.json @@ -14,7 +14,6 @@ "FailedLoginAttemptWithUserName": "Αποτυχημένη προσπάθεια σύνδεσης από {0}", "Favorites": "Αγαπημένα", "Folders": "Φάκελοι", - "Games": "Παιχνίδια", "Genres": "Είδη", "HeaderAlbumArtists": "Άλμπουμ Καλλιτεχνών", "HeaderCameraUploads": "Camera Uploads", @@ -51,8 +50,6 @@ "NotificationOptionAudioPlayback": "Η αναπαραγωγή ήχου ξεκίνησε", "NotificationOptionAudioPlaybackStopped": "Η αναπαραγωγή ήχου σταμάτησε", "NotificationOptionCameraImageUploaded": "Camera image uploaded", - "NotificationOptionGamePlayback": "Η αναπαραγωγή του παιχνιδιού ξεκίνησε", - "NotificationOptionGamePlaybackStopped": "Η αναπαραγωγή του παιχνιδιού σταμάτησε", "NotificationOptionInstallationFailed": "Αποτυχία εγκατάστασης", "NotificationOptionNewLibraryContent": "Προστέθηκε νέο περιεχόμενο", "NotificationOptionPluginError": "Αποτυχία του plugin", diff --git a/Emby.Server.Implementations/Localization/Core/en-GB.json b/Emby.Server.Implementations/Localization/Core/en-GB.json index 20d397a1a..332902292 100644 --- a/Emby.Server.Implementations/Localization/Core/en-GB.json +++ b/Emby.Server.Implementations/Localization/Core/en-GB.json @@ -14,7 +14,6 @@ "FailedLoginAttemptWithUserName": "Failed login attempt from {0}", "Favorites": "Favourites", "Folders": "Folders", - "Games": "Games", "Genres": "Genres", "HeaderAlbumArtists": "Album Artists", "HeaderCameraUploads": "Camera Uploads", @@ -51,8 +50,6 @@ "NotificationOptionAudioPlayback": "Audio playback started", "NotificationOptionAudioPlaybackStopped": "Audio playback stopped", "NotificationOptionCameraImageUploaded": "Camera image uploaded", - "NotificationOptionGamePlayback": "Game playback started", - "NotificationOptionGamePlaybackStopped": "Game playback stopped", "NotificationOptionInstallationFailed": "Installation failure", "NotificationOptionNewLibraryContent": "New content added", "NotificationOptionPluginError": "Plugin failure", diff --git a/Emby.Server.Implementations/Localization/Core/en-US.json b/Emby.Server.Implementations/Localization/Core/en-US.json index 69c8bf03c..f19cd532b 100644 --- a/Emby.Server.Implementations/Localization/Core/en-US.json +++ b/Emby.Server.Implementations/Localization/Core/en-US.json @@ -14,7 +14,6 @@ "FailedLoginAttemptWithUserName": "Failed login attempt from {0}", "Favorites": "Favorites", "Folders": "Folders", - "Games": "Games", "Genres": "Genres", "HeaderAlbumArtists": "Album Artists", "HeaderCameraUploads": "Camera Uploads", @@ -51,8 +50,6 @@ "NotificationOptionAudioPlayback": "Audio playback started", "NotificationOptionAudioPlaybackStopped": "Audio playback stopped", "NotificationOptionCameraImageUploaded": "Camera image uploaded", - "NotificationOptionGamePlayback": "Game playback started", - "NotificationOptionGamePlaybackStopped": "Game playback stopped", "NotificationOptionInstallationFailed": "Installation failure", "NotificationOptionNewLibraryContent": "New content added", "NotificationOptionPluginError": "Plugin failure", diff --git a/Emby.Server.Implementations/Localization/Core/es-AR.json b/Emby.Server.Implementations/Localization/Core/es-AR.json index aaaf09788..c01bb0c50 100644 --- a/Emby.Server.Implementations/Localization/Core/es-AR.json +++ b/Emby.Server.Implementations/Localization/Core/es-AR.json @@ -14,7 +14,6 @@ "FailedLoginAttemptWithUserName": "Failed login attempt from {0}", "Favorites": "Favorites", "Folders": "Folders", - "Games": "Games", "Genres": "Genres", "HeaderAlbumArtists": "Album Artists", "HeaderCameraUploads": "Camera Uploads", @@ -51,8 +50,6 @@ "NotificationOptionAudioPlayback": "Audio playback started", "NotificationOptionAudioPlaybackStopped": "Audio playback stopped", "NotificationOptionCameraImageUploaded": "Camera image uploaded", - "NotificationOptionGamePlayback": "Game playback started", - "NotificationOptionGamePlaybackStopped": "Game playback stopped", "NotificationOptionInstallationFailed": "Installation failure", "NotificationOptionNewLibraryContent": "New content added", "NotificationOptionPluginError": "Plugin failure", diff --git a/Emby.Server.Implementations/Localization/Core/es-MX.json b/Emby.Server.Implementations/Localization/Core/es-MX.json index 2ba9c8c7a..2285f2808 100644 --- a/Emby.Server.Implementations/Localization/Core/es-MX.json +++ b/Emby.Server.Implementations/Localization/Core/es-MX.json @@ -14,7 +14,6 @@ "FailedLoginAttemptWithUserName": "Intento fallido de inicio de sesión de {0}", "Favorites": "Favoritos", "Folders": "Carpetas", - "Games": "Juegos", "Genres": "Géneros", "HeaderAlbumArtists": "Artistas del Álbum", "HeaderCameraUploads": "Subidos desde Camara", @@ -51,8 +50,6 @@ "NotificationOptionAudioPlayback": "Reproducción de audio iniciada", "NotificationOptionAudioPlaybackStopped": "Reproducción de audio detenida", "NotificationOptionCameraImageUploaded": "Imagen de la cámara subida", - "NotificationOptionGamePlayback": "Ejecución de juego iniciada", - "NotificationOptionGamePlaybackStopped": "Ejecución de juego detenida", "NotificationOptionInstallationFailed": "Falla de instalación", "NotificationOptionNewLibraryContent": "Nuevo contenido agregado", "NotificationOptionPluginError": "Falla de complemento", diff --git a/Emby.Server.Implementations/Localization/Core/es.json b/Emby.Server.Implementations/Localization/Core/es.json index 38a282382..5d118d21f 100644 --- a/Emby.Server.Implementations/Localization/Core/es.json +++ b/Emby.Server.Implementations/Localization/Core/es.json @@ -14,7 +14,6 @@ "FailedLoginAttemptWithUserName": "Error al intentar iniciar sesión a partir de {0}", "Favorites": "Favoritos", "Folders": "Carpetas", - "Games": "Juegos", "Genres": "Géneros", "HeaderAlbumArtists": "Artistas del Álbum", "HeaderCameraUploads": "Camera Uploads", @@ -51,8 +50,6 @@ "NotificationOptionAudioPlayback": "Se inició la reproducción de audio", "NotificationOptionAudioPlaybackStopped": "Se detuvo la reproducción de audio", "NotificationOptionCameraImageUploaded": "Imagen de la cámara cargada", - "NotificationOptionGamePlayback": "Se inició la reproducción del juego", - "NotificationOptionGamePlaybackStopped": "Se detuvo la reproducción del juego", "NotificationOptionInstallationFailed": "Error de instalación", "NotificationOptionNewLibraryContent": "Nuevo contenido añadido", "NotificationOptionPluginError": "Error en plugin", diff --git a/Emby.Server.Implementations/Localization/Core/fa.json b/Emby.Server.Implementations/Localization/Core/fa.json index 1d7bc5fe8..0a0c7553b 100644 --- a/Emby.Server.Implementations/Localization/Core/fa.json +++ b/Emby.Server.Implementations/Localization/Core/fa.json @@ -14,7 +14,6 @@ "FailedLoginAttemptWithUserName": "تلاش برای ورود از {0} ناموفق بود", "Favorites": "مورد علاقه ها", "Folders": "پوشه ها", - "Games": "بازی ها", "Genres": "ژانرها", "HeaderAlbumArtists": "هنرمندان آلبوم", "HeaderCameraUploads": "آپلودهای دوربین", @@ -51,8 +50,6 @@ "NotificationOptionAudioPlayback": "پخش صدا آغاز شد", "NotificationOptionAudioPlaybackStopped": "پخش صدا متوقف شد", "NotificationOptionCameraImageUploaded": "تصاویر دوربین آپلود شد", - "NotificationOptionGamePlayback": "پخش بازی آغاز شد", - "NotificationOptionGamePlaybackStopped": "پخش بازی متوقف شد", "NotificationOptionInstallationFailed": "شکست نصب", "NotificationOptionNewLibraryContent": "محتوای جدید افزوده شد", "NotificationOptionPluginError": "خرابی افزونه", diff --git a/Emby.Server.Implementations/Localization/Core/fr-CA.json b/Emby.Server.Implementations/Localization/Core/fr-CA.json index 22cd4cf6d..7202be9f5 100644 --- a/Emby.Server.Implementations/Localization/Core/fr-CA.json +++ b/Emby.Server.Implementations/Localization/Core/fr-CA.json @@ -14,7 +14,6 @@ "FailedLoginAttemptWithUserName": "Failed login attempt from {0}", "Favorites": "Favorites", "Folders": "Folders", - "Games": "Games", "Genres": "Genres", "HeaderAlbumArtists": "Album Artists", "HeaderCameraUploads": "Camera Uploads", @@ -51,8 +50,6 @@ "NotificationOptionAudioPlayback": "Audio playback started", "NotificationOptionAudioPlaybackStopped": "Audio playback stopped", "NotificationOptionCameraImageUploaded": "Camera image uploaded", - "NotificationOptionGamePlayback": "Game playback started", - "NotificationOptionGamePlaybackStopped": "Game playback stopped", "NotificationOptionInstallationFailed": "Installation failure", "NotificationOptionNewLibraryContent": "New content added", "NotificationOptionPluginError": "Plugin failure", diff --git a/Emby.Server.Implementations/Localization/Core/fr.json b/Emby.Server.Implementations/Localization/Core/fr.json index 085e22cf7..aa9a1add3 100644 --- a/Emby.Server.Implementations/Localization/Core/fr.json +++ b/Emby.Server.Implementations/Localization/Core/fr.json @@ -14,7 +14,6 @@ "FailedLoginAttemptWithUserName": "Échec d'une tentative de connexion de {0}", "Favorites": "Favoris", "Folders": "Dossiers", - "Games": "Jeux", "Genres": "Genres", "HeaderAlbumArtists": "Artistes de l'album", "HeaderCameraUploads": "Photos transférées", @@ -51,8 +50,6 @@ "NotificationOptionAudioPlayback": "Lecture audio démarrée", "NotificationOptionAudioPlaybackStopped": "Lecture audio arrêtée", "NotificationOptionCameraImageUploaded": "L'image de l'appareil photo a été transférée", - "NotificationOptionGamePlayback": "Lecture de jeu démarrée", - "NotificationOptionGamePlaybackStopped": "Lecture de jeu arrêtée", "NotificationOptionInstallationFailed": "Échec d'installation", "NotificationOptionNewLibraryContent": "Nouveau contenu ajouté", "NotificationOptionPluginError": "Erreur d'extension", diff --git a/Emby.Server.Implementations/Localization/Core/gsw.json b/Emby.Server.Implementations/Localization/Core/gsw.json index 537fe35d5..728002a56 100644 --- a/Emby.Server.Implementations/Localization/Core/gsw.json +++ b/Emby.Server.Implementations/Localization/Core/gsw.json @@ -14,7 +14,6 @@ "FailedLoginAttemptWithUserName": "Failed login attempt from {0}", "Favorites": "Favorites", "Folders": "Folders", - "Games": "Spiel", "Genres": "Genres", "HeaderAlbumArtists": "Albuminterprete", "HeaderCameraUploads": "Camera Uploads", @@ -51,8 +50,6 @@ "NotificationOptionAudioPlayback": "Audio playback started", "NotificationOptionAudioPlaybackStopped": "Audio playback stopped", "NotificationOptionCameraImageUploaded": "Camera image uploaded", - "NotificationOptionGamePlayback": "Game playback started", - "NotificationOptionGamePlaybackStopped": "Game playback stopped", "NotificationOptionInstallationFailed": "Installation failure", "NotificationOptionNewLibraryContent": "New content added", "NotificationOptionPluginError": "Plugin failure", diff --git a/Emby.Server.Implementations/Localization/Core/he.json b/Emby.Server.Implementations/Localization/Core/he.json index 6fff9d0ab..fff1d1f0e 100644 --- a/Emby.Server.Implementations/Localization/Core/he.json +++ b/Emby.Server.Implementations/Localization/Core/he.json @@ -14,7 +14,6 @@ "FailedLoginAttemptWithUserName": "Failed login attempt from {0}", "Favorites": "Favorites", "Folders": "Folders", - "Games": "משחקים", "Genres": "ז'אנרים", "HeaderAlbumArtists": "Album Artists", "HeaderCameraUploads": "Camera Uploads", @@ -51,8 +50,6 @@ "NotificationOptionAudioPlayback": "Audio playback started", "NotificationOptionAudioPlaybackStopped": "Audio playback stopped", "NotificationOptionCameraImageUploaded": "Camera image uploaded", - "NotificationOptionGamePlayback": "Game playback started", - "NotificationOptionGamePlaybackStopped": "Game playback stopped", "NotificationOptionInstallationFailed": "Installation failure", "NotificationOptionNewLibraryContent": "New content added", "NotificationOptionPluginError": "Plugin failure", diff --git a/Emby.Server.Implementations/Localization/Core/hr.json b/Emby.Server.Implementations/Localization/Core/hr.json index 3232a4ff7..f284b3cd9 100644 --- a/Emby.Server.Implementations/Localization/Core/hr.json +++ b/Emby.Server.Implementations/Localization/Core/hr.json @@ -14,7 +14,6 @@ "FailedLoginAttemptWithUserName": "Neuspjeli pokušaj prijave za {0}", "Favorites": "Omiljeni", "Folders": "Mape", - "Games": "Igre", "Genres": "Žanrovi", "HeaderAlbumArtists": "Izvođači albuma", "HeaderCameraUploads": "Camera Uploads", @@ -51,8 +50,6 @@ "NotificationOptionAudioPlayback": "Reprodukcija glazbe započeta", "NotificationOptionAudioPlaybackStopped": "Reprodukcija audiozapisa je zaustavljena", "NotificationOptionCameraImageUploaded": "Slike kamere preuzete", - "NotificationOptionGamePlayback": "Igrica pokrenuta", - "NotificationOptionGamePlaybackStopped": "Reprodukcija igre je zaustavljena", "NotificationOptionInstallationFailed": "Instalacija nije izvršena", "NotificationOptionNewLibraryContent": "Novi sadržaj je dodan", "NotificationOptionPluginError": "Dodatak otkazao", diff --git a/Emby.Server.Implementations/Localization/Core/hu.json b/Emby.Server.Implementations/Localization/Core/hu.json index 3a0119faf..d2d16b18f 100644 --- a/Emby.Server.Implementations/Localization/Core/hu.json +++ b/Emby.Server.Implementations/Localization/Core/hu.json @@ -14,7 +14,6 @@ "FailedLoginAttemptWithUserName": "Failed login attempt from {0}", "Favorites": "Kedvencek", "Folders": "Könyvtárak", - "Games": "Játékok", "Genres": "Műfajok", "HeaderAlbumArtists": "Album Előadók", "HeaderCameraUploads": "Camera Uploads", @@ -51,8 +50,6 @@ "NotificationOptionAudioPlayback": "Audió lejátszás elkezdve", "NotificationOptionAudioPlaybackStopped": "Audió lejátszás befejezve", "NotificationOptionCameraImageUploaded": "Kamera kép feltöltve", - "NotificationOptionGamePlayback": "Game playback started", - "NotificationOptionGamePlaybackStopped": "Game playback stopped", "NotificationOptionInstallationFailed": "Telepítési hiba", "NotificationOptionNewLibraryContent": "Új tartalom hozzáadva", "NotificationOptionPluginError": "Bővítmény hiba", diff --git a/Emby.Server.Implementations/Localization/Core/it.json b/Emby.Server.Implementations/Localization/Core/it.json index 58b7bb61a..b3d9c16cf 100644 --- a/Emby.Server.Implementations/Localization/Core/it.json +++ b/Emby.Server.Implementations/Localization/Core/it.json @@ -14,7 +14,6 @@ "FailedLoginAttemptWithUserName": "Tentativo di accesso fallito da {0}", "Favorites": "Preferiti", "Folders": "Cartelle", - "Games": "Giochi", "Genres": "Generi", "HeaderAlbumArtists": "Artisti Album", "HeaderCameraUploads": "Caricamenti Fotocamera", @@ -51,8 +50,6 @@ "NotificationOptionAudioPlayback": "La riproduzione audio è iniziata", "NotificationOptionAudioPlaybackStopped": "La riproduzione audio è stata interrotta", "NotificationOptionCameraImageUploaded": "Immagine fotocamera caricata", - "NotificationOptionGamePlayback": "Il gioco è stato avviato", - "NotificationOptionGamePlaybackStopped": "Il gioco è stato fermato", "NotificationOptionInstallationFailed": "Installazione fallita", "NotificationOptionNewLibraryContent": "Nuovo contenuto aggiunto", "NotificationOptionPluginError": "Errore del Plug-in", diff --git a/Emby.Server.Implementations/Localization/Core/kk.json b/Emby.Server.Implementations/Localization/Core/kk.json index 45b8617f1..ae256f79d 100644 --- a/Emby.Server.Implementations/Localization/Core/kk.json +++ b/Emby.Server.Implementations/Localization/Core/kk.json @@ -14,7 +14,6 @@ "FailedLoginAttemptWithUserName": "{0} тарапынан кіру әрекеті сәтсіз", "Favorites": "Таңдаулылар", "Folders": "Қалталар", - "Games": "Ойындар", "Genres": "Жанрлар", "HeaderAlbumArtists": "Альбом орындаушылары", "HeaderCameraUploads": "Камерадан жүктелгендер", @@ -51,8 +50,6 @@ "NotificationOptionAudioPlayback": "Дыбыс ойнатуы басталды", "NotificationOptionAudioPlaybackStopped": "Дыбыс ойнатуы тоқтатылды", "NotificationOptionCameraImageUploaded": "Камерадан фотосурет кері қотарылған", - "NotificationOptionGamePlayback": "Ойын ойнатуы басталды", - "NotificationOptionGamePlaybackStopped": "Ойын ойнатуы тоқтатылды", "NotificationOptionInstallationFailed": "Орнату сәтсіздігі", "NotificationOptionNewLibraryContent": "Жаңа мазмұн үстелген", "NotificationOptionPluginError": "Плагин сәтсіздігі", diff --git a/Emby.Server.Implementations/Localization/Core/ko.json b/Emby.Server.Implementations/Localization/Core/ko.json index 04fc52d6e..21808fd18 100644 --- a/Emby.Server.Implementations/Localization/Core/ko.json +++ b/Emby.Server.Implementations/Localization/Core/ko.json @@ -14,7 +14,6 @@ "FailedLoginAttemptWithUserName": "Failed login attempt from {0}", "Favorites": "Favorites", "Folders": "Folders", - "Games": "Games", "Genres": "Genres", "HeaderAlbumArtists": "앨범 아티스트", "HeaderCameraUploads": "Camera Uploads", @@ -51,8 +50,6 @@ "NotificationOptionAudioPlayback": "Audio playback started", "NotificationOptionAudioPlaybackStopped": "Audio playback stopped", "NotificationOptionCameraImageUploaded": "Camera image uploaded", - "NotificationOptionGamePlayback": "Game playback started", - "NotificationOptionGamePlaybackStopped": "Game playback stopped", "NotificationOptionInstallationFailed": "Installation failure", "NotificationOptionNewLibraryContent": "New content added", "NotificationOptionPluginError": "Plugin failure", diff --git a/Emby.Server.Implementations/Localization/Core/lt-LT.json b/Emby.Server.Implementations/Localization/Core/lt-LT.json index 653565db6..558904f06 100644 --- a/Emby.Server.Implementations/Localization/Core/lt-LT.json +++ b/Emby.Server.Implementations/Localization/Core/lt-LT.json @@ -14,7 +14,6 @@ "FailedLoginAttemptWithUserName": "Failed login attempt from {0}", "Favorites": "Favorites", "Folders": "Folders", - "Games": "Games", "Genres": "Žanrai", "HeaderAlbumArtists": "Album Artists", "HeaderCameraUploads": "Camera Uploads", @@ -51,8 +50,6 @@ "NotificationOptionAudioPlayback": "Audio playback started", "NotificationOptionAudioPlaybackStopped": "Audio playback stopped", "NotificationOptionCameraImageUploaded": "Camera image uploaded", - "NotificationOptionGamePlayback": "Game playback started", - "NotificationOptionGamePlaybackStopped": "Game playback stopped", "NotificationOptionInstallationFailed": "Installation failure", "NotificationOptionNewLibraryContent": "New content added", "NotificationOptionPluginError": "Plugin failure", diff --git a/Emby.Server.Implementations/Localization/Core/ms.json b/Emby.Server.Implementations/Localization/Core/ms.json index aaaf09788..c01bb0c50 100644 --- a/Emby.Server.Implementations/Localization/Core/ms.json +++ b/Emby.Server.Implementations/Localization/Core/ms.json @@ -14,7 +14,6 @@ "FailedLoginAttemptWithUserName": "Failed login attempt from {0}", "Favorites": "Favorites", "Folders": "Folders", - "Games": "Games", "Genres": "Genres", "HeaderAlbumArtists": "Album Artists", "HeaderCameraUploads": "Camera Uploads", @@ -51,8 +50,6 @@ "NotificationOptionAudioPlayback": "Audio playback started", "NotificationOptionAudioPlaybackStopped": "Audio playback stopped", "NotificationOptionCameraImageUploaded": "Camera image uploaded", - "NotificationOptionGamePlayback": "Game playback started", - "NotificationOptionGamePlaybackStopped": "Game playback stopped", "NotificationOptionInstallationFailed": "Installation failure", "NotificationOptionNewLibraryContent": "New content added", "NotificationOptionPluginError": "Plugin failure", diff --git a/Emby.Server.Implementations/Localization/Core/nb.json b/Emby.Server.Implementations/Localization/Core/nb.json index ed63aa29c..dbda794ad 100644 --- a/Emby.Server.Implementations/Localization/Core/nb.json +++ b/Emby.Server.Implementations/Localization/Core/nb.json @@ -14,7 +14,6 @@ "FailedLoginAttemptWithUserName": "Mislykket påloggingsforsøk fra {0}", "Favorites": "Favoritter", "Folders": "Mapper", - "Games": "Spill", "Genres": "Sjanger", "HeaderAlbumArtists": "Albumartist", "HeaderCameraUploads": "Camera Uploads", @@ -51,8 +50,6 @@ "NotificationOptionAudioPlayback": "Lyd tilbakespilling startet", "NotificationOptionAudioPlaybackStopped": "Lyd avspilling stoppet", "NotificationOptionCameraImageUploaded": "Kamera bilde lastet opp", - "NotificationOptionGamePlayback": "Spill avspillingen startet", - "NotificationOptionGamePlaybackStopped": "Filmer", "NotificationOptionInstallationFailed": "Installasjon feil", "NotificationOptionNewLibraryContent": "Ny innhold er lagt til", "NotificationOptionPluginError": "Plugin feil", diff --git a/Emby.Server.Implementations/Localization/Core/nl.json b/Emby.Server.Implementations/Localization/Core/nl.json index 7b8c8765e..589753c44 100644 --- a/Emby.Server.Implementations/Localization/Core/nl.json +++ b/Emby.Server.Implementations/Localization/Core/nl.json @@ -14,7 +14,6 @@ "FailedLoginAttemptWithUserName": "Mislukte aanmeld poging van {0}", "Favorites": "Favorieten", "Folders": "Mappen", - "Games": "Spellen", "Genres": "Genres", "HeaderAlbumArtists": "Album artiesten", "HeaderCameraUploads": "Camera uploads", @@ -51,8 +50,6 @@ "NotificationOptionAudioPlayback": "Geluid gestart", "NotificationOptionAudioPlaybackStopped": "Geluid gestopt", "NotificationOptionCameraImageUploaded": "Camera afbeelding geüpload", - "NotificationOptionGamePlayback": "Spel gestart", - "NotificationOptionGamePlaybackStopped": "Spel gestopt", "NotificationOptionInstallationFailed": "Installatie mislukt", "NotificationOptionNewLibraryContent": "Nieuwe content toegevoegd", "NotificationOptionPluginError": "Plug-in fout", diff --git a/Emby.Server.Implementations/Localization/Core/pl.json b/Emby.Server.Implementations/Localization/Core/pl.json index 5aefa740b..92b12409d 100644 --- a/Emby.Server.Implementations/Localization/Core/pl.json +++ b/Emby.Server.Implementations/Localization/Core/pl.json @@ -14,7 +14,6 @@ "FailedLoginAttemptWithUserName": "Próba logowania przez {0} zakończona niepowodzeniem", "Favorites": "Ulubione", "Folders": "Foldery", - "Games": "Gry", "Genres": "Gatunki", "HeaderAlbumArtists": "Wykonawcy albumów", "HeaderCameraUploads": "Przekazane obrazy", @@ -51,8 +50,6 @@ "NotificationOptionAudioPlayback": "Rozpoczęto odtwarzanie muzyki", "NotificationOptionAudioPlaybackStopped": "Odtwarzane dźwięku zatrzymane", "NotificationOptionCameraImageUploaded": "Przekazano obraz z urządzenia mobilnego", - "NotificationOptionGamePlayback": "Odtwarzanie gry rozpoczęte", - "NotificationOptionGamePlaybackStopped": "Odtwarzanie gry zatrzymane", "NotificationOptionInstallationFailed": "Niepowodzenie instalacji", "NotificationOptionNewLibraryContent": "Dodano nową zawartość", "NotificationOptionPluginError": "Awaria wtyczki", diff --git a/Emby.Server.Implementations/Localization/Core/pt-BR.json b/Emby.Server.Implementations/Localization/Core/pt-BR.json index 9ae25d3ac..aaedf0850 100644 --- a/Emby.Server.Implementations/Localization/Core/pt-BR.json +++ b/Emby.Server.Implementations/Localization/Core/pt-BR.json @@ -14,7 +14,6 @@ "FailedLoginAttemptWithUserName": "Falha na tentativa de login de {0}", "Favorites": "Favoritos", "Folders": "Pastas", - "Games": "Jogos", "Genres": "Gêneros", "HeaderAlbumArtists": "Artistas do Álbum", "HeaderCameraUploads": "Uploads da Câmera", @@ -51,8 +50,6 @@ "NotificationOptionAudioPlayback": "Reprodução de áudio iniciada", "NotificationOptionAudioPlaybackStopped": "Reprodução de áudio parada", "NotificationOptionCameraImageUploaded": "Imagem de câmera enviada", - "NotificationOptionGamePlayback": "Reprodução de jogo iniciada", - "NotificationOptionGamePlaybackStopped": "Reprodução de jogo parada", "NotificationOptionInstallationFailed": "Falha na instalação", "NotificationOptionNewLibraryContent": "Novo conteúdo adicionado", "NotificationOptionPluginError": "Falha de plugin", diff --git a/Emby.Server.Implementations/Localization/Core/pt-PT.json b/Emby.Server.Implementations/Localization/Core/pt-PT.json index 59c25f0e3..dc69d8af2 100644 --- a/Emby.Server.Implementations/Localization/Core/pt-PT.json +++ b/Emby.Server.Implementations/Localization/Core/pt-PT.json @@ -14,7 +14,6 @@ "FailedLoginAttemptWithUserName": "Failed login attempt from {0}", "Favorites": "Favorites", "Folders": "Folders", - "Games": "Games", "Genres": "Genres", "HeaderAlbumArtists": "Album Artists", "HeaderCameraUploads": "Camera Uploads", @@ -51,8 +50,6 @@ "NotificationOptionAudioPlayback": "Audio playback started", "NotificationOptionAudioPlaybackStopped": "Audio playback stopped", "NotificationOptionCameraImageUploaded": "Camera image uploaded", - "NotificationOptionGamePlayback": "Game playback started", - "NotificationOptionGamePlaybackStopped": "Game playback stopped", "NotificationOptionInstallationFailed": "Installation failure", "NotificationOptionNewLibraryContent": "New content added", "NotificationOptionPluginError": "Plugin failure", diff --git a/Emby.Server.Implementations/Localization/Core/ru.json b/Emby.Server.Implementations/Localization/Core/ru.json index 338141294..d799fa50b 100644 --- a/Emby.Server.Implementations/Localization/Core/ru.json +++ b/Emby.Server.Implementations/Localization/Core/ru.json @@ -14,7 +14,6 @@ "FailedLoginAttemptWithUserName": "{0} - попытка входа неудачна", "Favorites": "Избранное", "Folders": "Папки", - "Games": "Игры", "Genres": "Жанры", "HeaderAlbumArtists": "Исп-ли альбома", "HeaderCameraUploads": "Камеры", @@ -51,8 +50,6 @@ "NotificationOptionAudioPlayback": "Воспр-ие аудио зап-но", "NotificationOptionAudioPlaybackStopped": "Восп-ие аудио ост-но", "NotificationOptionCameraImageUploaded": "Произведена выкладка отснятого с камеры", - "NotificationOptionGamePlayback": "Воспр-ие игры зап-но", - "NotificationOptionGamePlaybackStopped": "Восп-ие игры ост-но", "NotificationOptionInstallationFailed": "Сбой установки", "NotificationOptionNewLibraryContent": "Новое содержание добавлено", "NotificationOptionPluginError": "Сбой плагина", diff --git a/Emby.Server.Implementations/Localization/Core/sk.json b/Emby.Server.Implementations/Localization/Core/sk.json index ed0c68952..bc7e7184e 100644 --- a/Emby.Server.Implementations/Localization/Core/sk.json +++ b/Emby.Server.Implementations/Localization/Core/sk.json @@ -14,7 +14,6 @@ "FailedLoginAttemptWithUserName": "Neúspešný pokus o prihlásenie z {0}", "Favorites": "Obľúbené", "Folders": "Priečinky", - "Games": "Hry", "Genres": "Žánre", "HeaderAlbumArtists": "Album Artists", "HeaderCameraUploads": "Camera Uploads", @@ -51,8 +50,6 @@ "NotificationOptionAudioPlayback": "Spustené prehrávanie audia", "NotificationOptionAudioPlaybackStopped": "Zastavené prehrávanie audia", "NotificationOptionCameraImageUploaded": "Nahraný obrázok z fotoaparátu", - "NotificationOptionGamePlayback": "Game playback started", - "NotificationOptionGamePlaybackStopped": "Hra ukončená", "NotificationOptionInstallationFailed": "Chyba inštalácie", "NotificationOptionNewLibraryContent": "Pridaný nový obsah", "NotificationOptionPluginError": "Chyba rozšírenia", diff --git a/Emby.Server.Implementations/Localization/Core/sl-SI.json b/Emby.Server.Implementations/Localization/Core/sl-SI.json index 8fe279836..e850257d4 100644 --- a/Emby.Server.Implementations/Localization/Core/sl-SI.json +++ b/Emby.Server.Implementations/Localization/Core/sl-SI.json @@ -14,7 +14,6 @@ "FailedLoginAttemptWithUserName": "Failed login attempt from {0}", "Favorites": "Favorites", "Folders": "Folders", - "Games": "Games", "Genres": "Genres", "HeaderAlbumArtists": "Album Artists", "HeaderCameraUploads": "Camera Uploads", @@ -51,8 +50,6 @@ "NotificationOptionAudioPlayback": "Audio playback started", "NotificationOptionAudioPlaybackStopped": "Audio playback stopped", "NotificationOptionCameraImageUploaded": "Camera image uploaded", - "NotificationOptionGamePlayback": "Game playback started", - "NotificationOptionGamePlaybackStopped": "Game playback stopped", "NotificationOptionInstallationFailed": "Installation failure", "NotificationOptionNewLibraryContent": "New content added", "NotificationOptionPluginError": "Plugin failure", diff --git a/Emby.Server.Implementations/Localization/Core/sv.json b/Emby.Server.Implementations/Localization/Core/sv.json index 517d648bb..fb2761a7d 100644 --- a/Emby.Server.Implementations/Localization/Core/sv.json +++ b/Emby.Server.Implementations/Localization/Core/sv.json @@ -14,7 +14,6 @@ "FailedLoginAttemptWithUserName": "Misslyckat inloggningsförsök från {0}", "Favorites": "Favoriter", "Folders": "Mappar", - "Games": "Spel", "Genres": "Genrer", "HeaderAlbumArtists": "Albumartister", "HeaderCameraUploads": "Camera Uploads", @@ -51,8 +50,6 @@ "NotificationOptionAudioPlayback": "Ljuduppspelning har påbörjats", "NotificationOptionAudioPlaybackStopped": "Ljuduppspelning stoppad", "NotificationOptionCameraImageUploaded": "Kamerabild har laddats upp", - "NotificationOptionGamePlayback": "Spel har startats", - "NotificationOptionGamePlaybackStopped": "Spel stoppat", "NotificationOptionInstallationFailed": "Fel vid installation", "NotificationOptionNewLibraryContent": "Nytt innehåll har lagts till", "NotificationOptionPluginError": "Fel uppstod med tillägget", diff --git a/Emby.Server.Implementations/Localization/Core/tr.json b/Emby.Server.Implementations/Localization/Core/tr.json index 9e86e2125..495f82db6 100644 --- a/Emby.Server.Implementations/Localization/Core/tr.json +++ b/Emby.Server.Implementations/Localization/Core/tr.json @@ -14,7 +14,6 @@ "FailedLoginAttemptWithUserName": "Failed login attempt from {0}", "Favorites": "Favorites", "Folders": "Folders", - "Games": "Games", "Genres": "Genres", "HeaderAlbumArtists": "Album Artists", "HeaderCameraUploads": "Camera Uploads", @@ -51,8 +50,6 @@ "NotificationOptionAudioPlayback": "Audio playback started", "NotificationOptionAudioPlaybackStopped": "Audio playback stopped", "NotificationOptionCameraImageUploaded": "Camera image uploaded", - "NotificationOptionGamePlayback": "Game playback started", - "NotificationOptionGamePlaybackStopped": "Game playback stopped", "NotificationOptionInstallationFailed": "Installation failure", "NotificationOptionNewLibraryContent": "New content added", "NotificationOptionPluginError": "Plugin failure", diff --git a/Emby.Server.Implementations/Localization/Core/zh-CN.json b/Emby.Server.Implementations/Localization/Core/zh-CN.json index 6d877ec17..8910a6bce 100644 --- a/Emby.Server.Implementations/Localization/Core/zh-CN.json +++ b/Emby.Server.Implementations/Localization/Core/zh-CN.json @@ -14,7 +14,6 @@ "FailedLoginAttemptWithUserName": "来自 {0} 的失败登入", "Favorites": "最爱", "Folders": "文件夹", - "Games": "游戏", "Genres": "风格", "HeaderAlbumArtists": "专辑作家", "HeaderCameraUploads": "相机上传", @@ -51,8 +50,6 @@ "NotificationOptionAudioPlayback": "音频开始播放", "NotificationOptionAudioPlaybackStopped": "音频播放已停止", "NotificationOptionCameraImageUploaded": "相机图片已上传", - "NotificationOptionGamePlayback": "游戏开始", - "NotificationOptionGamePlaybackStopped": "游戏停止", "NotificationOptionInstallationFailed": "安装失败", "NotificationOptionNewLibraryContent": "已添加新内容", "NotificationOptionPluginError": "插件失败", diff --git a/Emby.Server.Implementations/Localization/Core/zh-HK.json b/Emby.Server.Implementations/Localization/Core/zh-HK.json index cad5700fd..387fc2b92 100644 --- a/Emby.Server.Implementations/Localization/Core/zh-HK.json +++ b/Emby.Server.Implementations/Localization/Core/zh-HK.json @@ -14,7 +14,6 @@ "FailedLoginAttemptWithUserName": "Failed login attempt from {0}", "Favorites": "Favorites", "Folders": "Folders", - "Games": "Games", "Genres": "Genres", "HeaderAlbumArtists": "Album Artists", "HeaderCameraUploads": "Camera Uploads", @@ -51,8 +50,6 @@ "NotificationOptionAudioPlayback": "Audio playback started", "NotificationOptionAudioPlaybackStopped": "Audio playback stopped", "NotificationOptionCameraImageUploaded": "Camera image uploaded", - "NotificationOptionGamePlayback": "Game playback started", - "NotificationOptionGamePlaybackStopped": "Game playback stopped", "NotificationOptionInstallationFailed": "Installation failure", "NotificationOptionNewLibraryContent": "New content added", "NotificationOptionPluginError": "Plugin failure", diff --git a/Emby.Server.Implementations/Localization/LocalizationManager.cs b/Emby.Server.Implementations/Localization/LocalizationManager.cs index c3a7e1e9a..262ca24ec 100644 --- a/Emby.Server.Implementations/Localization/LocalizationManager.cs +++ b/Emby.Server.Implementations/Localization/LocalizationManager.cs @@ -465,11 +465,11 @@ namespace Emby.Server.Implementations.Localization if (parts.Length == 2) { - culture = parts[0].ToLower() + "-" + parts[1].ToUpper(); + culture = parts[0].ToLowerInvariant() + "-" + parts[1].ToUpperInvariant(); } else { - culture = culture.ToLower(); + culture = culture.ToLowerInvariant(); } return culture + ".json"; diff --git a/Emby.Server.Implementations/Localization/iso6392.txt b/Emby.Server.Implementations/Localization/iso6392.txt index f2cea78b6..40f8614f1 100644 --- a/Emby.Server.Implementations/Localization/iso6392.txt +++ b/Emby.Server.Implementations/Localization/iso6392.txt @@ -400,6 +400,7 @@ sog|||Sogdian|sogdien som||so|Somali|somali son|||Songhai languages|songhai, langues sot||st|Sotho, Southern|sotho du Sud +spa||es-mx|Spanish; Latin|espagnol; Latin spa||es|Spanish; Castilian|espagnol; castillan srd||sc|Sardinian|sarde srn|||Sranan Tongo|sranan tongo diff --git a/Emby.Server.Implementations/Networking/NetworkManager.cs b/Emby.Server.Implementations/Networking/NetworkManager.cs index f4b9f84dc..aa884664f 100644 --- a/Emby.Server.Implementations/Networking/NetworkManager.cs +++ b/Emby.Server.Implementations/Networking/NetworkManager.cs @@ -111,7 +111,8 @@ namespace Emby.Server.Implementations.Networking .OrderBy(i => i.AddressFamily == AddressFamily.InterNetwork ? 0 : 1) .ThenBy(i => listClone.IndexOf(i)) .Where(FilterIpAddress) - .DistinctBy(i => i.ToString()) + .GroupBy(i => i.ToString()) + .Select(x => x.First()) .ToList(); } @@ -429,7 +430,8 @@ namespace Emby.Server.Implementations.Networking return new List<IPAddress>(); } - }).DistinctBy(i => i.ToString()) + }).GroupBy(i => i.ToString()) + .Select(x => x.First()) .ToList(); } diff --git a/Emby.Server.Implementations/Playlists/PlaylistImageProvider.cs b/Emby.Server.Implementations/Playlists/PlaylistImageProvider.cs index 223153164..8a7c1492d 100644 --- a/Emby.Server.Implementations/Playlists/PlaylistImageProvider.cs +++ b/Emby.Server.Implementations/Playlists/PlaylistImageProvider.cs @@ -13,7 +13,6 @@ using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Playlists; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Entities; -using MediaBrowser.Model.Extensions; using MediaBrowser.Model.IO; using MediaBrowser.Model.Querying; @@ -64,7 +63,8 @@ namespace Emby.Server.Implementations.Playlists }) .Where(i => i != null) .OrderBy(i => Guid.NewGuid()) - .DistinctBy(i => i.Id) + .GroupBy(x => x.Id) + .Select(x => x.First()) .ToList(); } } diff --git a/Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs b/Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs index 2b648b04b..08bb39578 100644 --- a/Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs +++ b/Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs @@ -10,7 +10,6 @@ using MediaBrowser.Common.Progress; using MediaBrowser.Model.Events; using MediaBrowser.Model.IO; using MediaBrowser.Model.Serialization; -using MediaBrowser.Model.System; using MediaBrowser.Model.Tasks; using Microsoft.Extensions.Logging; diff --git a/Emby.Server.Implementations/ScheduledTasks/TaskManager.cs b/Emby.Server.Implementations/ScheduledTasks/TaskManager.cs index b8479fd26..595c3037d 100644 --- a/Emby.Server.Implementations/ScheduledTasks/TaskManager.cs +++ b/Emby.Server.Implementations/ScheduledTasks/TaskManager.cs @@ -1,14 +1,12 @@ using System; using System.Collections.Concurrent; using System.Collections.Generic; -using System.IO; using System.Linq; using System.Threading.Tasks; using MediaBrowser.Common.Configuration; using MediaBrowser.Model.Events; using MediaBrowser.Model.IO; using MediaBrowser.Model.Serialization; -using MediaBrowser.Model.System; using MediaBrowser.Model.Tasks; using Microsoft.Extensions.Logging; @@ -74,38 +72,6 @@ namespace Emby.Server.Implementations.ScheduledTasks ScheduledTasks = new IScheduledTaskWorker[] { }; } - private void RunStartupTasks() - { - var path = Path.Combine(ApplicationPaths.CachePath, "startuptasks.txt"); - - // ToDo: Fix this shit - if (!File.Exists(path)) - return; - - List<string> lines; - - try - { - lines = File.ReadAllLines(path).Where(i => !string.IsNullOrWhiteSpace(i)).Distinct(StringComparer.OrdinalIgnoreCase).ToList(); - - foreach (var key in lines) - { - var task = ScheduledTasks.FirstOrDefault(i => string.Equals(i.ScheduledTask.Key, key, StringComparison.OrdinalIgnoreCase)); - - if (task != null) - { - QueueScheduledTask(task, new TaskOptions()); - } - } - - _fileSystem.DeleteFile(path); - } - catch - { - return; - } - } - /// <summary> /// Cancels if running and queue. /// </summary> @@ -247,14 +213,9 @@ namespace Emby.Server.Implementations.ScheduledTasks /// <param name="tasks">The tasks.</param> public void AddTasks(IEnumerable<IScheduledTask> tasks) { - var myTasks = ScheduledTasks.ToList(); - - var list = tasks.ToList(); - myTasks.AddRange(list.Select(t => new ScheduledTaskWorker(t, ApplicationPaths, this, JsonSerializer, Logger, _fileSystem))); - - ScheduledTasks = myTasks.ToArray(); + var list = tasks.Select(t => new ScheduledTaskWorker(t, ApplicationPaths, this, JsonSerializer, Logger, _fileSystem)); - RunStartupTasks(); + ScheduledTasks = ScheduledTasks.Concat(list).ToArray(); } /// <summary> diff --git a/Emby.Server.Implementations/ScheduledTasks/ChapterImagesTask.cs b/Emby.Server.Implementations/ScheduledTasks/Tasks/ChapterImagesTask.cs index 5373b4392..81fdb96d2 100644 --- a/Emby.Server.Implementations/ScheduledTasks/ChapterImagesTask.cs +++ b/Emby.Server.Implementations/ScheduledTasks/Tasks/ChapterImagesTask.cs @@ -68,8 +68,6 @@ namespace Emby.Server.Implementations.ScheduledTasks }; } - public string Key => "RefreshChapterImages"; - /// <summary> /// Returns the task to be executed /// </summary> @@ -161,22 +159,18 @@ namespace Emby.Server.Implementations.ScheduledTasks } } - /// <summary> - /// Gets the name of the task - /// </summary> - /// <value>The name.</value> public string Name => "Chapter image extraction"; - /// <summary> - /// Gets the description. - /// </summary> - /// <value>The description.</value> public string Description => "Creates thumbnails for videos that have chapters."; - /// <summary> - /// Gets the category. - /// </summary> - /// <value>The category.</value> public string Category => "Library"; + + public string Key => "RefreshChapterImages"; + + public bool IsHidden => false; + + public bool IsEnabled => true; + + public bool IsLogged => true; } } diff --git a/Emby.Server.Implementations/ScheduledTasks/Tasks/DeleteCacheFileTask.cs b/Emby.Server.Implementations/ScheduledTasks/Tasks/DeleteCacheFileTask.cs index 52077b242..6ec83b5c0 100644 --- a/Emby.Server.Implementations/ScheduledTasks/Tasks/DeleteCacheFileTask.cs +++ b/Emby.Server.Implementations/ScheduledTasks/Tasks/DeleteCacheFileTask.cs @@ -158,31 +158,15 @@ namespace Emby.Server.Implementations.ScheduledTasks.Tasks } } - /// <summary> - /// Gets the name of the task - /// </summary> - /// <value>The name.</value> public string Name => "Cache file cleanup"; - public string Key => "DeleteCacheFiles"; - - /// <summary> - /// Gets the description. - /// </summary> - /// <value>The description.</value> public string Description => "Deletes cache files no longer needed by the system"; - /// <summary> - /// Gets the category. - /// </summary> - /// <value>The category.</value> public string Category => "Maintenance"; - /// <summary> - /// Gets a value indicating whether this instance is hidden. - /// </summary> - /// <value><c>true</c> if this instance is hidden; otherwise, <c>false</c>.</value> - public bool IsHidden => true; + public string Key => "DeleteCacheFiles"; + + public bool IsHidden => false; public bool IsEnabled => true; diff --git a/Emby.Server.Implementations/ScheduledTasks/Tasks/DeleteLogFileTask.cs b/Emby.Server.Implementations/ScheduledTasks/Tasks/DeleteLogFileTask.cs index a57fe4945..e468c301a 100644 --- a/Emby.Server.Implementations/ScheduledTasks/Tasks/DeleteLogFileTask.cs +++ b/Emby.Server.Implementations/ScheduledTasks/Tasks/DeleteLogFileTask.cs @@ -81,31 +81,15 @@ namespace Emby.Server.Implementations.ScheduledTasks.Tasks return Task.CompletedTask; } - public string Key => "CleanLogFiles"; - - /// <summary> - /// Gets the name of the task - /// </summary> - /// <value>The name.</value> public string Name => "Log file cleanup"; - /// <summary> - /// Gets the description. - /// </summary> - /// <value>The description.</value> public string Description => string.Format("Deletes log files that are more than {0} days old.", ConfigurationManager.CommonConfiguration.LogFileRetentionDays); - /// <summary> - /// Gets the category. - /// </summary> - /// <value>The category.</value> public string Category => "Maintenance"; - /// <summary> - /// Gets a value indicating whether this instance is hidden. - /// </summary> - /// <value><c>true</c> if this instance is hidden; otherwise, <c>false</c>.</value> - public bool IsHidden => true; + public string Key => "CleanLogFiles"; + + public bool IsHidden => false; public bool IsEnabled => true; diff --git a/Emby.Server.Implementations/ScheduledTasks/PeopleValidationTask.cs b/Emby.Server.Implementations/ScheduledTasks/Tasks/PeopleValidationTask.cs index 68031170f..d70799c47 100644 --- a/Emby.Server.Implementations/ScheduledTasks/PeopleValidationTask.cs +++ b/Emby.Server.Implementations/ScheduledTasks/Tasks/PeopleValidationTask.cs @@ -47,8 +47,6 @@ namespace Emby.Server.Implementations.ScheduledTasks }; } - public string Key => "RefreshPeople"; - /// <summary> /// Returns the task to be executed /// </summary> @@ -60,22 +58,18 @@ namespace Emby.Server.Implementations.ScheduledTasks return _libraryManager.ValidatePeople(cancellationToken, progress); } - /// <summary> - /// Gets the name of the task - /// </summary> - /// <value>The name.</value> public string Name => "Refresh people"; - /// <summary> - /// Gets the description. - /// </summary> - /// <value>The description.</value> public string Description => "Updates metadata for actors and directors in your media library."; - /// <summary> - /// Gets the category. - /// </summary> - /// <value>The category.</value> public string Category => "Library"; + + public string Key => "RefreshPeople"; + + public bool IsHidden => false; + + public bool IsEnabled => true; + + public bool IsLogged => true; } } diff --git a/Emby.Server.Implementations/ScheduledTasks/Tasks/PluginUpdateTask.cs b/Emby.Server.Implementations/ScheduledTasks/Tasks/PluginUpdateTask.cs new file mode 100644 index 000000000..c6431c311 --- /dev/null +++ b/Emby.Server.Implementations/ScheduledTasks/Tasks/PluginUpdateTask.cs @@ -0,0 +1,119 @@ +using MediaBrowser.Common; +using MediaBrowser.Common.Updates; +using MediaBrowser.Model.Net; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using MediaBrowser.Common.Progress; +using MediaBrowser.Model.Tasks; +using Microsoft.Extensions.Logging; + +namespace Emby.Server.Implementations.ScheduledTasks +{ + /// <summary> + /// Plugin Update Task + /// </summary> + public class PluginUpdateTask : IScheduledTask, IConfigurableScheduledTask + { + /// <summary> + /// The _logger + /// </summary> + private readonly ILogger _logger; + + private readonly IInstallationManager _installationManager; + + private readonly IApplicationHost _appHost; + + public PluginUpdateTask(ILogger logger, IInstallationManager installationManager, IApplicationHost appHost) + { + _logger = logger; + _installationManager = installationManager; + _appHost = appHost; + } + + /// <summary> + /// Creates the triggers that define when the task will run + /// </summary> + /// <returns>IEnumerable{BaseTaskTrigger}.</returns> + public IEnumerable<TaskTriggerInfo> GetDefaultTriggers() + { + return new[] { + + // At startup + new TaskTriggerInfo {Type = TaskTriggerInfo.TriggerStartup}, + + // Every so often + new TaskTriggerInfo { Type = TaskTriggerInfo.TriggerInterval, IntervalTicks = TimeSpan.FromHours(24).Ticks} + }; + } + + /// <summary> + /// Update installed plugins + /// </summary> + /// <param name="cancellationToken">The cancellation token.</param> + /// <param name="progress">The progress.</param> + /// <returns>Task.</returns> + public async Task Execute(CancellationToken cancellationToken, IProgress<double> progress) + { + progress.Report(0); + + var packagesToInstall = (await _installationManager.GetAvailablePluginUpdates(typeof(PluginUpdateTask).Assembly.GetName().Version, true, cancellationToken).ConfigureAwait(false)).ToList(); + + progress.Report(10); + + var numComplete = 0; + + foreach (var package in packagesToInstall) + { + cancellationToken.ThrowIfCancellationRequested(); + + try + { + await _installationManager.InstallPackage(package, true, new SimpleProgress<double>(), cancellationToken).ConfigureAwait(false); + } + catch (OperationCanceledException) + { + // InstallPackage has it's own inner cancellation token, so only throw this if it's ours + if (cancellationToken.IsCancellationRequested) + { + throw; + } + } + catch (HttpException ex) + { + _logger.LogError(ex, "Error downloading {0}", package.name); + } + catch (IOException ex) + { + _logger.LogError(ex, "Error updating {0}", package.name); + } + + // Update progress + lock (progress) + { + numComplete++; + progress.Report(90.0 * numComplete / packagesToInstall.Count + 10); + } + } + + progress.Report(100); + } + + public string Name => "Check for plugin updates"; + + public string Description => "Downloads and installs updates for plugins that are configured to update automatically."; + + public string Category => "Application"; + + public string Key => "PluginUpdates"; + + public bool IsHidden => false; + + public bool IsEnabled => true; + + public bool IsLogged => true; + } +} diff --git a/Emby.Server.Implementations/ScheduledTasks/RefreshMediaLibraryTask.cs b/Emby.Server.Implementations/ScheduledTasks/Tasks/RefreshMediaLibraryTask.cs index f6fa64d13..1a3d85ad7 100644 --- a/Emby.Server.Implementations/ScheduledTasks/RefreshMediaLibraryTask.cs +++ b/Emby.Server.Implementations/ScheduledTasks/Tasks/RefreshMediaLibraryTask.cs @@ -58,24 +58,18 @@ namespace Emby.Server.Implementations.ScheduledTasks return ((LibraryManager)_libraryManager).ValidateMediaLibraryInternal(progress, cancellationToken); } - /// <summary> - /// Gets the name. - /// </summary> - /// <value>The name.</value> public string Name => "Scan media library"; - /// <summary> - /// Gets the description. - /// </summary> - /// <value>The description.</value> public string Description => "Scans your media library and refreshes metatata based on configuration."; - /// <summary> - /// Gets the category. - /// </summary> - /// <value>The category.</value> public string Category => "Library"; public string Key => "RefreshLibrary"; + + public bool IsHidden => false; + + public bool IsEnabled => true; + + public bool IsLogged => true; } } diff --git a/Emby.Server.Implementations/ScheduledTasks/DailyTrigger.cs b/Emby.Server.Implementations/ScheduledTasks/Triggers/DailyTrigger.cs index 98685cebe..98685cebe 100644 --- a/Emby.Server.Implementations/ScheduledTasks/DailyTrigger.cs +++ b/Emby.Server.Implementations/ScheduledTasks/Triggers/DailyTrigger.cs diff --git a/Emby.Server.Implementations/ScheduledTasks/IntervalTrigger.cs b/Emby.Server.Implementations/ScheduledTasks/Triggers/IntervalTrigger.cs index 3a34da3af..3a34da3af 100644 --- a/Emby.Server.Implementations/ScheduledTasks/IntervalTrigger.cs +++ b/Emby.Server.Implementations/ScheduledTasks/Triggers/IntervalTrigger.cs diff --git a/Emby.Server.Implementations/ScheduledTasks/StartupTrigger.cs b/Emby.Server.Implementations/ScheduledTasks/Triggers/StartupTrigger.cs index 08ff4f55f..08ff4f55f 100644 --- a/Emby.Server.Implementations/ScheduledTasks/StartupTrigger.cs +++ b/Emby.Server.Implementations/ScheduledTasks/Triggers/StartupTrigger.cs diff --git a/Emby.Server.Implementations/ScheduledTasks/WeeklyTrigger.cs b/Emby.Server.Implementations/ScheduledTasks/Triggers/WeeklyTrigger.cs index 2a6a7b13c..2a6a7b13c 100644 --- a/Emby.Server.Implementations/ScheduledTasks/WeeklyTrigger.cs +++ b/Emby.Server.Implementations/ScheduledTasks/Triggers/WeeklyTrigger.cs diff --git a/Emby.Server.Implementations/ServerApplicationPaths.cs b/Emby.Server.Implementations/ServerApplicationPaths.cs index edea10a07..36975df50 100644 --- a/Emby.Server.Implementations/ServerApplicationPaths.cs +++ b/Emby.Server.Implementations/ServerApplicationPaths.cs @@ -18,8 +18,13 @@ namespace Emby.Server.Implementations string appFolderPath, string applicationResourcesPath, string logDirectoryPath = null, - string configurationDirectoryPath = null) - : base(programDataPath, appFolderPath, logDirectoryPath, configurationDirectoryPath) + string configurationDirectoryPath = null, + string cacheDirectoryPath = null) + : base(programDataPath, + appFolderPath, + logDirectoryPath, + configurationDirectoryPath, + cacheDirectoryPath) { ApplicationResourcesPath = applicationResourcesPath; } @@ -136,12 +141,6 @@ namespace Emby.Server.Implementations return path; } - /// <summary> - /// Gets the game genre path. - /// </summary> - /// <value>The game genre path.</value> - public string GameGenrePath => Path.Combine(InternalMetadataPath, "GameGenre"); - private string _internalMetadataPath; public string InternalMetadataPath { diff --git a/Emby.Server.Implementations/Services/RequestHelper.cs b/Emby.Server.Implementations/Services/RequestHelper.cs index 24e9cbfa4..2563cac99 100644 --- a/Emby.Server.Implementations/Services/RequestHelper.cs +++ b/Emby.Server.Implementations/Services/RequestHelper.cs @@ -45,7 +45,7 @@ namespace Emby.Server.Implementations.Services { return contentType == null ? null - : contentType.Split(';')[0].ToLower().Trim(); + : contentType.Split(';')[0].ToLowerInvariant().Trim(); } } diff --git a/Emby.Server.Implementations/Services/ServiceExec.cs b/Emby.Server.Implementations/Services/ServiceExec.cs index 45c918fa1..aa67a3601 100644 --- a/Emby.Server.Implementations/Services/ServiceExec.cs +++ b/Emby.Server.Implementations/Services/ServiceExec.cs @@ -98,7 +98,7 @@ namespace Emby.Server.Implementations.Services return Task.FromResult(response); } - var expectedMethodName = actionName.Substring(0, 1) + actionName.Substring(1).ToLower(); + var expectedMethodName = actionName.Substring(0, 1) + actionName.Substring(1).ToLowerInvariant(); throw new NotImplementedException(string.Format("Could not find method named {1}({0}) or Any({0}) on Service {2}", requestDto.GetType().GetMethodName(), expectedMethodName, serviceType.GetMethodName())); } diff --git a/Emby.Server.Implementations/Services/ServiceMethod.cs b/Emby.Server.Implementations/Services/ServiceMethod.cs index 7add72815..5018bf4a2 100644 --- a/Emby.Server.Implementations/Services/ServiceMethod.cs +++ b/Emby.Server.Implementations/Services/ServiceMethod.cs @@ -11,7 +11,7 @@ namespace Emby.Server.Implementations.Services public static string Key(Type serviceType, string method, string requestDtoName) { - return serviceType.FullName + " " + method.ToUpper() + " " + requestDtoName; + return serviceType.FullName + " " + method.ToUpperInvariant() + " " + requestDtoName; } } } diff --git a/Emby.Server.Implementations/Services/ServicePath.cs b/Emby.Server.Implementations/Services/ServicePath.cs index 7e1993b71..f575baca3 100644 --- a/Emby.Server.Implementations/Services/ServicePath.cs +++ b/Emby.Server.Implementations/Services/ServicePath.cs @@ -60,7 +60,7 @@ namespace Emby.Server.Implementations.Services public static string[] GetPathPartsForMatching(string pathInfo) { - return pathInfo.ToLower().Split(new[] { PathSeperatorChar }, StringSplitOptions.RemoveEmptyEntries); + return pathInfo.ToLowerInvariant().Split(new[] { PathSeperatorChar }, StringSplitOptions.RemoveEmptyEntries); } public static List<string> GetFirstMatchHashKeys(string[] pathPartsForMatching) @@ -104,7 +104,7 @@ namespace Emby.Server.Implementations.Services this.Description = description; this.restPath = path; - this.Verbs = string.IsNullOrWhiteSpace(verbs) ? ServiceExecExtensions.AllVerbs : verbs.ToUpper().Split(new[] { ' ', ',' }, StringSplitOptions.RemoveEmptyEntries); + this.Verbs = string.IsNullOrWhiteSpace(verbs) ? ServiceExecExtensions.AllVerbs : verbs.ToUpperInvariant().Split(new[] { ' ', ',' }, StringSplitOptions.RemoveEmptyEntries); var componentsList = new List<string>(); @@ -154,7 +154,7 @@ namespace Emby.Server.Implementations.Services } else { - this.literalsToMatch[i] = component.ToLower(); + this.literalsToMatch[i] = component.ToLowerInvariant(); if (firstLiteralMatch == null) { @@ -189,7 +189,7 @@ namespace Emby.Server.Implementations.Services foreach (var propertyInfo in GetSerializableProperties(RequestType)) { var propertyName = propertyInfo.Name; - propertyNamesMap.Add(propertyName.ToLower(), propertyName); + propertyNamesMap.Add(propertyName.ToLowerInvariant(), propertyName); } } @@ -483,7 +483,7 @@ namespace Emby.Server.Implementations.Services continue; } - if (!this.propertyNamesMap.TryGetValue(variableName.ToLower(), out var propertyNameOnRequest)) + if (!this.propertyNamesMap.TryGetValue(variableName.ToLowerInvariant(), out var propertyNameOnRequest)) { if (string.Equals("ignore", variableName, StringComparison.OrdinalIgnoreCase)) { diff --git a/Emby.Server.Implementations/Services/SwaggerService.cs b/Emby.Server.Implementations/Services/SwaggerService.cs index 9bceeabec..3e6970eef 100644 --- a/Emby.Server.Implementations/Services/SwaggerService.cs +++ b/Emby.Server.Implementations/Services/SwaggerService.cs @@ -216,40 +216,28 @@ namespace Emby.Server.Implementations.Services { var responses = new Dictionary<string, SwaggerResponse> { + { "200", new SwaggerResponse { description = "OK" } } }; - responses["200"] = new SwaggerResponse + var apiKeySecurity = new Dictionary<string, string[]> { - description = "OK" + { "api_key", Array.Empty<string>() } }; - var security = new List<Dictionary<string, string[]>>(); - - var apiKeySecurity = new Dictionary<string, string[]>(); - apiKeySecurity["api_key"] = Array.Empty<string>(); - - security.Add(apiKeySecurity); - - result[verb.ToLower()] = new SwaggerMethod + result[verb.ToLowerInvariant()] = new SwaggerMethod { summary = info.Summary, description = info.Description, - produces = new[] - { - "application/json" - }, - consumes = new[] - { - "application/json" - }, + produces = new[] { "application/json" }, + consumes = new[] { "application/json" }, operationId = info.RequestType.Name, tags = Array.Empty<string>(), - parameters = new SwaggerParam[] { }, + parameters = Array.Empty<SwaggerParam>(), responses = responses, - security = security.ToArray() + security = new [] { apiKeySecurity } }; } diff --git a/Emby.Server.Implementations/Sorting/GameSystemComparer.cs b/Emby.Server.Implementations/Sorting/GameSystemComparer.cs deleted file mode 100644 index 2a04bae3c..000000000 --- a/Emby.Server.Implementations/Sorting/GameSystemComparer.cs +++ /dev/null @@ -1,51 +0,0 @@ -using System; -using MediaBrowser.Controller.Entities; -using MediaBrowser.Controller.Sorting; -using MediaBrowser.Model.Querying; - -namespace Emby.Server.Implementations.Sorting -{ - public class GameSystemComparer : IBaseItemComparer - { - /// <summary> - /// Compares the specified x. - /// </summary> - /// <param name="x">The x.</param> - /// <param name="y">The y.</param> - /// <returns>System.Int32.</returns> - public int Compare(BaseItem x, BaseItem y) - { - return string.Compare(GetValue(x), GetValue(y), StringComparison.CurrentCultureIgnoreCase); - } - - /// <summary> - /// Gets the value. - /// </summary> - /// <param name="x">The x.</param> - /// <returns>System.String.</returns> - private static string GetValue(BaseItem x) - { - var game = x as Game; - - if (game != null) - { - return game.GameSystem; - } - - var system = x as GameSystem; - - if (system != null) - { - return system.GameSystemName; - } - - return string.Empty; - } - - /// <summary> - /// Gets the name. - /// </summary> - /// <value>The name.</value> - public string Name => ItemSortBy.GameSystem; - } -} diff --git a/Emby.Server.Implementations/Sorting/PlayersComparer.cs b/Emby.Server.Implementations/Sorting/PlayersComparer.cs deleted file mode 100644 index e3652f36b..000000000 --- a/Emby.Server.Implementations/Sorting/PlayersComparer.cs +++ /dev/null @@ -1,43 +0,0 @@ -using MediaBrowser.Controller.Entities; -using MediaBrowser.Controller.Sorting; -using MediaBrowser.Model.Querying; - -namespace Emby.Server.Implementations.Sorting -{ - public class PlayersComparer : IBaseItemComparer - { - /// <summary> - /// Compares the specified x. - /// </summary> - /// <param name="x">The x.</param> - /// <param name="y">The y.</param> - /// <returns>System.Int32.</returns> - public int Compare(BaseItem x, BaseItem y) - { - return GetValue(x).CompareTo(GetValue(y)); - } - - /// <summary> - /// Gets the value. - /// </summary> - /// <param name="x">The x.</param> - /// <returns>System.String.</returns> - private static int GetValue(BaseItem x) - { - var game = x as Game; - - if (game != null) - { - return game.PlayersSupported ?? 0; - } - - return 0; - } - - /// <summary> - /// Gets the name. - /// </summary> - /// <value>The name.</value> - public string Name => ItemSortBy.Players; - } -} diff --git a/Emby.Server.Implementations/StartupOptions.cs b/Emby.Server.Implementations/StartupOptions.cs deleted file mode 100644 index 221263634..000000000 --- a/Emby.Server.Implementations/StartupOptions.cs +++ /dev/null @@ -1,30 +0,0 @@ -using System; -using System.Linq; - -namespace Emby.Server.Implementations -{ - public class StartupOptions - { - private readonly string[] _options; - - public StartupOptions(string[] commandLineArgs) - { - _options = commandLineArgs; - } - - public bool ContainsOption(string option) - => _options.Contains(option, StringComparer.OrdinalIgnoreCase); - - public string GetOption(string name) - { - int index = Array.IndexOf(_options, name); - - if (index == -1) - { - return null; - } - - return _options.ElementAtOrDefault(index + 1); - } - } -} diff --git a/Emby.Server.Implementations/Updates/InstallationManager.cs b/Emby.Server.Implementations/Updates/InstallationManager.cs index 552155635..dc7f57f27 100644 --- a/Emby.Server.Implementations/Updates/InstallationManager.cs +++ b/Emby.Server.Implementations/Updates/InstallationManager.cs @@ -169,10 +169,8 @@ namespace Emby.Server.Implementations.Updates string packageType = null, Version applicationVersion = null) { - // TODO cvium: when plugins get back this would need to be fixed - // var packages = await GetAvailablePackagesWithoutRegistrationInfo(cancellationToken).ConfigureAwait(false); - - return new List<PackageInfo>(); //FilterPackages(packages, packageType, applicationVersion); + var packages = await GetAvailablePackagesWithoutRegistrationInfo(cancellationToken).ConfigureAwait(false); + return FilterPackages(packages, packageType, applicationVersion); } /// <summary> @@ -184,12 +182,10 @@ namespace Emby.Server.Implementations.Updates { using (var response = await _httpClient.SendAsync(new HttpRequestOptions { - Url = "https://www.mb3admin.local/admin/service/EmbyPackages.json", + Url = "https://repo.jellyfin.org/releases/plugin/manifest.json", CancellationToken = cancellationToken, Progress = new SimpleProgress<double>(), - CacheLength = GetCacheLength(), - CacheMode = CacheMode.Unconditional - + CacheLength = GetCacheLength() }, "GET").ConfigureAwait(false)) { using (var stream = response.Content) diff --git a/Emby.Server.Implementations/UserViews/CollectionFolderImageProvider.cs b/Emby.Server.Implementations/UserViews/CollectionFolderImageProvider.cs index 8788cfc26..ce6c2cd87 100644 --- a/Emby.Server.Implementations/UserViews/CollectionFolderImageProvider.cs +++ b/Emby.Server.Implementations/UserViews/CollectionFolderImageProvider.cs @@ -43,10 +43,6 @@ namespace Emby.Server.Implementations.UserViews { includeItemTypes = new string[] { "Book", "AudioBook" }; } - else if (string.Equals(viewType, CollectionType.Games)) - { - includeItemTypes = new string[] { "Game" }; - } else if (string.Equals(viewType, CollectionType.BoxSets)) { includeItemTypes = new string[] { "BoxSet" }; diff --git a/Emby.Server.Implementations/UserViews/DynamicImageProvider.cs b/Emby.Server.Implementations/UserViews/DynamicImageProvider.cs index 937db3f23..4ec68e550 100644 --- a/Emby.Server.Implementations/UserViews/DynamicImageProvider.cs +++ b/Emby.Server.Implementations/UserViews/DynamicImageProvider.cs @@ -12,7 +12,6 @@ using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Entities; -using MediaBrowser.Model.Extensions; using MediaBrowser.Model.IO; namespace Emby.Server.Implementations.UserViews @@ -83,7 +82,8 @@ namespace Emby.Server.Implementations.UserViews return i; - }).DistinctBy(i => i.Id); + }).GroupBy(x => x.Id) + .Select(x => x.First()); if (isUsingCollectionStrip) { diff --git a/Jellyfin.Drawing.Skia/StripCollageBuilder.cs b/Jellyfin.Drawing.Skia/StripCollageBuilder.cs index 92115047c..dfdf39871 100644 --- a/Jellyfin.Drawing.Skia/StripCollageBuilder.cs +++ b/Jellyfin.Drawing.Skia/StripCollageBuilder.cs @@ -25,7 +25,7 @@ namespace Jellyfin.Drawing.Skia throw new ArgumentNullException(nameof(outputPath)); } - var ext = Path.GetExtension(outputPath).ToLower(); + var ext = Path.GetExtension(outputPath).ToLowerInvariant(); if (ext == ".jpg" || ext == ".jpeg") return SKEncodedImageFormat.Jpeg; diff --git a/Jellyfin.Server/CoreAppHost.cs b/Jellyfin.Server/CoreAppHost.cs index b580f45ca..5182ab4d7 100644 --- a/Jellyfin.Server/CoreAppHost.cs +++ b/Jellyfin.Server/CoreAppHost.cs @@ -16,7 +16,7 @@ namespace Jellyfin.Server { } - public override bool CanSelfRestart => StartupOptions.ContainsOption("-restartpath"); + public override bool CanSelfRestart => StartupOptions.RestartPath != null; protected override void RestartInternal() => Program.Restart(); diff --git a/Jellyfin.Server/Jellyfin.Server.csproj b/Jellyfin.Server/Jellyfin.Server.csproj index 5a4bf5149..1f72de86d 100644 --- a/Jellyfin.Server/Jellyfin.Server.csproj +++ b/Jellyfin.Server/Jellyfin.Server.csproj @@ -32,6 +32,7 @@ </PropertyGroup> <ItemGroup> + <PackageReference Include="CommandLineParser" Version="2.4.3" /> <PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="2.2.0" /> <PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="2.2.0" /> <PackageReference Include="Serilog.AspNetCore" Version="2.1.1" /> diff --git a/Jellyfin.Server/Program.cs b/Jellyfin.Server/Program.cs index 513d9674e..3bd063294 100644 --- a/Jellyfin.Server/Program.cs +++ b/Jellyfin.Server/Program.cs @@ -6,8 +6,10 @@ using System.Net; using System.Net.Security; using System.Reflection; using System.Runtime.InteropServices; +using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; +using CommandLine; using Emby.Drawing; using Emby.Server.Implementations; using Emby.Server.Implementations.EnvironmentInfo; @@ -35,19 +37,32 @@ namespace Jellyfin.Server public static async Task Main(string[] args) { - StartupOptions options = new StartupOptions(args); - Version version = Assembly.GetEntryAssembly().GetName().Version; - - if (options.ContainsOption("-v") || options.ContainsOption("--version")) + // For backwards compatibility. + // Modify any input arguments now which start with single-hyphen to POSIX standard + // double-hyphen to allow parsing by CommandLineParser package. + const string pattern = @"^(-[^-\s]{2})"; // Match -xx, not -x, not --xx, not xx + const string substitution = @"-$1"; // Prepend with additional single-hyphen + var regex = new Regex(pattern); + + for (var i = 0; i < args.Length; i++) { - Console.WriteLine(version.ToString()); + args[i] = regex.Replace(args[i], substitution); } + // Parse the command line arguments and either start the app or exit indicating error + await Parser.Default.ParseArguments<StartupOptions>(args) + .MapResult( + options => StartApp(options), + errs => Task.FromResult(0)).ConfigureAwait(false); + } + + private static async Task StartApp(StartupOptions options) + { ServerApplicationPaths appPaths = CreateApplicationPaths(options); // $JELLYFIN_LOG_DIR needs to be set for the logger configuration manager Environment.SetEnvironmentVariable("JELLYFIN_LOG_DIR", appPaths.LogDirectoryPath); - await createLogger(appPaths); + await CreateLogger(appPaths); _logger = _loggerFactory.CreateLogger("Main"); AppDomain.CurrentDomain.UnhandledException += (sender, e) @@ -78,9 +93,9 @@ namespace Jellyfin.Server Shutdown(); }; - _logger.LogInformation("Jellyfin version: {Version}", version); + _logger.LogInformation("Jellyfin version: {Version}", Assembly.GetEntryAssembly().GetName().Version); - EnvironmentInfo environmentInfo = new EnvironmentInfo(getOperatingSystem()); + EnvironmentInfo environmentInfo = new EnvironmentInfo(GetOperatingSystem()); ApplicationHost.LogEnvironmentInfo(_logger, appPaths, environmentInfo); SQLitePCL.Batteries_V2.Init(); @@ -133,9 +148,9 @@ namespace Jellyfin.Server string programDataPath = Environment.GetEnvironmentVariable("JELLYFIN_DATA_PATH"); if (string.IsNullOrEmpty(programDataPath)) { - if (options.ContainsOption("-programdata")) + if (options.DataDir != null) { - programDataPath = options.GetOption("-programdata"); + programDataPath = options.DataDir; } else { @@ -171,9 +186,9 @@ namespace Jellyfin.Server string configDir = Environment.GetEnvironmentVariable("JELLYFIN_CONFIG_DIR"); if (string.IsNullOrEmpty(configDir)) { - if (options.ContainsOption("-configdir")) + if (options.ConfigDir != null) { - configDir = options.GetOption("-configdir"); + configDir = options.ConfigDir; } else { @@ -187,12 +202,37 @@ namespace Jellyfin.Server Directory.CreateDirectory(configDir); } + string cacheDir = Environment.GetEnvironmentVariable("JELLYFIN_CACHE_DIR"); + if (string.IsNullOrEmpty(cacheDir)) + { + if (options.CacheDir != null) + { + cacheDir = options.CacheDir; + } + else if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + // $XDG_CACHE_HOME defines the base directory relative to which user specific non-essential data files should be stored. + cacheDir = Environment.GetEnvironmentVariable("XDG_CACHE_HOME"); + // If $XDG_CACHE_HOME is either not set or empty, $HOME/.cache should be used. + if (string.IsNullOrEmpty(cacheDir)) + { + cacheDir = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".cache"); + } + cacheDir = Path.Combine(cacheDir, "jellyfin"); + } + } + + if (cacheDir != null) + { + Directory.CreateDirectory(cacheDir); + } + string logDir = Environment.GetEnvironmentVariable("JELLYFIN_LOG_DIR"); if (string.IsNullOrEmpty(logDir)) { - if (options.ContainsOption("-logdir")) + if (options.LogDir != null) { - logDir = options.GetOption("-logdir"); + logDir = options.LogDir; } else { @@ -208,10 +248,10 @@ namespace Jellyfin.Server string appPath = AppContext.BaseDirectory; - return new ServerApplicationPaths(programDataPath, appPath, appPath, logDir, configDir); + return new ServerApplicationPaths(programDataPath, appPath, appPath, logDir, configDir, cacheDir); } - private static async Task createLogger(IApplicationPaths appPaths) + private static async Task CreateLogger(IApplicationPaths appPaths) { try { @@ -271,7 +311,7 @@ namespace Jellyfin.Server return new NullImageEncoder(); } - private static MediaBrowser.Model.System.OperatingSystem getOperatingSystem() + private static MediaBrowser.Model.System.OperatingSystem GetOperatingSystem() { switch (Environment.OSVersion.Platform) { @@ -315,11 +355,11 @@ namespace Jellyfin.Server Shutdown(); } - private static void StartNewInstance(StartupOptions startupOptions) + private static void StartNewInstance(StartupOptions options) { _logger.LogInformation("Starting new instance"); - string module = startupOptions.GetOption("-restartpath"); + string module = options.RestartPath; if (string.IsNullOrWhiteSpace(module)) { @@ -328,9 +368,9 @@ namespace Jellyfin.Server string commandLineArgsString; - if (startupOptions.ContainsOption("-restartargs")) + if (options.RestartArgs != null) { - commandLineArgsString = startupOptions.GetOption("-restartargs") ?? string.Empty; + commandLineArgsString = options.RestartArgs ?? string.Empty; } else { diff --git a/Jellyfin.Server/SocketSharp/RequestMono.cs b/Jellyfin.Server/SocketSharp/RequestMono.cs index 017690062..f09197fb3 100644 --- a/Jellyfin.Server/SocketSharp/RequestMono.cs +++ b/Jellyfin.Server/SocketSharp/RequestMono.cs @@ -360,13 +360,13 @@ namespace Jellyfin.SocketSharp int len = buffer.Length; if (dest_offset > len) { - throw new ArgumentException("destination offset is beyond array size"); + throw new ArgumentException("destination offset is beyond array size", nameof(dest_offset)); } // reordered to avoid possible integer overflow if (dest_offset > len - count) { - throw new ArgumentException("Reading would overrun buffer"); + throw new ArgumentException("Reading would overrun buffer", nameof(count)); } if (count > end - position) @@ -528,7 +528,7 @@ namespace Jellyfin.SocketSharp } } - class HttpMultipart + private class HttpMultipart { public class Element @@ -543,19 +543,19 @@ namespace Jellyfin.SocketSharp public override string ToString() { return "ContentType " + ContentType + ", Name " + Name + ", Filename " + Filename + ", Start " + - Start.ToString() + ", Length " + Length.ToString(); + Start.ToString(CultureInfo.CurrentCulture) + ", Length " + Length.ToString(CultureInfo.CurrentCulture); } } - Stream data; - string boundary; - byte[] boundary_bytes; - byte[] buffer; - bool at_eof; - Encoding encoding; - StringBuilder sb; + private Stream data; + private string boundary; + private byte[] boundary_bytes; + private byte[] buffer; + private bool at_eof; + private Encoding encoding; + private StringBuilder sb; - const byte LF = (byte)'\n', CR = (byte)'\r'; + private const byte LF = (byte)'\n', CR = (byte)'\r'; // See RFC 2046 // In the case of multipart entities, in which one or more different @@ -610,7 +610,6 @@ namespace Jellyfin.SocketSharp } return sb.ToString(); - } private static string GetContentDispositionAttribute(string l, string name) diff --git a/Jellyfin.Server/SocketSharp/WebSocketSharpRequest.cs b/Jellyfin.Server/SocketSharp/WebSocketSharpRequest.cs index 97550e686..2e8dd9185 100644 --- a/Jellyfin.Server/SocketSharp/WebSocketSharpRequest.cs +++ b/Jellyfin.Server/SocketSharp/WebSocketSharpRequest.cs @@ -29,12 +29,24 @@ namespace Jellyfin.SocketSharp private static string GetHandlerPathIfAny(string listenerUrl) { - if (listenerUrl == null) return null; + if (listenerUrl == null) + { + return null; + } + var pos = listenerUrl.IndexOf("://", StringComparison.OrdinalIgnoreCase); - if (pos == -1) return null; + if (pos == -1) + { + return null; + } + var startHostUrl = listenerUrl.Substring(pos + "://".Length); var endPos = startHostUrl.IndexOf('/'); - if (endPos == -1) return null; + if (endPos == -1) + { + return null; + } + var endHostUrl = startHostUrl.Substring(endPos + 1); return string.IsNullOrEmpty(endHostUrl) ? null : endHostUrl.TrimEnd('/'); } @@ -210,9 +222,13 @@ namespace Jellyfin.SocketSharp if (acceptsAnything) { if (hasDefaultContentType) + { return defaultContentType; - if (serverDefaultContentType != null) + } + else if (serverDefaultContentType != null) + { return serverDefaultContentType; + } } } @@ -229,11 +245,16 @@ namespace Jellyfin.SocketSharp public static bool HasAnyOfContentTypes(IRequest request, params string[] contentTypes) { - if (contentTypes == null || request.ContentType == null) return false; + if (contentTypes == null || request.ContentType == null) + { + return false; + } + foreach (var contentType in contentTypes) { if (IsContentType(request, contentType)) return true; } + return false; } @@ -264,12 +285,12 @@ namespace Jellyfin.SocketSharp } } - format = LeftPart(format, '.').ToLower(); + format = LeftPart(format, '.').ToLowerInvariant(); if (format.Contains("json", StringComparison.OrdinalIgnoreCase)) { return "application/json"; } - if (format.Contains("xml", StringComparison.OrdinalIgnoreCase)) + else if (format.Contains("xml", StringComparison.OrdinalIgnoreCase)) { return "application/xml"; } @@ -283,10 +304,9 @@ namespace Jellyfin.SocketSharp { return null; } + var pos = strVal.IndexOf(needle); - return pos == -1 - ? strVal - : strVal.Substring(0, pos); + return pos == -1 ? strVal : strVal.Substring(0, pos); } public static string HandlerFactoryPath; @@ -433,6 +453,7 @@ namespace Jellyfin.SocketSharp { return null; } + try { return Encoding.GetEncoding(param); diff --git a/Jellyfin.Server/StartupOptions.cs b/Jellyfin.Server/StartupOptions.cs new file mode 100644 index 000000000..5d3f7b171 --- /dev/null +++ b/Jellyfin.Server/StartupOptions.cs @@ -0,0 +1,44 @@ +using CommandLine; +using Emby.Server.Implementations; + +namespace Jellyfin.Server +{ + /// <summary> + /// Class used by CommandLine package when parsing the command line arguments. + /// </summary> + public class StartupOptions : IStartupOptions + { + [Option('d', "datadir", Required = false, HelpText = "Path to use for the data folder (database files, etc.).")] + public string DataDir { get; set; } + + [Option('C', "cachedir", Required = false, HelpText = "Path to use for caching.")] + public string CacheDir { get; set; } + + [Option('c', "configdir", Required = false, HelpText = "Path to use for configuration data (user settings and pictures).")] + public string ConfigDir { get; set; } + + [Option('l', "logdir", Required = false, HelpText = "Path to use for writing log files.")] + public string LogDir { get; set; } + + [Option("ffmpeg", Required = false, HelpText = "Path to external FFmpeg executable to use in place of default found in PATH. Must be specified along with --ffprobe.")] + public string FFmpegPath { get; set; } + + [Option("ffprobe", Required = false, HelpText = "Path to external FFprobe executable to use in place of default found in PATH. Must be specified along with --ffmpeg.")] + public string FFprobePath { get; set; } + + [Option("service", Required = false, HelpText = "Run as headless service.")] + public bool IsService { get; set; } + + [Option("noautorunwebapp", Required = false, HelpText = "Run headless if startup wizard is complete.")] + public bool NoAutoRunWebApp { get; set; } + + [Option("package-name", Required = false, HelpText = "Used when packaging Jellyfin (example, synology).")] + public string PackageName { get; set; } + + [Option("restartpath", Required = false, HelpText = "Path to restart script.")] + public string RestartPath { get; set; } + + [Option("restartargs", Required = false, HelpText = "Arguments for restart script.")] + public string RestartArgs { get; set; } + } +} diff --git a/MediaBrowser.Api/ApiEntryPoint.cs b/MediaBrowser.Api/ApiEntryPoint.cs index 763535129..a212d3f3a 100644 --- a/MediaBrowser.Api/ApiEntryPoint.cs +++ b/MediaBrowser.Api/ApiEntryPoint.cs @@ -462,7 +462,7 @@ namespace MediaBrowser.Api Logger.LogInformation("Transcoding kill timer stopped for JobId {0} PlaySessionId {1}. Killing transcoding", job.Id, job.PlaySessionId); - KillTranscodingJob(job, true, path => true); + KillTranscodingJob(job, true, path => true).GetAwaiter().GetResult(); } /// <summary> @@ -472,9 +472,9 @@ namespace MediaBrowser.Api /// <param name="playSessionId">The play session identifier.</param> /// <param name="deleteFiles">The delete files.</param> /// <returns>Task.</returns> - internal void KillTranscodingJobs(string deviceId, string playSessionId, Func<string, bool> deleteFiles) + internal Task KillTranscodingJobs(string deviceId, string playSessionId, Func<string, bool> deleteFiles) { - KillTranscodingJobs(j => + return KillTranscodingJobs(j => { if (!string.IsNullOrWhiteSpace(playSessionId)) { @@ -492,7 +492,7 @@ namespace MediaBrowser.Api /// <param name="killJob">The kill job.</param> /// <param name="deleteFiles">The delete files.</param> /// <returns>Task.</returns> - private void KillTranscodingJobs(Func<TranscodingJob, bool> killJob, Func<string, bool> deleteFiles) + private Task KillTranscodingJobs(Func<TranscodingJob, bool> killJob, Func<string, bool> deleteFiles) { var jobs = new List<TranscodingJob>(); @@ -505,13 +505,18 @@ namespace MediaBrowser.Api if (jobs.Count == 0) { - return; + return Task.CompletedTask; } - foreach (var job in jobs) + IEnumerable<Task> GetKillJobs() { - KillTranscodingJob(job, false, deleteFiles); + foreach (var job in jobs) + { + yield return KillTranscodingJob(job, false, deleteFiles); + } } + + return Task.WhenAll(GetKillJobs()); } /// <summary> @@ -520,7 +525,7 @@ namespace MediaBrowser.Api /// <param name="job">The job.</param> /// <param name="closeLiveStream">if set to <c>true</c> [close live stream].</param> /// <param name="delete">The delete.</param> - private async void KillTranscodingJob(TranscodingJob job, bool closeLiveStream, Func<string, bool> delete) + private async Task KillTranscodingJob(TranscodingJob job, bool closeLiveStream, Func<string, bool> delete) { job.DisposeKillTimer(); @@ -577,7 +582,7 @@ namespace MediaBrowser.Api if (delete(job.Path)) { - DeletePartialStreamFiles(job.Path, job.Type, 0, 1500); + await DeletePartialStreamFiles(job.Path, job.Type, 0, 1500).ConfigureAwait(false); } if (closeLiveStream && !string.IsNullOrWhiteSpace(job.LiveStreamId)) @@ -588,12 +593,12 @@ namespace MediaBrowser.Api } catch (Exception ex) { - Logger.LogError(ex, "Error closing live stream for {path}", job.Path); + Logger.LogError(ex, "Error closing live stream for {Path}", job.Path); } } } - private async void DeletePartialStreamFiles(string path, TranscodingJobType jobType, int retryCount, int delayMs) + private async Task DeletePartialStreamFiles(string path, TranscodingJobType jobType, int retryCount, int delayMs) { if (retryCount >= 10) { @@ -623,7 +628,7 @@ namespace MediaBrowser.Api { Logger.LogError(ex, "Error deleting partial stream file(s) {path}", path); - DeletePartialStreamFiles(path, jobType, retryCount + 1, 500); + await DeletePartialStreamFiles(path, jobType, retryCount + 1, 500).ConfigureAwait(false); } catch (Exception ex) { @@ -650,8 +655,7 @@ namespace MediaBrowser.Api var name = Path.GetFileNameWithoutExtension(outputFilePath); var filesToDelete = _fileSystem.GetFilePaths(directory) - .Where(f => f.IndexOf(name, StringComparison.OrdinalIgnoreCase) != -1) - .ToList(); + .Where(f => f.IndexOf(name, StringComparison.OrdinalIgnoreCase) != -1); Exception e = null; diff --git a/MediaBrowser.Api/BaseApiService.cs b/MediaBrowser.Api/BaseApiService.cs index 8decea5a2..4a484b718 100644 --- a/MediaBrowser.Api/BaseApiService.cs +++ b/MediaBrowser.Api/BaseApiService.cs @@ -228,21 +228,6 @@ namespace MediaBrowser.Api return libraryManager.GetMusicGenre(name); } - protected GameGenre GetGameGenre(string name, ILibraryManager libraryManager, DtoOptions dtoOptions) - { - if (name.IndexOf(BaseItem.SlugChar) != -1) - { - var result = GetItemFromSlugName<GameGenre>(libraryManager, name, dtoOptions); - - if (result != null) - { - return result; - } - } - - return libraryManager.GetGameGenre(name); - } - protected Person GetPerson(string name, ILibraryManager libraryManager, DtoOptions dtoOptions) { if (name.IndexOf(BaseItem.SlugChar) != -1) @@ -349,10 +334,6 @@ namespace MediaBrowser.Api { item = GetMusicGenre(name, libraryManager, dtoOptions); } - else if (type.IndexOf("GameGenre", StringComparison.OrdinalIgnoreCase) == 0) - { - item = GetGameGenre(name, libraryManager, dtoOptions); - } else if (type.IndexOf("Studio", StringComparison.OrdinalIgnoreCase) == 0) { item = GetStudio(name, libraryManager, dtoOptions); diff --git a/MediaBrowser.Api/FilterService.cs b/MediaBrowser.Api/FilterService.cs index be80305f9..9caf07cea 100644 --- a/MediaBrowser.Api/FilterService.cs +++ b/MediaBrowser.Api/FilterService.cs @@ -143,16 +143,6 @@ namespace MediaBrowser.Api }).ToArray(); } - else if (string.Equals(request.IncludeItemTypes, "Game", StringComparison.OrdinalIgnoreCase) || - string.Equals(request.IncludeItemTypes, "GameSystem", StringComparison.OrdinalIgnoreCase)) - { - filters.Genres = _libraryManager.GetGameGenres(genreQuery).Items.Select(i => new NameGuidPair - { - Name = i.Item1.Name, - Id = i.Item1.Id - - }).ToArray(); - } else { filters.Genres = _libraryManager.GetGenres(genreQuery).Items.Select(i => new NameGuidPair diff --git a/MediaBrowser.Api/GamesService.cs b/MediaBrowser.Api/GamesService.cs deleted file mode 100644 index bb908836c..000000000 --- a/MediaBrowser.Api/GamesService.cs +++ /dev/null @@ -1,140 +0,0 @@ -using System; -using System.IO; -using System.Linq; -using MediaBrowser.Controller.Dto; -using MediaBrowser.Controller.Entities; -using MediaBrowser.Controller.Library; -using MediaBrowser.Controller.Net; -using MediaBrowser.Controller.Persistence; -using MediaBrowser.Model.Dto; -using MediaBrowser.Model.Services; - -namespace MediaBrowser.Api -{ - /// <summary> - /// Class GetGameSystemSummaries - /// </summary> - [Route("/Games/SystemSummaries", "GET", Summary = "Finds games similar to a given game.")] - public class GetGameSystemSummaries : IReturn<GameSystemSummary[]> - { - /// <summary> - /// Gets or sets the user id. - /// </summary> - /// <value>The user id.</value> - [ApiMember(Name = "UserId", Description = "Optional. Filter by user id", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")] - public Guid UserId { get; set; } - } - - /// <summary> - /// Class GamesService - /// </summary> - [Authenticated] - public class GamesService : BaseApiService - { - /// <summary> - /// The _user manager - /// </summary> - private readonly IUserManager _userManager; - - /// <summary> - /// The _user data repository - /// </summary> - private readonly IUserDataManager _userDataRepository; - /// <summary> - /// The _library manager - /// </summary> - private readonly ILibraryManager _libraryManager; - - /// <summary> - /// The _item repo - /// </summary> - private readonly IItemRepository _itemRepo; - /// <summary> - /// The _dto service - /// </summary> - private readonly IDtoService _dtoService; - - private readonly IAuthorizationContext _authContext; - - /// <summary> - /// Initializes a new instance of the <see cref="GamesService" /> class. - /// </summary> - /// <param name="userManager">The user manager.</param> - /// <param name="userDataRepository">The user data repository.</param> - /// <param name="libraryManager">The library manager.</param> - /// <param name="itemRepo">The item repo.</param> - /// <param name="dtoService">The dto service.</param> - public GamesService(IUserManager userManager, IUserDataManager userDataRepository, ILibraryManager libraryManager, IItemRepository itemRepo, IDtoService dtoService, IAuthorizationContext authContext) - { - _userManager = userManager; - _userDataRepository = userDataRepository; - _libraryManager = libraryManager; - _itemRepo = itemRepo; - _dtoService = dtoService; - _authContext = authContext; - } - - /// <summary> - /// Gets the specified request. - /// </summary> - /// <param name="request">The request.</param> - /// <returns>System.Object.</returns> - public object Get(GetGameSystemSummaries request) - { - var user = request.UserId == null ? null : _userManager.GetUserById(request.UserId); - var query = new InternalItemsQuery(user) - { - IncludeItemTypes = new[] { typeof(GameSystem).Name }, - DtoOptions = new DtoOptions(false) - { - EnableImages = false - } - }; - - var result = _libraryManager.GetItemList(query) - .Cast<GameSystem>() - .Select(i => GetSummary(i, user)) - .ToArray(); - - return ToOptimizedResult(result); - } - - /// <summary> - /// Gets the summary. - /// </summary> - /// <param name="system">The system.</param> - /// <param name="user">The user.</param> - /// <returns>GameSystemSummary.</returns> - private GameSystemSummary GetSummary(GameSystem system, User user) - { - var summary = new GameSystemSummary - { - Name = system.GameSystemName, - DisplayName = system.Name - }; - - var items = user == null ? - system.GetRecursiveChildren(i => i is Game) : - system.GetRecursiveChildren(user, new InternalItemsQuery(user) - { - IncludeItemTypes = new[] { typeof(Game).Name }, - DtoOptions = new DtoOptions(false) - { - EnableImages = false - } - }); - - var games = items.Cast<Game>().ToArray(); - - summary.ClientInstalledGameCount = games.Count(i => i.IsPlaceHolder); - - summary.GameCount = games.Length; - - summary.GameFileExtensions = games.Where(i => !i.IsPlaceHolder).Select(i => Path.GetExtension(i.Path)) - .Distinct(StringComparer.OrdinalIgnoreCase) - .ToArray(); - - return summary; - } - } -} diff --git a/MediaBrowser.Api/Images/ImageByNameService.cs b/MediaBrowser.Api/Images/ImageByNameService.cs index fdf584277..922bd8ed6 100644 --- a/MediaBrowser.Api/Images/ImageByNameService.cs +++ b/MediaBrowser.Api/Images/ImageByNameService.cs @@ -145,7 +145,7 @@ namespace MediaBrowser.Api.Images Theme = supportsThemes ? GetThemeName(i.FullName, path) : null, Context = supportsThemes ? null : GetThemeName(i.FullName, path), - Format = i.Extension.ToLower().TrimStart('.') + Format = i.Extension.ToLowerInvariant().TrimStart('.') }) .OrderBy(i => i.Name) .ToList(); diff --git a/MediaBrowser.Api/Images/ImageService.cs b/MediaBrowser.Api/Images/ImageService.cs index 149e54f01..b5e23476e 100644 --- a/MediaBrowser.Api/Images/ImageService.cs +++ b/MediaBrowser.Api/Images/ImageService.cs @@ -95,8 +95,6 @@ namespace MediaBrowser.Api.Images [Route("/Artists/{Name}/Images/{Type}/{Index}", "GET")] [Route("/Genres/{Name}/Images/{Type}", "GET")] [Route("/Genres/{Name}/Images/{Type}/{Index}", "GET")] - [Route("/GameGenres/{Name}/Images/{Type}", "GET")] - [Route("/GameGenres/{Name}/Images/{Type}/{Index}", "GET")] [Route("/MusicGenres/{Name}/Images/{Type}", "GET")] [Route("/MusicGenres/{Name}/Images/{Type}/{Index}", "GET")] [Route("/Persons/{Name}/Images/{Type}", "GET")] @@ -109,8 +107,6 @@ namespace MediaBrowser.Api.Images [Route("/Artists/{Name}/Images/{Type}/{Index}", "HEAD")] [Route("/Genres/{Name}/Images/{Type}", "HEAD")] [Route("/Genres/{Name}/Images/{Type}/{Index}", "HEAD")] - [Route("/GameGenres/{Name}/Images/{Type}", "HEAD")] - [Route("/GameGenres/{Name}/Images/{Type}/{Index}", "HEAD")] [Route("/MusicGenres/{Name}/Images/{Type}", "HEAD")] [Route("/MusicGenres/{Name}/Images/{Type}/{Index}", "HEAD")] [Route("/Persons/{Name}/Images/{Type}", "HEAD")] diff --git a/MediaBrowser.Api/ItemLookupService.cs b/MediaBrowser.Api/ItemLookupService.cs index 0e7bdc086..f3ea7907f 100644 --- a/MediaBrowser.Api/ItemLookupService.cs +++ b/MediaBrowser.Api/ItemLookupService.cs @@ -57,12 +57,6 @@ namespace MediaBrowser.Api { } - [Route("/Items/RemoteSearch/Game", "POST")] - [Authenticated] - public class GetGameRemoteSearchResults : RemoteSearchQuery<GameInfo>, IReturn<List<RemoteSearchResult>> - { - } - [Route("/Items/RemoteSearch/BoxSet", "POST")] [Authenticated] public class GetBoxSetRemoteSearchResults : RemoteSearchQuery<BoxSetInfo>, IReturn<List<RemoteSearchResult>> @@ -173,13 +167,6 @@ namespace MediaBrowser.Api return ToOptimizedResult(result); } - public async Task<object> Post(GetGameRemoteSearchResults request) - { - var result = await _providerManager.GetRemoteSearchResults<Game, GameInfo>(request, CancellationToken.None).ConfigureAwait(false); - - return ToOptimizedResult(result); - } - public async Task<object> Post(GetBoxSetRemoteSearchResults request) { var result = await _providerManager.GetRemoteSearchResults<BoxSet, BoxSetInfo>(request, CancellationToken.None).ConfigureAwait(false); diff --git a/MediaBrowser.Api/ItemUpdateService.cs b/MediaBrowser.Api/ItemUpdateService.cs index 94e53a685..825732888 100644 --- a/MediaBrowser.Api/ItemUpdateService.cs +++ b/MediaBrowser.Api/ItemUpdateService.cs @@ -155,11 +155,6 @@ namespace MediaBrowser.Api Name = "Books", Value = "books" }); - list.Add(new NameValuePair - { - Name = "Games", - Value = "games" - }); } list.Add(new NameValuePair diff --git a/MediaBrowser.Api/Library/LibraryService.cs b/MediaBrowser.Api/Library/LibraryService.cs index 12d807a7e..d44b07256 100644 --- a/MediaBrowser.Api/Library/LibraryService.cs +++ b/MediaBrowser.Api/Library/LibraryService.cs @@ -265,7 +265,6 @@ namespace MediaBrowser.Api.Library public string Id { get; set; } } - [Route("/Games/{Id}/Similar", "GET", Summary = "Finds games similar to a given game.")] [Route("/Artists/{Id}/Similar", "GET", Summary = "Finds albums similar to a given album.")] [Route("/Items/{Id}/Similar", "GET", Summary = "Gets similar items")] [Route("/Albums/{Id}/Similar", "GET", Summary = "Finds albums similar to a given album.")] @@ -369,8 +368,6 @@ namespace MediaBrowser.Api.Library return new string[] { "Series", "Season", "Episode" }; case CollectionType.Books: return new string[] { "Book" }; - case CollectionType.Games: - return new string[] { "Game", "GameSystem" }; case CollectionType.Music: return new string[] { "MusicAlbum", "MusicArtist", "Audio", "MusicVideo" }; case CollectionType.HomeVideos: @@ -554,7 +551,8 @@ namespace MediaBrowser.Api.Library Name = i.Name, DefaultEnabled = IsSaverEnabledByDefault(i.Name, types, isNewLibrary) }) - .DistinctBy(i => i.Name, StringComparer.OrdinalIgnoreCase) + .GroupBy(i => i.Name, StringComparer.OrdinalIgnoreCase) + .Select(x => x.First()) .ToArray(); result.MetadataReaders = plugins @@ -564,7 +562,8 @@ namespace MediaBrowser.Api.Library Name = i.Name, DefaultEnabled = true }) - .DistinctBy(i => i.Name, StringComparer.OrdinalIgnoreCase) + .GroupBy(i => i.Name, StringComparer.OrdinalIgnoreCase) + .Select(x => x.First()) .ToArray(); result.SubtitleFetchers = plugins @@ -574,7 +573,8 @@ namespace MediaBrowser.Api.Library Name = i.Name, DefaultEnabled = true }) - .DistinctBy(i => i.Name, StringComparer.OrdinalIgnoreCase) + .GroupBy(i => i.Name, StringComparer.OrdinalIgnoreCase) + .Select(x => x.First()) .ToArray(); var typeOptions = new List<LibraryTypeOptions>(); @@ -596,7 +596,8 @@ namespace MediaBrowser.Api.Library Name = i.Name, DefaultEnabled = IsMetadataFetcherEnabledByDefault(i.Name, type, isNewLibrary) }) - .DistinctBy(i => i.Name, StringComparer.OrdinalIgnoreCase) + .GroupBy(i => i.Name, StringComparer.OrdinalIgnoreCase) + .Select(x => x.First()) .ToArray(), ImageFetchers = plugins @@ -607,7 +608,8 @@ namespace MediaBrowser.Api.Library Name = i.Name, DefaultEnabled = IsImageFetcherEnabledByDefault(i.Name, type, isNewLibrary) }) - .DistinctBy(i => i.Name, StringComparer.OrdinalIgnoreCase) + .GroupBy(i => i.Name, StringComparer.OrdinalIgnoreCase) + .Select(x => x.First()) .ToArray(), SupportedImageTypes = plugins @@ -952,8 +954,6 @@ namespace MediaBrowser.Api.Library { AlbumCount = GetCount(typeof(MusicAlbum), user, request), EpisodeCount = GetCount(typeof(Episode), user, request), - GameCount = GetCount(typeof(Game), user, request), - GameSystemCount = GetCount(typeof(GameSystem), user, request), MovieCount = GetCount(typeof(Movie), user, request), SeriesCount = GetCount(typeof(Series), user, request), SongCount = GetCount(typeof(Audio), user, request), diff --git a/MediaBrowser.Api/LiveTv/LiveTvService.cs b/MediaBrowser.Api/LiveTv/LiveTvService.cs index 88ed4b525..8fdd726b7 100644 --- a/MediaBrowser.Api/LiveTv/LiveTvService.cs +++ b/MediaBrowser.Api/LiveTv/LiveTvService.cs @@ -875,7 +875,9 @@ namespace MediaBrowser.Api.LiveTv private string GetHashedString(string str) { // legacy - return BitConverter.ToString(_cryptographyProvider.ComputeSHA1(Encoding.UTF8.GetBytes(str))).Replace("-", string.Empty).ToLower(); + return BitConverter.ToString( + _cryptographyProvider.ComputeSHA1(Encoding.UTF8.GetBytes(str))) + .Replace("-", string.Empty).ToLowerInvariant(); } public void Delete(DeleteListingProvider request) diff --git a/MediaBrowser.Api/Movies/MoviesService.cs b/MediaBrowser.Api/Movies/MoviesService.cs index 996087018..91766255f 100644 --- a/MediaBrowser.Api/Movies/MoviesService.cs +++ b/MediaBrowser.Api/Movies/MoviesService.cs @@ -268,7 +268,8 @@ namespace MediaBrowser.Api.Movies EnableGroupByMetadataKey = true, DtoOptions = dtoOptions - }).DistinctBy(i => i.GetProviderId(MetadataProviders.Imdb) ?? Guid.NewGuid().ToString("N")) + }).GroupBy(i => i.GetProviderId(MetadataProviders.Imdb) ?? Guid.NewGuid().ToString("N")) + .Select(x => x.First()) .Take(itemLimit) .ToList(); @@ -308,7 +309,8 @@ namespace MediaBrowser.Api.Movies EnableGroupByMetadataKey = true, DtoOptions = dtoOptions - }).DistinctBy(i => i.GetProviderId(MetadataProviders.Imdb) ?? Guid.NewGuid().ToString("N")) + }).GroupBy(i => i.GetProviderId(MetadataProviders.Imdb) ?? Guid.NewGuid().ToString("N")) + .Select(x => x.First()) .Take(itemLimit) .ToList(); diff --git a/MediaBrowser.Api/PackageService.cs b/MediaBrowser.Api/PackageService.cs index 16819ee37..fbb876dea 100644 --- a/MediaBrowser.Api/PackageService.cs +++ b/MediaBrowser.Api/PackageService.cs @@ -197,7 +197,7 @@ namespace MediaBrowser.Api throw new ResourceNotFoundException(string.Format("Package not found: {0}", request.Name)); } - Task.Run(() => _installationManager.InstallPackage(package, true, new SimpleProgress<double>(), CancellationToken.None)); + await _installationManager.InstallPackage(package, true, new SimpleProgress<double>(), CancellationToken.None); } /// <summary> diff --git a/MediaBrowser.Api/Playback/BaseStreamingService.cs b/MediaBrowser.Api/Playback/BaseStreamingService.cs index 4ed83baad..ec42cad33 100644 --- a/MediaBrowser.Api/Playback/BaseStreamingService.cs +++ b/MediaBrowser.Api/Playback/BaseStreamingService.cs @@ -135,10 +135,10 @@ namespace MediaBrowser.Api.Playback if (EnableOutputInSubFolder) { - return Path.Combine(folder, dataHash, dataHash + (outputFileExtension ?? string.Empty).ToLower()); + return Path.Combine(folder, dataHash, dataHash + (outputFileExtension ?? string.Empty).ToLowerInvariant()); } - return Path.Combine(folder, dataHash + (outputFileExtension ?? string.Empty).ToLower()); + return Path.Combine(folder, dataHash + (outputFileExtension ?? string.Empty).ToLowerInvariant()); } protected virtual bool EnableOutputInSubFolder => false; diff --git a/MediaBrowser.Api/Session/SessionsService.cs b/MediaBrowser.Api/Session/SessionsService.cs index c9a11c117..f011e6e41 100644 --- a/MediaBrowser.Api/Session/SessionsService.cs +++ b/MediaBrowser.Api/Session/SessionsService.cs @@ -194,7 +194,7 @@ namespace MediaBrowser.Api.Session [ApiMember(Name = "Id", Description = "Session Id", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "POST")] public string Id { get; set; } - [ApiMember(Name = "PlayableMediaTypes", Description = "A list of playable media types, comma delimited. Audio, Video, Book, Game, Photo.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "POST")] + [ApiMember(Name = "PlayableMediaTypes", Description = "A list of playable media types, comma delimited. Audio, Video, Book, Photo.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "POST")] public string PlayableMediaTypes { get; set; } [ApiMember(Name = "SupportedCommands", Description = "A list of supported remote control commands, comma delimited", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "POST")] diff --git a/MediaBrowser.Api/StartupWizardService.cs b/MediaBrowser.Api/StartupWizardService.cs index 3d59b4c9a..53ba7eefd 100644 --- a/MediaBrowser.Api/StartupWizardService.cs +++ b/MediaBrowser.Api/StartupWizardService.cs @@ -3,7 +3,6 @@ using System.Threading.Tasks; using MediaBrowser.Common.Net; using MediaBrowser.Controller; using MediaBrowser.Controller.Configuration; -using MediaBrowser.Controller.Connect; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.MediaEncoding; using MediaBrowser.Controller.Net; @@ -39,7 +38,7 @@ namespace MediaBrowser.Api } [Route("/Startup/User", "POST", Summary = "Updates initial user info", IsHidden = true)] - public class UpdateStartupUser : StartupUser, IReturn<UpdateStartupUserResult> + public class UpdateStartupUser : StartupUser { } @@ -102,12 +101,11 @@ namespace MediaBrowser.Api return new StartupUser { Name = user.Name, - ConnectUserName = user.ConnectUserName, Password = user.Password }; } - public async Task<object> Post(UpdateStartupUser request) + public async Task Post(UpdateStartupUser request) { var user = _userManager.Users.First(); @@ -118,10 +116,6 @@ namespace MediaBrowser.Api if (!string.IsNullOrEmpty(request.Password)) { await _userManager.ChangePassword(user, request.Password).ConfigureAwait(false); } - - var result = new UpdateStartupUserResult(); - - return result; } } @@ -135,12 +129,6 @@ namespace MediaBrowser.Api public class StartupUser { public string Name { get; set; } - public string ConnectUserName { get; set; } public string Password { get; set; } } - - public class UpdateStartupUserResult - { - public UserLinkResult UserLinkResult { get; set; } - } } diff --git a/MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs b/MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs index 6e577c53e..471b41127 100644 --- a/MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs +++ b/MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs @@ -224,7 +224,6 @@ namespace MediaBrowser.Api.UserLibrary dto.TrailerCount = counts.TrailerCount; dto.AlbumCount = counts.AlbumCount; dto.SongCount = counts.SongCount; - dto.GameCount = counts.GameCount; dto.ArtistCount = counts.ArtistCount; } diff --git a/MediaBrowser.Api/UserLibrary/BaseItemsRequest.cs b/MediaBrowser.Api/UserLibrary/BaseItemsRequest.cs index 4cccc0cb5..7af50c329 100644 --- a/MediaBrowser.Api/UserLibrary/BaseItemsRequest.cs +++ b/MediaBrowser.Api/UserLibrary/BaseItemsRequest.cs @@ -42,12 +42,6 @@ namespace MediaBrowser.Api.UserLibrary [ApiMember(Name = "MinIndexNumber", Description = "Optional filter by minimum index number.", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")] public int? MinIndexNumber { get; set; } - [ApiMember(Name = "MinPlayers", Description = "Optional filter by minimum number of game players.", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")] - public int? MinPlayers { get; set; } - - [ApiMember(Name = "MaxPlayers", Description = "Optional filter by maximum number of game players.", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")] - public int? MaxPlayers { get; set; } - [ApiMember(Name = "ParentIndexNumber", Description = "Optional filter by parent index number.", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")] public int? ParentIndexNumber { get; set; } diff --git a/MediaBrowser.Api/UserLibrary/GameGenresService.cs b/MediaBrowser.Api/UserLibrary/GameGenresService.cs deleted file mode 100644 index 3e0d4aca4..000000000 --- a/MediaBrowser.Api/UserLibrary/GameGenresService.cs +++ /dev/null @@ -1,105 +0,0 @@ -using System; -using System.Collections.Generic; -using MediaBrowser.Controller.Dto; -using MediaBrowser.Controller.Entities; -using MediaBrowser.Controller.Library; -using MediaBrowser.Controller.Net; -using MediaBrowser.Controller.Persistence; -using MediaBrowser.Model.Dto; -using MediaBrowser.Model.Querying; -using MediaBrowser.Model.Services; - -namespace MediaBrowser.Api.UserLibrary -{ - [Route("/GameGenres", "GET", Summary = "Gets all Game genres from a given item, folder, or the entire library")] - public class GetGameGenres : GetItemsByName - { - } - - [Route("/GameGenres/{Name}", "GET", Summary = "Gets a Game genre, by name")] - public class GetGameGenre : IReturn<BaseItemDto> - { - /// <summary> - /// Gets or sets the name. - /// </summary> - /// <value>The name.</value> - [ApiMember(Name = "Name", Description = "The genre name", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")] - public string Name { get; set; } - - /// <summary> - /// Gets or sets the user id. - /// </summary> - /// <value>The user id.</value> - [ApiMember(Name = "UserId", Description = "Optional. Filter by user id, and attach user data", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")] - public Guid UserId { get; set; } - } - - [Authenticated] - public class GameGenresService : BaseItemsByNameService<GameGenre> - { - /// <summary> - /// Gets the specified request. - /// </summary> - /// <param name="request">The request.</param> - /// <returns>System.Object.</returns> - public object Get(GetGameGenre request) - { - var result = GetItem(request); - - return ToOptimizedResult(result); - } - - /// <summary> - /// Gets the item. - /// </summary> - /// <param name="request">The request.</param> - /// <returns>Task{BaseItemDto}.</returns> - private BaseItemDto GetItem(GetGameGenre request) - { - var dtoOptions = GetDtoOptions(AuthorizationContext, request); - - var item = GetGameGenre(request.Name, LibraryManager, dtoOptions); - - if (!request.UserId.Equals(Guid.Empty)) - { - var user = UserManager.GetUserById(request.UserId); - - return DtoService.GetBaseItemDto(item, dtoOptions, user); - } - - return DtoService.GetBaseItemDto(item, dtoOptions); - } - - /// <summary> - /// Gets the specified request. - /// </summary> - /// <param name="request">The request.</param> - /// <returns>System.Object.</returns> - public object Get(GetGameGenres request) - { - var result = GetResultSlim(request); - - return ToOptimizedResult(result); - } - - protected override QueryResult<Tuple<BaseItem, ItemCounts>> GetItems(GetItemsByName request, InternalItemsQuery query) - { - return LibraryManager.GetGameGenres(query); - } - - /// <summary> - /// Gets all items. - /// </summary> - /// <param name="request">The request.</param> - /// <param name="items">The items.</param> - /// <returns>IEnumerable{Tuple{System.StringFunc{System.Int32}}}.</returns> - protected override IEnumerable<BaseItem> GetAllItems(GetItemsByName request, IList<BaseItem> items) - { - throw new NotImplementedException(); - } - - public GameGenresService(IUserManager userManager, ILibraryManager libraryManager, IUserDataManager userDataRepository, IItemRepository itemRepository, IDtoService dtoService, IAuthorizationContext authorizationContext) : base(userManager, libraryManager, userDataRepository, itemRepository, dtoService, authorizationContext) - { - } - } -} diff --git a/MediaBrowser.Api/UserLibrary/GenresService.cs b/MediaBrowser.Api/UserLibrary/GenresService.cs index e20428ead..baf570d50 100644 --- a/MediaBrowser.Api/UserLibrary/GenresService.cs +++ b/MediaBrowser.Api/UserLibrary/GenresService.cs @@ -101,11 +101,6 @@ namespace MediaBrowser.Api.UserLibrary return LibraryManager.GetMusicGenres(query); } - if (string.Equals(viewType, CollectionType.Games)) - { - return LibraryManager.GetGameGenres(query); - } - return LibraryManager.GetGenres(query); } diff --git a/MediaBrowser.Api/UserLibrary/ItemsService.cs b/MediaBrowser.Api/UserLibrary/ItemsService.cs index bf453576c..3ae7da007 100644 --- a/MediaBrowser.Api/UserLibrary/ItemsService.cs +++ b/MediaBrowser.Api/UserLibrary/ItemsService.cs @@ -304,8 +304,6 @@ namespace MediaBrowser.Api.UserLibrary VideoTypes = request.GetVideoTypes(), AdjacentTo = request.AdjacentTo, ItemIds = GetGuids(request.Ids), - MinPlayers = request.MinPlayers, - MaxPlayers = request.MaxPlayers, MinCommunityRating = request.MinCommunityRating, MinCriticRating = request.MinCriticRating, ParentId = string.IsNullOrWhiteSpace(request.ParentId) ? Guid.Empty : new Guid(request.ParentId), diff --git a/MediaBrowser.Api/UserLibrary/PlaystateService.cs b/MediaBrowser.Api/UserLibrary/PlaystateService.cs index 72a943092..b40a92a7c 100644 --- a/MediaBrowser.Api/UserLibrary/PlaystateService.cs +++ b/MediaBrowser.Api/UserLibrary/PlaystateService.cs @@ -247,14 +247,14 @@ namespace MediaBrowser.Api.UserLibrary /// Posts the specified request. /// </summary> /// <param name="request">The request.</param> - public async Task<object> Post(MarkPlayedItem request) + public object Post(MarkPlayedItem request) { - var result = await MarkPlayed(request).ConfigureAwait(false); + var result = MarkPlayed(request); return ToOptimizedResult(result); } - private async Task<UserItemDataDto> MarkPlayed(MarkPlayedItem request) + private UserItemDataDto MarkPlayed(MarkPlayedItem request) { var user = _userManager.GetUserById(request.UserId); @@ -366,9 +366,9 @@ namespace MediaBrowser.Api.UserLibrary /// Posts the specified request. /// </summary> /// <param name="request">The request.</param> - public void Delete(OnPlaybackStopped request) + public Task Delete(OnPlaybackStopped request) { - Post(new ReportPlaybackStopped + return Post(new ReportPlaybackStopped { ItemId = new Guid(request.Id), PositionTicks = request.PositionTicks, @@ -379,20 +379,18 @@ namespace MediaBrowser.Api.UserLibrary }); } - public void Post(ReportPlaybackStopped request) + public async Task Post(ReportPlaybackStopped request) { Logger.LogDebug("ReportPlaybackStopped PlaySessionId: {0}", request.PlaySessionId ?? string.Empty); if (!string.IsNullOrWhiteSpace(request.PlaySessionId)) { - ApiEntryPoint.Instance.KillTranscodingJobs(_authContext.GetAuthorizationInfo(Request).DeviceId, request.PlaySessionId, s => true); + await ApiEntryPoint.Instance.KillTranscodingJobs(_authContext.GetAuthorizationInfo(Request).DeviceId, request.PlaySessionId, s => true); } request.SessionId = GetSession(_sessionContext).Id; - var task = _sessionManager.OnPlaybackStopped(request); - - Task.WaitAll(task); + await _sessionManager.OnPlaybackStopped(request); } /// <summary> @@ -403,10 +401,10 @@ namespace MediaBrowser.Api.UserLibrary { var task = MarkUnplayed(request); - return ToOptimizedResult(task.Result); + return ToOptimizedResult(task); } - private async Task<UserItemDataDto> MarkUnplayed(MarkUnplayedItem request) + private UserItemDataDto MarkUnplayed(MarkUnplayedItem request) { var user = _userManager.GetUserById(request.UserId); diff --git a/MediaBrowser.Api/UserService.cs b/MediaBrowser.Api/UserService.cs index 2ef18d7cf..a6849f75f 100644 --- a/MediaBrowser.Api/UserService.cs +++ b/MediaBrowser.Api/UserService.cs @@ -10,7 +10,6 @@ using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Net; using MediaBrowser.Controller.Session; using MediaBrowser.Model.Configuration; -using MediaBrowser.Model.Connect; using MediaBrowser.Model.Dto; using MediaBrowser.Model.Services; using MediaBrowser.Model.Users; @@ -299,11 +298,6 @@ namespace MediaBrowser.Api users = users.Where(i => i.Policy.IsHidden == request.IsHidden.Value); } - if (request.IsGuest.HasValue) - { - users = users.Where(i => (i.ConnectLinkType.HasValue && i.ConnectLinkType.Value == UserLinkType.Guest) == request.IsGuest.Value); - } - if (filterByDevice) { var deviceId = _authContext.GetAuthorizationInfo(Request).DeviceId; diff --git a/MediaBrowser.Controller/Connect/UserLinkResult.cs b/MediaBrowser.Controller/Connect/UserLinkResult.cs deleted file mode 100644 index 327ceb952..000000000 --- a/MediaBrowser.Controller/Connect/UserLinkResult.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace MediaBrowser.Controller.Connect -{ - public class UserLinkResult - { - public bool IsPending { get; set; } - public bool IsNewUserInvitation { get; set; } - public string GuestDisplayName { get; set; } - } -} diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs index 482d14e11..72c4e3573 100644 --- a/MediaBrowser.Controller/Entities/BaseItem.cs +++ b/MediaBrowser.Controller/Entities/BaseItem.cs @@ -615,7 +615,7 @@ namespace MediaBrowser.Controller.Entities if (!string.IsNullOrEmpty(ForcedSortName)) { // Need the ToLower because that's what CreateSortName does - _sortName = ModifySortChunks(ForcedSortName).ToLower(); + _sortName = ModifySortChunks(ForcedSortName).ToLowerInvariant(); } else { @@ -661,7 +661,7 @@ namespace MediaBrowser.Controller.Entities return Name.TrimStart(); } - var sortable = Name.Trim().ToLower(); + var sortable = Name.Trim().ToLowerInvariant(); foreach (var removeChar in ConfigurationManager.Configuration.SortRemoveCharacters) { diff --git a/MediaBrowser.Controller/Entities/CollectionFolder.cs b/MediaBrowser.Controller/Entities/CollectionFolder.cs index 91cfcd0ce..275052d48 100644 --- a/MediaBrowser.Controller/Entities/CollectionFolder.cs +++ b/MediaBrowser.Controller/Entities/CollectionFolder.cs @@ -335,7 +335,11 @@ namespace MediaBrowser.Controller.Entities .OfType<Folder>() .ToList(); - return PhysicalLocations.Where(i => !FileSystem.AreEqual(i, Path)).SelectMany(i => GetPhysicalParents(i, rootChildren)).DistinctBy(i => i.Id); + return PhysicalLocations + .Where(i => !FileSystem.AreEqual(i, Path)) + .SelectMany(i => GetPhysicalParents(i, rootChildren)) + .GroupBy(x => x.Id) + .Select(x => x.First()); } private IEnumerable<Folder> GetPhysicalParents(string path, List<Folder> rootChildren) diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs index dab96509c..8bfadbee6 100644 --- a/MediaBrowser.Controller/Entities/Folder.cs +++ b/MediaBrowser.Controller/Entities/Folder.cs @@ -1149,16 +1149,6 @@ namespace MediaBrowser.Controller.Entities return false; } - if (request.MinPlayers.HasValue) - { - return false; - } - - if (request.MaxPlayers.HasValue) - { - return false; - } - if (request.MinCommunityRating.HasValue) { return false; diff --git a/MediaBrowser.Controller/Entities/Game.cs b/MediaBrowser.Controller/Entities/Game.cs deleted file mode 100644 index eea1bf43d..000000000 --- a/MediaBrowser.Controller/Entities/Game.cs +++ /dev/null @@ -1,113 +0,0 @@ -using System; -using System.Collections.Generic; -using MediaBrowser.Controller.Providers; -using MediaBrowser.Model.Configuration; -using MediaBrowser.Model.Entities; -using MediaBrowser.Model.IO; -using MediaBrowser.Model.Serialization; - -namespace MediaBrowser.Controller.Entities -{ - public class Game : BaseItem, IHasTrailers, IHasScreenshots, ISupportsPlaceHolders, IHasLookupInfo<GameInfo> - { - public Game() - { - MultiPartGameFiles = Array.Empty<string>(); - RemoteTrailers = EmptyMediaUrlArray; - LocalTrailerIds = Array.Empty<Guid>(); - RemoteTrailerIds = Array.Empty<Guid>(); - } - - public Guid[] LocalTrailerIds { get; set; } - public Guid[] RemoteTrailerIds { get; set; } - - public override bool CanDownload() - { - return IsFileProtocol; - } - - [IgnoreDataMember] - public override bool SupportsThemeMedia => true; - - [IgnoreDataMember] - public override bool SupportsPeople => false; - - /// <summary> - /// Gets the type of the media. - /// </summary> - /// <value>The type of the media.</value> - [IgnoreDataMember] - public override string MediaType => Model.Entities.MediaType.Game; - - /// <summary> - /// Gets or sets the players supported. - /// </summary> - /// <value>The players supported.</value> - public int? PlayersSupported { get; set; } - - /// <summary> - /// Gets a value indicating whether this instance is place holder. - /// </summary> - /// <value><c>true</c> if this instance is place holder; otherwise, <c>false</c>.</value> - public bool IsPlaceHolder { get; set; } - - /// <summary> - /// Gets or sets the game system. - /// </summary> - /// <value>The game system.</value> - public string GameSystem { get; set; } - - /// <summary> - /// Gets or sets a value indicating whether this instance is multi part. - /// </summary> - /// <value><c>true</c> if this instance is multi part; otherwise, <c>false</c>.</value> - public bool IsMultiPart { get; set; } - - /// <summary> - /// Holds the paths to the game files in the event this is a multipart game - /// </summary> - public string[] MultiPartGameFiles { get; set; } - - public override List<string> GetUserDataKeys() - { - var list = base.GetUserDataKeys(); - var id = this.GetProviderId(MetadataProviders.Gamesdb); - - if (!string.IsNullOrEmpty(id)) - { - list.Insert(0, "Game-Gamesdb-" + id); - } - return list; - } - - public override IEnumerable<FileSystemMetadata> GetDeletePaths() - { - if (!IsInMixedFolder) - { - return new[] { - new FileSystemMetadata - { - FullName = System.IO.Path.GetDirectoryName(Path), - IsDirectory = true - } - }; - } - - return base.GetDeletePaths(); - } - - public override UnratedItem GetBlockUnratedType() - { - return UnratedItem.Game; - } - - public GameInfo GetLookupInfo() - { - var id = GetItemLookupInfo<GameInfo>(); - - id.GameSystem = GameSystem; - - return id; - } - } -} diff --git a/MediaBrowser.Controller/Entities/GameGenre.cs b/MediaBrowser.Controller/Entities/GameGenre.cs deleted file mode 100644 index c0fd4ae89..000000000 --- a/MediaBrowser.Controller/Entities/GameGenre.cs +++ /dev/null @@ -1,109 +0,0 @@ -using System; -using System.Collections.Generic; -using MediaBrowser.Controller.Extensions; -using MediaBrowser.Model.Serialization; -using Microsoft.Extensions.Logging; - -namespace MediaBrowser.Controller.Entities -{ - public class GameGenre : BaseItem, IItemByName - { - public override List<string> GetUserDataKeys() - { - var list = base.GetUserDataKeys(); - - list.Insert(0, GetType().Name + "-" + (Name ?? string.Empty).RemoveDiacritics()); - return list; - } - - public override string CreatePresentationUniqueKey() - { - return GetUserDataKeys()[0]; - } - - public override double GetDefaultPrimaryImageAspectRatio() - { - return 1; - } - - /// <summary> - /// Returns the folder containing the item. - /// If the item is a folder, it returns the folder itself - /// </summary> - /// <value>The containing folder path.</value> - [IgnoreDataMember] - public override string ContainingFolderPath => Path; - - [IgnoreDataMember] - public override bool SupportsAncestors => false; - - public override bool IsSaveLocalMetadataEnabled() - { - return true; - } - - public override bool CanDelete() - { - return false; - } - - public IList<BaseItem> GetTaggedItems(InternalItemsQuery query) - { - query.GenreIds = new[] { Id }; - query.IncludeItemTypes = new[] { typeof(Game).Name }; - - return LibraryManager.GetItemList(query); - } - - [IgnoreDataMember] - public override bool SupportsPeople => false; - - public static string GetPath(string name) - { - return GetPath(name, true); - } - - public static string GetPath(string name, bool normalizeName) - { - // Trim the period at the end because windows will have a hard time with that - var validName = normalizeName ? - FileSystem.GetValidFilename(name).Trim().TrimEnd('.') : - name; - - return System.IO.Path.Combine(ConfigurationManager.ApplicationPaths.GameGenrePath, validName); - } - - private string GetRebasedPath() - { - return GetPath(System.IO.Path.GetFileName(Path), false); - } - - public override bool RequiresRefresh() - { - var newPath = GetRebasedPath(); - if (!string.Equals(Path, newPath, StringComparison.Ordinal)) - { - Logger.LogDebug("{0} path has changed from {1} to {2}", GetType().Name, Path, newPath); - return true; - } - return base.RequiresRefresh(); - } - - /// <summary> - /// This is called before any metadata refresh and returns true or false indicating if changes were made - /// </summary> - public override bool BeforeMetadataRefresh(bool replaceAllMetdata) - { - var hasChanges = base.BeforeMetadataRefresh(replaceAllMetdata); - - var newPath = GetRebasedPath(); - if (!string.Equals(Path, newPath, StringComparison.Ordinal)) - { - Path = newPath; - hasChanges = true; - } - - return hasChanges; - } - } -} diff --git a/MediaBrowser.Controller/Entities/GameSystem.cs b/MediaBrowser.Controller/Entities/GameSystem.cs deleted file mode 100644 index 63f830d25..000000000 --- a/MediaBrowser.Controller/Entities/GameSystem.cs +++ /dev/null @@ -1,77 +0,0 @@ -using System; -using System.Collections.Generic; -using MediaBrowser.Controller.Providers; -using MediaBrowser.Model.Configuration; -using MediaBrowser.Model.Serialization; -using MediaBrowser.Model.Users; - -namespace MediaBrowser.Controller.Entities -{ - /// <summary> - /// Class GameSystem - /// </summary> - public class GameSystem : Folder, IHasLookupInfo<GameSystemInfo> - { - /// <summary> - /// Return the id that should be used to key display prefs for this item. - /// Default is based on the type for everything except actual generic folders. - /// </summary> - /// <value>The display prefs id.</value> - [IgnoreDataMember] - public override Guid DisplayPreferencesId => Id; - - [IgnoreDataMember] - public override bool SupportsPlayedStatus => false; - - [IgnoreDataMember] - public override bool SupportsInheritedParentImages => false; - - public override double GetDefaultPrimaryImageAspectRatio() - { - double value = 16; - value /= 9; - - return value; - } - - /// <summary> - /// Gets or sets the game system. - /// </summary> - /// <value>The game system.</value> - public string GameSystemName { get; set; } - - public override List<string> GetUserDataKeys() - { - var list = base.GetUserDataKeys(); - - if (!string.IsNullOrEmpty(GameSystemName)) - { - list.Insert(0, "GameSystem-" + GameSystemName); - } - return list; - } - - protected override bool GetBlockUnratedValue(UserPolicy config) - { - // Don't block. Determine by game - return false; - } - - public override UnratedItem GetBlockUnratedType() - { - return UnratedItem.Game; - } - - public GameSystemInfo GetLookupInfo() - { - var id = GetItemLookupInfo<GameSystemInfo>(); - - id.Path = Path; - - return id; - } - - [IgnoreDataMember] - public override bool SupportsPeople => false; - } -} diff --git a/MediaBrowser.Controller/Entities/Genre.cs b/MediaBrowser.Controller/Entities/Genre.cs index 3f3ab3551..44cb62d22 100644 --- a/MediaBrowser.Controller/Entities/Genre.cs +++ b/MediaBrowser.Controller/Entities/Genre.cs @@ -56,7 +56,7 @@ namespace MediaBrowser.Controller.Entities public IList<BaseItem> GetTaggedItems(InternalItemsQuery query) { query.GenreIds = new[] { Id }; - query.ExcludeItemTypes = new[] { typeof(Game).Name, typeof(MusicVideo).Name, typeof(Audio.Audio).Name, typeof(MusicAlbum).Name, typeof(MusicArtist).Name }; + query.ExcludeItemTypes = new[] { typeof(MusicVideo).Name, typeof(Audio.Audio).Name, typeof(MusicAlbum).Name, typeof(MusicArtist).Name }; return LibraryManager.GetItemList(query); } diff --git a/MediaBrowser.Controller/Entities/InternalItemsQuery.cs b/MediaBrowser.Controller/Entities/InternalItemsQuery.cs index 4b7af5391..78f859069 100644 --- a/MediaBrowser.Controller/Entities/InternalItemsQuery.cs +++ b/MediaBrowser.Controller/Entities/InternalItemsQuery.cs @@ -95,9 +95,6 @@ namespace MediaBrowser.Controller.Entities public bool? IsKids { get; set; } public bool? IsNews { get; set; } public bool? IsSeries { get; set; } - - public int? MinPlayers { get; set; } - public int? MaxPlayers { get; set; } public int? MinIndexNumber { get; set; } public int? AiredDuringSeason { get; set; } public double? MinCriticRating { get; set; } diff --git a/MediaBrowser.Controller/Entities/TV/Series.cs b/MediaBrowser.Controller/Entities/TV/Series.cs index 4539ab0f2..570e9389e 100644 --- a/MediaBrowser.Controller/Entities/TV/Series.cs +++ b/MediaBrowser.Controller/Entities/TV/Series.cs @@ -270,7 +270,7 @@ namespace MediaBrowser.Controller.Entities.TV // This depends on settings for that series // When this happens, remove the duplicate from season 0 - return allEpisodes.DistinctBy(i => i.Id).Reverse(); + return allEpisodes.GroupBy(i => i.Id).Select(x => x.First()).Reverse(); } public async Task RefreshAllMetadata(MetadataRefreshOptions refreshOptions, IProgress<double> progress, CancellationToken cancellationToken) diff --git a/MediaBrowser.Controller/Entities/User.cs b/MediaBrowser.Controller/Entities/User.cs index 06bae9211..0d5f508dd 100644 --- a/MediaBrowser.Controller/Entities/User.cs +++ b/MediaBrowser.Controller/Entities/User.cs @@ -5,7 +5,6 @@ using System.Threading.Tasks; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Configuration; -using MediaBrowser.Model.Connect; using MediaBrowser.Model.Serialization; using MediaBrowser.Model.Users; @@ -33,11 +32,6 @@ namespace MediaBrowser.Controller.Entities public string EasyPassword { get; set; } public string Salt { get; set; } - public string ConnectUserName { get; set; } - public string ConnectUserId { get; set; } - public UserLinkType? ConnectLinkType { get; set; } - public string ConnectAccessKey { get; set; } - // Strictly to remove IgnoreDataMember public override ItemImageInfo[] ImageInfos { diff --git a/MediaBrowser.Controller/Entities/UserView.cs b/MediaBrowser.Controller/Entities/UserView.cs index de4105df9..3e2191376 100644 --- a/MediaBrowser.Controller/Entities/UserView.cs +++ b/MediaBrowser.Controller/Entities/UserView.cs @@ -150,7 +150,6 @@ namespace MediaBrowser.Controller.Entities private static string[] OriginalFolderViewTypes = new string[] { - MediaBrowser.Model.Entities.CollectionType.Games, MediaBrowser.Model.Entities.CollectionType.Books, MediaBrowser.Model.Entities.CollectionType.MusicVideos, MediaBrowser.Model.Entities.CollectionType.HomeVideos, diff --git a/MediaBrowser.Controller/Entities/UserViewBuilder.cs b/MediaBrowser.Controller/Entities/UserViewBuilder.cs index 0b0134669..683218a9e 100644 --- a/MediaBrowser.Controller/Entities/UserViewBuilder.cs +++ b/MediaBrowser.Controller/Entities/UserViewBuilder.cs @@ -848,52 +848,6 @@ namespace MediaBrowser.Controller.Entities } } - if (query.MinPlayers.HasValue) - { - var filterValue = query.MinPlayers.Value; - - var game = item as Game; - - if (game != null) - { - var players = game.PlayersSupported ?? 1; - - var ok = players >= filterValue; - - if (!ok) - { - return false; - } - } - else - { - return false; - } - } - - if (query.MaxPlayers.HasValue) - { - var filterValue = query.MaxPlayers.Value; - - var game = item as Game; - - if (game != null) - { - var players = game.PlayersSupported ?? 1; - - var ok = players <= filterValue; - - if (!ok) - { - return false; - } - } - else - { - return false; - } - } - if (query.MinCommunityRating.HasValue) { var val = query.MinCommunityRating.Value; diff --git a/MediaBrowser.Controller/Entities/Video.cs b/MediaBrowser.Controller/Entities/Video.cs index 33a967758..31cd42975 100644 --- a/MediaBrowser.Controller/Entities/Video.cs +++ b/MediaBrowser.Controller/Entities/Video.cs @@ -305,7 +305,7 @@ namespace MediaBrowser.Controller.Entities private string GetUserDataKey(string providerId) { - var key = providerId + "-" + ExtraType.ToString().ToLower(); + var key = providerId + "-" + ExtraType.ToString().ToLowerInvariant(); // Make sure different trailers have their own data. if (RunTimeTicks.HasValue) diff --git a/MediaBrowser.Controller/IServerApplicationPaths.cs b/MediaBrowser.Controller/IServerApplicationPaths.cs index 2b43513b7..15d7e9f62 100644 --- a/MediaBrowser.Controller/IServerApplicationPaths.cs +++ b/MediaBrowser.Controller/IServerApplicationPaths.cs @@ -47,12 +47,6 @@ namespace MediaBrowser.Controller string MusicGenrePath { get; } /// <summary> - /// Gets the game genre path. - /// </summary> - /// <value>The game genre path.</value> - string GameGenrePath { get; } - - /// <summary> /// Gets the path to the Studio directory /// </summary> /// <value>The studio path.</value> diff --git a/MediaBrowser.Controller/Library/ILibraryManager.cs b/MediaBrowser.Controller/Library/ILibraryManager.cs index 9d404ba1a..60c183d04 100644 --- a/MediaBrowser.Controller/Library/ILibraryManager.cs +++ b/MediaBrowser.Controller/Library/ILibraryManager.cs @@ -89,13 +89,6 @@ namespace MediaBrowser.Controller.Library MusicGenre GetMusicGenre(string name); /// <summary> - /// Gets the game genre. - /// </summary> - /// <param name="name">The name.</param> - /// <returns>Task{GameGenre}.</returns> - GameGenre GetGameGenre(string name); - - /// <summary> /// Gets a Year /// </summary> /// <param name="value">The value.</param> @@ -521,8 +514,6 @@ namespace MediaBrowser.Controller.Library Guid GetMusicGenreId(string name); - Guid GetGameGenreId(string name); - Task AddVirtualFolder(string name, string collectionType, LibraryOptions options, bool refreshLibrary); Task RemoveVirtualFolder(string name, bool refreshLibrary); void AddMediaPath(string virtualFolderName, MediaPathInfo path); @@ -531,7 +522,6 @@ namespace MediaBrowser.Controller.Library QueryResult<Tuple<BaseItem, ItemCounts>> GetGenres(InternalItemsQuery query); QueryResult<Tuple<BaseItem, ItemCounts>> GetMusicGenres(InternalItemsQuery query); - QueryResult<Tuple<BaseItem, ItemCounts>> GetGameGenres(InternalItemsQuery query); QueryResult<Tuple<BaseItem, ItemCounts>> GetStudios(InternalItemsQuery query); QueryResult<Tuple<BaseItem, ItemCounts>> GetArtists(InternalItemsQuery query); QueryResult<Tuple<BaseItem, ItemCounts>> GetAlbumArtists(InternalItemsQuery query); diff --git a/MediaBrowser.Controller/Library/NameExtensions.cs b/MediaBrowser.Controller/Library/NameExtensions.cs index e2988a831..6b0b7e53a 100644 --- a/MediaBrowser.Controller/Library/NameExtensions.cs +++ b/MediaBrowser.Controller/Library/NameExtensions.cs @@ -1,7 +1,7 @@ using System; +using System.Linq; using System.Collections.Generic; using MediaBrowser.Controller.Extensions; -using MediaBrowser.Model.Extensions; namespace MediaBrowser.Controller.Library { @@ -14,13 +14,11 @@ namespace MediaBrowser.Controller.Library return string.Empty; } - //return name; return name.RemoveDiacritics(); } public static IEnumerable<string> DistinctNames(this IEnumerable<string> names) - { - return names.DistinctBy(RemoveDiacritics, StringComparer.OrdinalIgnoreCase); - } + => names.GroupBy(RemoveDiacritics, StringComparer.OrdinalIgnoreCase) + .Select(x => x.First()); } } diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index fc2b8f9c9..f5f147db1 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -136,7 +136,7 @@ namespace MediaBrowser.Controller.MediaEncoding return "libtheora"; } - return codec.ToLower(); + return codec.ToLowerInvariant(); } return "copy"; @@ -405,7 +405,7 @@ namespace MediaBrowser.Controller.MediaEncoding return "libopus"; } - return codec.ToLower(); + return codec.ToLowerInvariant(); } /// <summary> @@ -762,7 +762,7 @@ namespace MediaBrowser.Controller.MediaEncoding // vaapi does not support Baseline profile, force Constrained Baseline in this case, // which is compatible (and ugly) if (string.Equals(videoEncoder, "h264_vaapi", StringComparison.OrdinalIgnoreCase) && - profile != null && profile.ToLower().Contains("baseline")) + profile != null && profile.ToLowerInvariant().Contains("baseline")) { profile = "constrained_baseline"; } @@ -2175,7 +2175,7 @@ namespace MediaBrowser.Controller.MediaEncoding { if (string.Equals(encodingOptions.HardwareAccelerationType, "qsv", StringComparison.OrdinalIgnoreCase)) { - switch (videoStream.Codec.ToLower()) + switch (videoStream.Codec.ToLowerInvariant()) { case "avc": case "h264": @@ -2215,7 +2215,7 @@ namespace MediaBrowser.Controller.MediaEncoding else if (string.Equals(encodingOptions.HardwareAccelerationType, "nvenc", StringComparison.OrdinalIgnoreCase)) { - switch (videoStream.Codec.ToLower()) + switch (videoStream.Codec.ToLowerInvariant()) { case "avc": case "h264": @@ -2254,7 +2254,7 @@ namespace MediaBrowser.Controller.MediaEncoding else if (string.Equals(encodingOptions.HardwareAccelerationType, "mediacodec", StringComparison.OrdinalIgnoreCase)) { - switch (videoStream.Codec.ToLower()) + switch (videoStream.Codec.ToLowerInvariant()) { case "avc": case "h264": @@ -2299,7 +2299,7 @@ namespace MediaBrowser.Controller.MediaEncoding else if (string.Equals(encodingOptions.HardwareAccelerationType, "omx", StringComparison.OrdinalIgnoreCase)) { - switch (videoStream.Codec.ToLower()) + switch (videoStream.Codec.ToLowerInvariant()) { case "avc": case "h264": @@ -2324,7 +2324,7 @@ namespace MediaBrowser.Controller.MediaEncoding return "-hwaccel dxva2"; } - switch (videoStream.Codec.ToLower()) + switch (videoStream.Codec.ToLowerInvariant()) { case "avc": case "h264": diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs b/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs index 1fe8856cc..916d691b8 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs @@ -10,19 +10,13 @@ using MediaBrowser.Model.Entities; using MediaBrowser.Model.IO; using MediaBrowser.Model.MediaInfo; using MediaBrowser.Model.Session; -using Microsoft.Extensions.Logging; -using System.IO; using MediaBrowser.Model.Net; -using MediaBrowser.Controller.Library; -using System.Threading.Tasks; namespace MediaBrowser.Controller.MediaEncoding { // For now, a common base class until the API and MediaEncoding classes are unified public class EncodingJobInfo { - protected readonly IMediaSourceManager MediaSourceManager; - public MediaStream VideoStream { get; set; } public VideoType VideoType { get; set; } public Dictionary<string, string> RemoteHttpHeaders { get; set; } @@ -49,7 +43,6 @@ namespace MediaBrowser.Controller.MediaEncoding public string OutputFilePath { get; set; } public string MimeType { get; set; } - public long? EncodingDurationTicks { get; set; } public string GetMimeType(string outputPath, bool enableStreamDefault = true) { @@ -68,7 +61,12 @@ namespace MediaBrowser.Controller.MediaEncoding { if (_transcodeReasons == null) { - _transcodeReasons = (BaseRequest.TranscodeReasons ?? string.Empty) + if (BaseRequest.TranscodeReasons == null) + { + return Array.Empty<TranscodeReason>(); + } + + _transcodeReasons = BaseRequest.TranscodeReasons .Split(',') .Where(i => !string.IsNullOrEmpty(i)) .Select(v => (TranscodeReason)Enum.Parse(typeof(TranscodeReason), v, true)) @@ -98,7 +96,8 @@ namespace MediaBrowser.Controller.MediaEncoding get { // For live tv + in progress recordings - if (string.Equals(InputContainer, "mpegts", StringComparison.OrdinalIgnoreCase) || string.Equals(InputContainer, "ts", StringComparison.OrdinalIgnoreCase)) + if (string.Equals(InputContainer, "mpegts", StringComparison.OrdinalIgnoreCase) + || string.Equals(InputContainer, "ts", StringComparison.OrdinalIgnoreCase)) { if (!MediaSource.RunTimeTicks.HasValue) { @@ -155,15 +154,7 @@ namespace MediaBrowser.Controller.MediaEncoding } } - if (forceDeinterlaceIfSourceIsInterlaced) - { - if (isInputInterlaced) - { - return true; - } - } - - return false; + return forceDeinterlaceIfSourceIsInterlaced && isInputInterlaced; } public string[] GetRequestedProfiles(string codec) @@ -211,7 +202,8 @@ namespace MediaBrowser.Controller.MediaEncoding if (!string.IsNullOrEmpty(codec)) { var value = BaseRequest.GetOption(codec, "maxrefframes"); - if (!string.IsNullOrEmpty(value) && int.TryParse(value, NumberStyles.Any, CultureInfo.InvariantCulture, out var result)) + if (!string.IsNullOrEmpty(value) + && int.TryParse(value, NumberStyles.Any, CultureInfo.InvariantCulture, out var result)) { return result; } @@ -230,7 +222,8 @@ namespace MediaBrowser.Controller.MediaEncoding if (!string.IsNullOrEmpty(codec)) { var value = BaseRequest.GetOption(codec, "videobitdepth"); - if (!string.IsNullOrEmpty(value) && int.TryParse(value, NumberStyles.Any, CultureInfo.InvariantCulture, out var result)) + if (!string.IsNullOrEmpty(value) + && int.TryParse(value, NumberStyles.Any, CultureInfo.InvariantCulture, out var result)) { return result; } @@ -249,7 +242,8 @@ namespace MediaBrowser.Controller.MediaEncoding if (!string.IsNullOrEmpty(codec)) { var value = BaseRequest.GetOption(codec, "audiobitdepth"); - if (!string.IsNullOrEmpty(value) && int.TryParse(value, NumberStyles.Any, CultureInfo.InvariantCulture, out var result)) + if (!string.IsNullOrEmpty(value) + && int.TryParse(value, NumberStyles.Any, CultureInfo.InvariantCulture, out var result)) { return result; } @@ -264,6 +258,7 @@ namespace MediaBrowser.Controller.MediaEncoding { return BaseRequest.MaxAudioChannels; } + if (BaseRequest.AudioChannels.HasValue) { return BaseRequest.AudioChannels; @@ -272,7 +267,8 @@ namespace MediaBrowser.Controller.MediaEncoding if (!string.IsNullOrEmpty(codec)) { var value = BaseRequest.GetOption(codec, "audiochannels"); - if (!string.IsNullOrEmpty(value) && int.TryParse(value, NumberStyles.Any, CultureInfo.InvariantCulture, out var result)) + if (!string.IsNullOrEmpty(value) + && int.TryParse(value, NumberStyles.Any, CultureInfo.InvariantCulture, out var result)) { return result; } @@ -294,7 +290,8 @@ namespace MediaBrowser.Controller.MediaEncoding SupportedSubtitleCodecs = Array.Empty<string>(); } - public bool IsSegmentedLiveStream => TranscodingType != TranscodingJobType.Progressive && !RunTimeTicks.HasValue; + public bool IsSegmentedLiveStream + => TranscodingType != TranscodingJobType.Progressive && !RunTimeTicks.HasValue; public bool EnableBreakOnNonKeyFrames(string videoCodec) { @@ -428,11 +425,12 @@ namespace MediaBrowser.Controller.MediaEncoding { if (BaseRequest.Static || string.Equals(OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase)) { - return VideoStream == null ? null : VideoStream.Level; + return VideoStream?.Level; } var level = GetRequestedLevel(ActualOutputVideoCodec); - if (!string.IsNullOrEmpty(level) && double.TryParse(level, NumberStyles.Any, CultureInfo.InvariantCulture, out var result)) + if (!string.IsNullOrEmpty(level) + && double.TryParse(level, NumberStyles.Any, CultureInfo.InvariantCulture, out var result)) { return result; } @@ -450,7 +448,7 @@ namespace MediaBrowser.Controller.MediaEncoding { if (BaseRequest.Static || string.Equals(OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase)) { - return VideoStream == null ? null : VideoStream.BitDepth; + return VideoStream?.BitDepth; } return null; @@ -467,7 +465,7 @@ namespace MediaBrowser.Controller.MediaEncoding { if (BaseRequest.Static || string.Equals(OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase)) { - return VideoStream == null ? null : VideoStream.RefFrames; + return VideoStream?.RefFrames; } return null; @@ -494,13 +492,14 @@ namespace MediaBrowser.Controller.MediaEncoding { get { - var defaultValue = string.Equals(OutputContainer, "m2ts", StringComparison.OrdinalIgnoreCase) ? + if (BaseRequest.Static) + { + return InputTimestamp; + } + + return string.Equals(OutputContainer, "m2ts", StringComparison.OrdinalIgnoreCase) ? TransportStreamTimestamp.Valid : TransportStreamTimestamp.None; - - return !BaseRequest.Static - ? defaultValue - : InputTimestamp; } } @@ -513,7 +512,7 @@ namespace MediaBrowser.Controller.MediaEncoding { if (BaseRequest.Static || string.Equals(OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase)) { - return VideoStream == null ? null : VideoStream.PacketLength; + return VideoStream?.PacketLength; } return null; @@ -529,7 +528,7 @@ namespace MediaBrowser.Controller.MediaEncoding { if (BaseRequest.Static || string.Equals(OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase)) { - return VideoStream == null ? null : VideoStream.Profile; + return VideoStream?.Profile; } var requestedProfile = GetRequestedProfiles(ActualOutputVideoCodec).FirstOrDefault(); @@ -542,42 +541,13 @@ namespace MediaBrowser.Controller.MediaEncoding } } - /// <summary> - /// Predicts the audio sample rate that will be in the output stream - /// </summary> - public string TargetVideoRange - { - get - { - if (BaseRequest.Static || string.Equals(OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase)) - { - return VideoStream == null ? null : VideoStream.VideoRange; - } - - return "SDR"; - } - } - - public string TargetAudioProfile - { - get - { - if (BaseRequest.Static || string.Equals(OutputAudioCodec, "copy", StringComparison.OrdinalIgnoreCase)) - { - return AudioStream == null ? null : AudioStream.Profile; - } - - return null; - } - } - public string TargetVideoCodecTag { get { if (BaseRequest.Static || string.Equals(OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase)) { - return VideoStream == null ? null : VideoStream.CodecTag; + return VideoStream?.CodecTag; } return null; @@ -590,7 +560,7 @@ namespace MediaBrowser.Controller.MediaEncoding { if (BaseRequest.Static || string.Equals(OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase)) { - return VideoStream == null ? null : VideoStream.IsAnamorphic; + return VideoStream?.IsAnamorphic; } return false; @@ -605,14 +575,7 @@ namespace MediaBrowser.Controller.MediaEncoding if (string.Equals(codec, "copy", StringComparison.OrdinalIgnoreCase)) { - var stream = VideoStream; - - if (stream != null) - { - return stream.Codec; - } - - return null; + return VideoStream?.Codec; } return codec; @@ -627,14 +590,7 @@ namespace MediaBrowser.Controller.MediaEncoding if (string.Equals(codec, "copy", StringComparison.OrdinalIgnoreCase)) { - var stream = AudioStream; - - if (stream != null) - { - return stream.Codec; - } - - return null; + return AudioStream?.Codec; } return codec; @@ -647,7 +603,7 @@ namespace MediaBrowser.Controller.MediaEncoding { if (BaseRequest.Static || string.Equals(OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase)) { - return VideoStream == null ? (bool?)null : VideoStream.IsInterlaced; + return VideoStream?.IsInterlaced; } if (DeInterlace(ActualOutputVideoCodec, true)) @@ -655,7 +611,7 @@ namespace MediaBrowser.Controller.MediaEncoding return false; } - return VideoStream == null ? (bool?)null : VideoStream.IsInterlaced; + return VideoStream?.IsInterlaced; } } @@ -665,7 +621,7 @@ namespace MediaBrowser.Controller.MediaEncoding { if (BaseRequest.Static || string.Equals(OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase)) { - return VideoStream == null ? null : VideoStream.IsAVC; + return VideoStream?.IsAVC; } return false; diff --git a/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs b/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs index 48055a37e..057e43910 100644 --- a/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs +++ b/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs @@ -82,28 +82,6 @@ namespace MediaBrowser.Controller.MediaEncoding /// <returns>System.String.</returns> string GetTimeParameter(long ticks); - /// <summary> - /// Encodes the audio. - /// </summary> - /// <param name="options">The options.</param> - /// <param name="progress">The progress.</param> - /// <param name="cancellationToken">The cancellation token.</param> - /// <returns>Task.</returns> - Task<string> EncodeAudio(EncodingJobOptions options, - IProgress<double> progress, - CancellationToken cancellationToken); - - /// <summary> - /// Encodes the video. - /// </summary> - /// <param name="options">The options.</param> - /// <param name="progress">The progress.</param> - /// <param name="cancellationToken">The cancellation token.</param> - /// <returns>Task<System.String>.</returns> - Task<string> EncodeVideo(EncodingJobOptions options, - IProgress<double> progress, - CancellationToken cancellationToken); - Task ConvertImage(string inputPath, string outputPath); /// <summary> diff --git a/MediaBrowser.Controller/Persistence/IItemRepository.cs b/MediaBrowser.Controller/Persistence/IItemRepository.cs index 0d086fd7e..5156fce11 100644 --- a/MediaBrowser.Controller/Persistence/IItemRepository.cs +++ b/MediaBrowser.Controller/Persistence/IItemRepository.cs @@ -143,13 +143,11 @@ namespace MediaBrowser.Controller.Persistence QueryResult<Tuple<BaseItem, ItemCounts>> GetGenres(InternalItemsQuery query); QueryResult<Tuple<BaseItem, ItemCounts>> GetMusicGenres(InternalItemsQuery query); - QueryResult<Tuple<BaseItem, ItemCounts>> GetGameGenres(InternalItemsQuery query); 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); - List<string> GetGameGenreNames(); List<string> GetMusicGenreNames(); List<string> GetStudioNames(); List<string> GetGenreNames(); diff --git a/MediaBrowser.Controller/Providers/GameInfo.cs b/MediaBrowser.Controller/Providers/GameInfo.cs deleted file mode 100644 index 1f3eb40b7..000000000 --- a/MediaBrowser.Controller/Providers/GameInfo.cs +++ /dev/null @@ -1,11 +0,0 @@ -namespace MediaBrowser.Controller.Providers -{ - public class GameInfo : ItemLookupInfo - { - /// <summary> - /// Gets or sets the game system. - /// </summary> - /// <value>The game system.</value> - public string GameSystem { get; set; } - } -} diff --git a/MediaBrowser.Controller/Providers/GameSystemInfo.cs b/MediaBrowser.Controller/Providers/GameSystemInfo.cs deleted file mode 100644 index 796486b82..000000000 --- a/MediaBrowser.Controller/Providers/GameSystemInfo.cs +++ /dev/null @@ -1,11 +0,0 @@ -namespace MediaBrowser.Controller.Providers -{ - public class GameSystemInfo : ItemLookupInfo - { - /// <summary> - /// Gets or sets the path. - /// </summary> - /// <value>The path.</value> - public string Path { get; set; } - } -} diff --git a/MediaBrowser.LocalMetadata/Images/LocalImageProvider.cs b/MediaBrowser.LocalMetadata/Images/LocalImageProvider.cs index 0a4928ed7..1a7654bfd 100644 --- a/MediaBrowser.LocalMetadata/Images/LocalImageProvider.cs +++ b/MediaBrowser.LocalMetadata/Images/LocalImageProvider.cs @@ -128,7 +128,6 @@ namespace MediaBrowser.LocalMetadata.Images var added = false; var isEpisode = item is Episode; var isSong = item.GetType() == typeof(Audio); - var isGame = item is Game; var isPerson = item is Person; // Logo @@ -157,7 +156,7 @@ namespace MediaBrowser.LocalMetadata.Images added = AddImage(files, images, "disc", imagePrefix, isInMixedFolder, ImageType.Disc); } } - else if (isGame || item is Video || item is BoxSet) + else if (item is Video || item is BoxSet) { added = AddImage(files, images, "disc", imagePrefix, isInMixedFolder, ImageType.Disc); @@ -172,19 +171,6 @@ namespace MediaBrowser.LocalMetadata.Images } } - if (isGame) - { - AddImage(files, images, "box", imagePrefix, isInMixedFolder, ImageType.Box); - AddImage(files, images, "menu", imagePrefix, isInMixedFolder, ImageType.Menu); - - added = AddImage(files, images, "back", imagePrefix, isInMixedFolder, ImageType.BoxRear); - - if (!added) - { - added = AddImage(files, images, "boxrear", imagePrefix, isInMixedFolder, ImageType.BoxRear); - } - } - // Banner if (!isEpisode && !isSong && !isPerson) { @@ -417,7 +403,7 @@ namespace MediaBrowser.LocalMetadata.Images var seriesFiles = GetFiles(series, false, directoryService).ToList(); // Try using the season name - var prefix = season.Name.ToLower().Replace(" ", string.Empty); + var prefix = season.Name.ToLowerInvariant().Replace(" ", string.Empty); var filenamePrefixes = new List<string> { prefix }; diff --git a/MediaBrowser.LocalMetadata/Parsers/GameSystemXmlParser.cs b/MediaBrowser.LocalMetadata/Parsers/GameSystemXmlParser.cs deleted file mode 100644 index a4997270f..000000000 --- a/MediaBrowser.LocalMetadata/Parsers/GameSystemXmlParser.cs +++ /dev/null @@ -1,66 +0,0 @@ -using System.Threading; -using System.Threading.Tasks; -using System.Xml; -using MediaBrowser.Controller.Entities; -using MediaBrowser.Controller.Providers; -using MediaBrowser.Model.Entities; -using MediaBrowser.Model.IO; -using MediaBrowser.Model.Xml; -using Microsoft.Extensions.Logging; - -namespace MediaBrowser.LocalMetadata.Parsers -{ - public class GameSystemXmlParser : BaseItemXmlParser<GameSystem> - { - public Task FetchAsync(MetadataResult<GameSystem> item, string metadataFile, CancellationToken cancellationToken) - { - Fetch(item, metadataFile, cancellationToken); - - cancellationToken.ThrowIfCancellationRequested(); - - return Task.CompletedTask; - } - - /// <summary> - /// Fetches the data from XML node. - /// </summary> - /// <param name="reader">The reader.</param> - /// <param name="result">The result.</param> - protected override void FetchDataFromXmlNode(XmlReader reader, MetadataResult<GameSystem> result) - { - var item = result.Item; - - switch (reader.Name) - { - case "GameSystem": - { - var val = reader.ReadElementContentAsString(); - if (!string.IsNullOrWhiteSpace(val)) - { - item.GameSystemName = val; - } - break; - } - - case "GamesDbId": - { - var val = reader.ReadElementContentAsString(); - if (!string.IsNullOrWhiteSpace(val)) - { - item.SetProviderId(MetadataProviders.Gamesdb, val); - } - break; - } - - - default: - base.FetchDataFromXmlNode(reader, result); - break; - } - } - - public GameSystemXmlParser(ILogger logger, IProviderManager providerManager, IXmlReaderSettingsFactory xmlReaderSettingsFactory, IFileSystem fileSystem) : base(logger, providerManager, xmlReaderSettingsFactory, fileSystem) - { - } - } -} diff --git a/MediaBrowser.LocalMetadata/Parsers/GameXmlParser.cs b/MediaBrowser.LocalMetadata/Parsers/GameXmlParser.cs deleted file mode 100644 index df7c51f27..000000000 --- a/MediaBrowser.LocalMetadata/Parsers/GameXmlParser.cs +++ /dev/null @@ -1,85 +0,0 @@ -using System.Globalization; -using System.Threading; -using System.Threading.Tasks; -using System.Xml; -using MediaBrowser.Controller.Entities; -using MediaBrowser.Controller.Providers; -using MediaBrowser.Model.Entities; -using MediaBrowser.Model.IO; -using MediaBrowser.Model.Xml; -using Microsoft.Extensions.Logging; - -namespace MediaBrowser.LocalMetadata.Parsers -{ - /// <summary> - /// Class EpisodeXmlParser - /// </summary> - public class GameXmlParser : BaseItemXmlParser<Game> - { - private readonly CultureInfo _usCulture = new CultureInfo("en-US"); - - public Task FetchAsync(MetadataResult<Game> item, string metadataFile, CancellationToken cancellationToken) - { - Fetch(item, metadataFile, cancellationToken); - - cancellationToken.ThrowIfCancellationRequested(); - - return Task.CompletedTask; - } - - /// <summary> - /// Fetches the data from XML node. - /// </summary> - /// <param name="reader">The reader.</param> - /// <param name="result">The result.</param> - protected override void FetchDataFromXmlNode(XmlReader reader, MetadataResult<Game> result) - { - var item = result.Item; - - switch (reader.Name) - { - case "GameSystem": - { - var val = reader.ReadElementContentAsString(); - if (!string.IsNullOrWhiteSpace(val)) - { - item.GameSystem = val; - } - break; - } - - case "GamesDbId": - { - var val = reader.ReadElementContentAsString(); - if (!string.IsNullOrWhiteSpace(val)) - { - item.SetProviderId(MetadataProviders.Gamesdb, val); - } - break; - } - - case "Players": - { - var val = reader.ReadElementContentAsString(); - if (!string.IsNullOrWhiteSpace(val)) - { - if (int.TryParse(val, NumberStyles.Integer, _usCulture, out var num)) - { - item.PlayersSupported = num; - } - } - break; - } - - - default: - base.FetchDataFromXmlNode(reader, result); - break; - } - } - - public GameXmlParser(ILogger logger, IProviderManager providerManager, IXmlReaderSettingsFactory xmlReaderSettingsFactory, IFileSystem fileSystem) : base(logger, providerManager, xmlReaderSettingsFactory, fileSystem) - { - } - } -} diff --git a/MediaBrowser.LocalMetadata/Providers/GameSystemXmlProvider.cs b/MediaBrowser.LocalMetadata/Providers/GameSystemXmlProvider.cs deleted file mode 100644 index 62f31d4fa..000000000 --- a/MediaBrowser.LocalMetadata/Providers/GameSystemXmlProvider.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System.IO; -using System.Threading; -using MediaBrowser.Controller.Entities; -using MediaBrowser.Controller.Providers; -using MediaBrowser.LocalMetadata.Parsers; -using MediaBrowser.Model.IO; -using MediaBrowser.Model.Xml; -using Microsoft.Extensions.Logging; - -namespace MediaBrowser.LocalMetadata.Providers -{ - public class GameSystemXmlProvider : BaseXmlProvider<GameSystem> - { - private readonly ILogger _logger; - private readonly IProviderManager _providerManager; - private readonly IXmlReaderSettingsFactory _xmlSettings; - - public GameSystemXmlProvider(IFileSystem fileSystem, ILogger logger, IProviderManager providerManager, IXmlReaderSettingsFactory xmlSettings) - : base(fileSystem) - { - _logger = logger; - _providerManager = providerManager; - _xmlSettings = xmlSettings; - } - - protected override void Fetch(MetadataResult<GameSystem> result, string path, CancellationToken cancellationToken) - { - new GameSystemXmlParser(_logger, _providerManager, _xmlSettings, FileSystem).Fetch(result, path, cancellationToken); - } - - protected override FileSystemMetadata GetXmlFile(ItemInfo info, IDirectoryService directoryService) - { - return directoryService.GetFile(Path.Combine(info.Path, "gamesystem.xml")); - } - } -} diff --git a/MediaBrowser.LocalMetadata/Providers/GameXmlProvider.cs b/MediaBrowser.LocalMetadata/Providers/GameXmlProvider.cs deleted file mode 100644 index acdbb0a29..000000000 --- a/MediaBrowser.LocalMetadata/Providers/GameXmlProvider.cs +++ /dev/null @@ -1,39 +0,0 @@ -using System.IO; -using System.Threading; -using MediaBrowser.Controller.Entities; -using MediaBrowser.Controller.Providers; -using MediaBrowser.LocalMetadata.Parsers; -using MediaBrowser.Model.IO; -using MediaBrowser.Model.Xml; -using Microsoft.Extensions.Logging; - -namespace MediaBrowser.LocalMetadata.Providers -{ - public class GameXmlProvider : BaseXmlProvider<Game> - { - private readonly ILogger _logger; - private readonly IProviderManager _providerManager; - private readonly IXmlReaderSettingsFactory _xmlSettings; - - public GameXmlProvider(IFileSystem fileSystem, ILogger logger, IProviderManager providerManager, IXmlReaderSettingsFactory xmlSettings) - : base(fileSystem) - { - _logger = logger; - _providerManager = providerManager; - _xmlSettings = xmlSettings; - } - - protected override void Fetch(MetadataResult<Game> result, string path, CancellationToken cancellationToken) - { - new GameXmlParser(_logger, _providerManager, _xmlSettings, FileSystem).Fetch(result, path, cancellationToken); - } - - protected override FileSystemMetadata GetXmlFile(ItemInfo info, IDirectoryService directoryService) - { - var specificFile = Path.ChangeExtension(info.Path, ".xml"); - var file = FileSystem.GetFileInfo(specificFile); - - return info.IsInMixedFolder || file.Exists ? file : FileSystem.GetFileInfo(Path.Combine(Path.GetDirectoryName(info.Path), "game.xml")); - } - } -} diff --git a/MediaBrowser.LocalMetadata/Savers/BaseXmlSaver.cs b/MediaBrowser.LocalMetadata/Savers/BaseXmlSaver.cs index 8a291e6a8..438b84252 100644 --- a/MediaBrowser.LocalMetadata/Savers/BaseXmlSaver.cs +++ b/MediaBrowser.LocalMetadata/Savers/BaseXmlSaver.cs @@ -172,7 +172,7 @@ namespace MediaBrowser.LocalMetadata.Savers writer.WriteElementString("Added", item.DateCreated.ToLocalTime().ToString("G")); - writer.WriteElementString("LockData", item.IsLocked.ToString().ToLower()); + writer.WriteElementString("LockData", item.IsLocked.ToString(CultureInfo.InvariantCulture).ToLowerInvariant()); if (item.LockedFields.Length > 0) { @@ -410,7 +410,9 @@ namespace MediaBrowser.LocalMetadata.Savers writer.WriteStartElement("Share"); writer.WriteElementString("UserId", share.UserId); - writer.WriteElementString("CanEdit", share.CanEdit.ToString().ToLower()); + writer.WriteElementString( + "CanEdit", + share.CanEdit.ToString(CultureInfo.InvariantCulture).ToLowerInvariant()); writer.WriteEndElement(); } diff --git a/MediaBrowser.LocalMetadata/Savers/GameSystemXmlSaver.cs b/MediaBrowser.LocalMetadata/Savers/GameSystemXmlSaver.cs deleted file mode 100644 index cf123171a..000000000 --- a/MediaBrowser.LocalMetadata/Savers/GameSystemXmlSaver.cs +++ /dev/null @@ -1,48 +0,0 @@ -using System.IO; -using System.Xml; -using MediaBrowser.Controller.Configuration; -using MediaBrowser.Controller.Entities; -using MediaBrowser.Controller.Library; -using MediaBrowser.Model.IO; -using MediaBrowser.Model.Xml; -using Microsoft.Extensions.Logging; - -namespace MediaBrowser.LocalMetadata.Savers -{ - public class GameSystemXmlSaver : BaseXmlSaver - { - public GameSystemXmlSaver(IFileSystem fileSystem, IServerConfigurationManager configurationManager, ILibraryManager libraryManager, IUserManager userManager, IUserDataManager userDataManager, ILogger logger, IXmlReaderSettingsFactory xmlReaderSettingsFactory) : base(fileSystem, configurationManager, libraryManager, userManager, userDataManager, logger, xmlReaderSettingsFactory) - { - } - - public override bool IsEnabledFor(BaseItem item, ItemUpdateType updateType) - { - if (!item.SupportsLocalMetadata) - { - return false; - } - - return item is GameSystem && updateType >= ItemUpdateType.MetadataDownload; - } - - protected override void WriteCustomElements(BaseItem item, XmlWriter writer) - { - var gameSystem = (GameSystem)item; - - if (!string.IsNullOrEmpty(gameSystem.GameSystemName)) - { - writer.WriteElementString("GameSystem", gameSystem.GameSystemName); - } - } - - protected override string GetLocalSavePath(BaseItem item) - { - return Path.Combine(item.Path, "gamesystem.xml"); - } - - protected override string GetRootElementName(BaseItem item) - { - return "Item"; - } - } -} diff --git a/MediaBrowser.LocalMetadata/Savers/GameXmlSaver.cs b/MediaBrowser.LocalMetadata/Savers/GameXmlSaver.cs deleted file mode 100644 index 3b7929618..000000000 --- a/MediaBrowser.LocalMetadata/Savers/GameXmlSaver.cs +++ /dev/null @@ -1,68 +0,0 @@ -using System.Globalization; -using System.IO; -using System.Xml; -using MediaBrowser.Controller.Configuration; -using MediaBrowser.Controller.Entities; -using MediaBrowser.Controller.Library; -using MediaBrowser.Model.IO; -using MediaBrowser.Model.Xml; -using Microsoft.Extensions.Logging; - -namespace MediaBrowser.LocalMetadata.Savers -{ - /// <summary> - /// Saves game.xml for games - /// </summary> - public class GameXmlSaver : BaseXmlSaver - { - private readonly CultureInfo UsCulture = new CultureInfo("en-US"); - - public override bool IsEnabledFor(BaseItem item, ItemUpdateType updateType) - { - if (!item.SupportsLocalMetadata) - { - return false; - } - - return item is Game && updateType >= ItemUpdateType.MetadataDownload; - } - - protected override void WriteCustomElements(BaseItem item, XmlWriter writer) - { - var game = (Game)item; - - if (!string.IsNullOrEmpty(game.GameSystem)) - { - writer.WriteElementString("GameSystem", game.GameSystem); - } - if (game.PlayersSupported.HasValue) - { - writer.WriteElementString("Players", game.PlayersSupported.Value.ToString(UsCulture)); - } - } - - protected override string GetLocalSavePath(BaseItem item) - { - return GetGameSavePath((Game)item); - } - - protected override string GetRootElementName(BaseItem item) - { - return "Item"; - } - - public static string GetGameSavePath(Game item) - { - if (item.IsInMixedFolder) - { - return Path.ChangeExtension(item.Path, ".xml"); - } - - return Path.Combine(item.ContainingFolderPath, "game.xml"); - } - - public GameXmlSaver(IFileSystem fileSystem, IServerConfigurationManager configurationManager, ILibraryManager libraryManager, IUserManager userManager, IUserDataManager userDataManager, ILogger logger, IXmlReaderSettingsFactory xmlReaderSettingsFactory) : base(fileSystem, configurationManager, libraryManager, userManager, userDataManager, logger, xmlReaderSettingsFactory) - { - } - } -} diff --git a/MediaBrowser.LocalMetadata/Savers/PersonXmlSaver.cs b/MediaBrowser.LocalMetadata/Savers/PersonXmlSaver.cs deleted file mode 100644 index 7dd2c589f..000000000 --- a/MediaBrowser.LocalMetadata/Savers/PersonXmlSaver.cs +++ /dev/null @@ -1,47 +0,0 @@ -namespace MediaBrowser.LocalMetadata.Savers -{ - ///// <summary> - ///// Class PersonXmlSaver - ///// </summary> - //public class PersonXmlSaver : BaseXmlSaver - //{ - // public override bool IsEnabledFor(IHasMetadata item, ItemUpdateType updateType) - // { - // if (!item.SupportsLocalMetadata) - // { - // return false; - // } - - // return item is Person && updateType >= ItemUpdateType.MetadataDownload; - // } - - // protected override List<string> GetTagsUsed() - // { - // var list = new List<string> - // { - // "PlaceOfBirth" - // }; - - // return list; - // } - - // protected override void WriteCustomElements(IHasMetadata item, XmlWriter writer) - // { - // var person = (Person)item; - - // if (person.ProductionLocations.Count > 0) - // { - // writer.WriteElementString("PlaceOfBirth", person.ProductionLocations[0]); - // } - // } - - // protected override string GetLocalSavePath(IHasMetadata item) - // { - // return Path.Combine(item.Path, "person.xml"); - // } - - // public PersonXmlSaver(IFileSystem fileSystem, IServerConfigurationManager configurationManager, ILibraryManager libraryManager, IUserManager userManager, IUserDataManager userDataManager, ILogger logger, IXmlReaderSettingsFactory xmlReaderSettingsFactory) : base(fileSystem, configurationManager, libraryManager, userManager, userDataManager, logger, xmlReaderSettingsFactory) - // { - // } - //} -} diff --git a/MediaBrowser.MediaEncoding/Encoder/AudioEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/AudioEncoder.cs deleted file mode 100644 index d5773fe31..000000000 --- a/MediaBrowser.MediaEncoding/Encoder/AudioEncoder.cs +++ /dev/null @@ -1,58 +0,0 @@ -using System; -using MediaBrowser.Controller.Configuration; -using MediaBrowser.Controller.Library; -using MediaBrowser.Controller.MediaEncoding; -using MediaBrowser.Controller.Session; -using MediaBrowser.Model.Diagnostics; -using MediaBrowser.Model.IO; -using Microsoft.Extensions.Logging; - -namespace MediaBrowser.MediaEncoding.Encoder -{ - public class AudioEncoder : BaseEncoder - { - public AudioEncoder(MediaEncoder mediaEncoder, ILogger logger, IServerConfigurationManager configurationManager, IFileSystem fileSystem, IIsoManager isoManager, ILibraryManager libraryManager, ISessionManager sessionManager, ISubtitleEncoder subtitleEncoder, IMediaSourceManager mediaSourceManager, IProcessFactory processFactory) : base(mediaEncoder, logger, configurationManager, fileSystem, isoManager, libraryManager, sessionManager, subtitleEncoder, mediaSourceManager, processFactory) - { - } - - protected override string GetCommandLineArguments(EncodingJob state) - { - var encodingOptions = GetEncodingOptions(); - - return EncodingHelper.GetProgressiveAudioFullCommandLine(state, encodingOptions, state.OutputFilePath); - } - - protected override string GetOutputFileExtension(EncodingJob state) - { - var ext = base.GetOutputFileExtension(state); - - if (!string.IsNullOrEmpty(ext)) - { - return ext; - } - - var audioCodec = state.Options.AudioCodec; - - if (string.Equals("aac", audioCodec, StringComparison.OrdinalIgnoreCase)) - { - return ".aac"; - } - if (string.Equals("mp3", audioCodec, StringComparison.OrdinalIgnoreCase)) - { - return ".mp3"; - } - if (string.Equals("vorbis", audioCodec, StringComparison.OrdinalIgnoreCase)) - { - return ".ogg"; - } - if (string.Equals("wma", audioCodec, StringComparison.OrdinalIgnoreCase)) - { - return ".wma"; - } - - return null; - } - - protected override bool IsVideoEncoder => false; - } -} diff --git a/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs deleted file mode 100644 index d3c44f5eb..000000000 --- a/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs +++ /dev/null @@ -1,372 +0,0 @@ -using System; -using System.Globalization; -using System.IO; -using System.Text; -using System.Threading; -using System.Threading.Tasks; -using MediaBrowser.Common.Configuration; -using MediaBrowser.Controller.Configuration; -using MediaBrowser.Controller.Library; -using MediaBrowser.Controller.MediaEncoding; -using MediaBrowser.Controller.Session; -using MediaBrowser.Model.Configuration; -using MediaBrowser.Model.Diagnostics; -using MediaBrowser.Model.Entities; -using MediaBrowser.Model.IO; -using MediaBrowser.Model.MediaInfo; -using Microsoft.Extensions.Logging; - -namespace MediaBrowser.MediaEncoding.Encoder -{ - public abstract class BaseEncoder - { - protected readonly MediaEncoder MediaEncoder; - protected readonly ILogger Logger; - protected readonly IServerConfigurationManager ConfigurationManager; - protected readonly IFileSystem FileSystem; - protected readonly IIsoManager IsoManager; - protected readonly ILibraryManager LibraryManager; - protected readonly ISessionManager SessionManager; - protected readonly ISubtitleEncoder SubtitleEncoder; - protected readonly IMediaSourceManager MediaSourceManager; - protected IProcessFactory ProcessFactory; - - protected readonly CultureInfo UsCulture = new CultureInfo("en-US"); - - protected EncodingHelper EncodingHelper; - - protected BaseEncoder(MediaEncoder mediaEncoder, - ILogger logger, - IServerConfigurationManager configurationManager, - IFileSystem fileSystem, - IIsoManager isoManager, - ILibraryManager libraryManager, - ISessionManager sessionManager, - ISubtitleEncoder subtitleEncoder, - IMediaSourceManager mediaSourceManager, IProcessFactory processFactory) - { - MediaEncoder = mediaEncoder; - Logger = logger; - ConfigurationManager = configurationManager; - FileSystem = fileSystem; - IsoManager = isoManager; - LibraryManager = libraryManager; - SessionManager = sessionManager; - SubtitleEncoder = subtitleEncoder; - MediaSourceManager = mediaSourceManager; - ProcessFactory = processFactory; - - EncodingHelper = new EncodingHelper(MediaEncoder, FileSystem, SubtitleEncoder); - } - - public async Task<EncodingJob> Start(EncodingJobOptions options, - IProgress<double> progress, - CancellationToken cancellationToken) - { - var encodingJob = await new EncodingJobFactory(Logger, LibraryManager, MediaSourceManager, ConfigurationManager, MediaEncoder) - .CreateJob(options, EncodingHelper, IsVideoEncoder, progress, cancellationToken).ConfigureAwait(false); - - encodingJob.OutputFilePath = GetOutputFilePath(encodingJob); - Directory.CreateDirectory(Path.GetDirectoryName(encodingJob.OutputFilePath)); - - encodingJob.ReadInputAtNativeFramerate = options.ReadInputAtNativeFramerate; - - await AcquireResources(encodingJob, cancellationToken).ConfigureAwait(false); - - var commandLineArgs = GetCommandLineArguments(encodingJob); - - var process = ProcessFactory.Create(new ProcessOptions - { - CreateNoWindow = true, - UseShellExecute = false, - - // Must consume both stdout and stderr or deadlocks may occur - //RedirectStandardOutput = true, - RedirectStandardError = true, - RedirectStandardInput = true, - - FileName = MediaEncoder.EncoderPath, - Arguments = commandLineArgs, - - IsHidden = true, - ErrorDialog = false, - EnableRaisingEvents = true - }); - - var workingDirectory = GetWorkingDirectory(options); - if (!string.IsNullOrWhiteSpace(workingDirectory)) - { - process.StartInfo.WorkingDirectory = workingDirectory; - } - - OnTranscodeBeginning(encodingJob); - - var commandLineLogMessage = process.StartInfo.FileName + " " + process.StartInfo.Arguments; - Logger.LogInformation(commandLineLogMessage); - - var logFilePath = Path.Combine(ConfigurationManager.CommonApplicationPaths.LogDirectoryPath, "transcode-" + Guid.NewGuid() + ".txt"); - Directory.CreateDirectory(Path.GetDirectoryName(logFilePath)); - - // FFMpeg writes debug/error info to stderr. This is useful when debugging so let's put it in the log directory. - encodingJob.LogFileStream = FileSystem.GetFileStream(logFilePath, FileOpenMode.Create, FileAccessMode.Write, FileShareMode.Read, true); - - var commandLineLogMessageBytes = Encoding.UTF8.GetBytes(commandLineLogMessage + Environment.NewLine + Environment.NewLine); - await encodingJob.LogFileStream.WriteAsync(commandLineLogMessageBytes, 0, commandLineLogMessageBytes.Length, cancellationToken).ConfigureAwait(false); - - process.Exited += (sender, args) => OnFfMpegProcessExited(process, encodingJob); - - try - { - process.Start(); - } - catch (Exception ex) - { - Logger.LogError(ex, "Error starting ffmpeg"); - - OnTranscodeFailedToStart(encodingJob.OutputFilePath, encodingJob); - - throw; - } - - cancellationToken.Register(() => Cancel(process, encodingJob)); - - // MUST read both stdout and stderr asynchronously or a deadlock may occurr - //process.BeginOutputReadLine(); - - // Important - don't await the log task or we won't be able to kill ffmpeg when the user stops playback - new JobLogger(Logger).StartStreamingLog(encodingJob, process.StandardError.BaseStream, encodingJob.LogFileStream); - - // Wait for the file to exist before proceeeding - while (!File.Exists(encodingJob.OutputFilePath) && !encodingJob.HasExited) - { - await Task.Delay(100, cancellationToken).ConfigureAwait(false); - } - - return encodingJob; - } - - private void Cancel(IProcess process, EncodingJob job) - { - Logger.LogInformation("Killing ffmpeg process for {0}", job.OutputFilePath); - - //process.Kill(); - process.StandardInput.WriteLine("q"); - - job.IsCancelled = true; - } - - /// <summary> - /// Processes the exited. - /// </summary> - /// <param name="process">The process.</param> - /// <param name="job">The job.</param> - private void OnFfMpegProcessExited(IProcess process, EncodingJob job) - { - job.HasExited = true; - - Logger.LogDebug("Disposing stream resources"); - job.Dispose(); - - var isSuccesful = false; - - try - { - var exitCode = process.ExitCode; - Logger.LogInformation("FFMpeg exited with code {0}", exitCode); - - isSuccesful = exitCode == 0; - } - catch (Exception ex) - { - Logger.LogError(ex, "FFMpeg exited with an error."); - } - - if (isSuccesful && !job.IsCancelled) - { - job.TaskCompletionSource.TrySetResult(true); - } - else if (job.IsCancelled) - { - try - { - DeleteFiles(job); - } - catch - { - } - try - { - job.TaskCompletionSource.TrySetException(new OperationCanceledException()); - } - catch - { - } - } - else - { - try - { - DeleteFiles(job); - } - catch - { - } - try - { - job.TaskCompletionSource.TrySetException(new Exception("Encoding failed")); - } - catch - { - } - } - - // This causes on exited to be called twice: - //try - //{ - // // Dispose the process - // process.Dispose(); - //} - //catch (Exception ex) - //{ - // Logger.LogError("Error disposing ffmpeg.", ex); - //} - } - - protected virtual void DeleteFiles(EncodingJob job) - { - FileSystem.DeleteFile(job.OutputFilePath); - } - - private void OnTranscodeBeginning(EncodingJob job) - { - job.ReportTranscodingProgress(null, null, null, null, null); - } - - private void OnTranscodeFailedToStart(string path, EncodingJob job) - { - if (!string.IsNullOrWhiteSpace(job.Options.DeviceId)) - { - SessionManager.ClearTranscodingInfo(job.Options.DeviceId); - } - } - - protected abstract bool IsVideoEncoder { get; } - - protected virtual string GetWorkingDirectory(EncodingJobOptions options) - { - return null; - } - - protected EncodingOptions GetEncodingOptions() - { - return ConfigurationManager.GetConfiguration<EncodingOptions>("encoding"); - } - - protected abstract string GetCommandLineArguments(EncodingJob job); - - private string GetOutputFilePath(EncodingJob state) - { - var folder = string.IsNullOrWhiteSpace(state.Options.TempDirectory) ? - ConfigurationManager.ApplicationPaths.TranscodingTempPath : - state.Options.TempDirectory; - - var outputFileExtension = GetOutputFileExtension(state); - - var filename = state.Id + (outputFileExtension ?? string.Empty).ToLower(); - return Path.Combine(folder, filename); - } - - protected virtual string GetOutputFileExtension(EncodingJob state) - { - if (!string.IsNullOrWhiteSpace(state.Options.Container)) - { - return "." + state.Options.Container; - } - - return null; - } - - /// <summary> - /// Gets the name of the output video codec - /// </summary> - /// <param name="state">The state.</param> - /// <returns>System.String.</returns> - protected string GetVideoDecoder(EncodingJob state) - { - if (string.Equals(state.OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase)) - { - return null; - } - - // 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 null; - } - - if (state.VideoStream != null && !string.IsNullOrWhiteSpace(state.VideoStream.Codec)) - { - if (string.Equals(GetEncodingOptions().HardwareAccelerationType, "qsv", StringComparison.OrdinalIgnoreCase)) - { - switch (state.MediaSource.VideoStream.Codec.ToLower()) - { - case "avc": - case "h264": - if (MediaEncoder.SupportsDecoder("h264_qsv")) - { - // Seeing stalls and failures with decoding. Not worth it compared to encoding. - return "-c:v h264_qsv "; - } - break; - case "mpeg2video": - if (MediaEncoder.SupportsDecoder("mpeg2_qsv")) - { - return "-c:v mpeg2_qsv "; - } - break; - case "vc1": - if (MediaEncoder.SupportsDecoder("vc1_qsv")) - { - return "-c:v vc1_qsv "; - } - break; - } - } - } - - // leave blank so ffmpeg will decide - return null; - } - - private async Task AcquireResources(EncodingJob state, CancellationToken cancellationToken) - { - if (state.VideoType == VideoType.Iso && state.IsoType.HasValue && IsoManager.CanMount(state.MediaPath)) - { - state.IsoMount = await IsoManager.Mount(state.MediaPath, cancellationToken).ConfigureAwait(false); - } - - if (state.MediaSource.RequiresOpening && string.IsNullOrWhiteSpace(state.Options.LiveStreamId)) - { - var liveStreamResponse = await MediaSourceManager.OpenLiveStream(new LiveStreamRequest - { - OpenToken = state.MediaSource.OpenToken - - }, cancellationToken).ConfigureAwait(false); - - EncodingHelper.AttachMediaSourceInfo(state, liveStreamResponse.MediaSource, null); - - if (state.IsVideoRequest) - { - EncodingHelper.TryStreamCopy(state); - } - } - - if (state.MediaSource.BufferMs.HasValue) - { - await Task.Delay(state.MediaSource.BufferMs.Value, cancellationToken).ConfigureAwait(false); - } - } - } -} diff --git a/MediaBrowser.MediaEncoding/Encoder/EncodingJob.cs b/MediaBrowser.MediaEncoding/Encoder/EncodingJob.cs deleted file mode 100644 index d4040cd31..000000000 --- a/MediaBrowser.MediaEncoding/Encoder/EncodingJob.cs +++ /dev/null @@ -1,149 +0,0 @@ -using System; -using System.IO; -using System.Threading.Tasks; -using MediaBrowser.Controller.Library; -using MediaBrowser.Controller.MediaEncoding; -using MediaBrowser.Model.Dlna; -using MediaBrowser.Model.Net; -using Microsoft.Extensions.Logging; - -namespace MediaBrowser.MediaEncoding.Encoder -{ - public class EncodingJob : EncodingJobInfo, IDisposable - { - public bool HasExited { get; internal set; } - public bool IsCancelled { get; internal set; } - - public Stream LogFileStream { get; set; } - public TaskCompletionSource<bool> TaskCompletionSource; - - public EncodingJobOptions Options - { - get => (EncodingJobOptions)BaseRequest; - set => BaseRequest = value; - } - - public Guid Id { get; set; } - - public bool EstimateContentLength { get; set; } - public TranscodeSeekInfo TranscodeSeekInfo { get; set; } - - public string ItemType { get; set; } - - private readonly ILogger _logger; - private readonly IMediaSourceManager _mediaSourceManager; - - public EncodingJob(ILogger logger, IMediaSourceManager mediaSourceManager) : - base(TranscodingJobType.Progressive) - { - _logger = logger; - _mediaSourceManager = mediaSourceManager; - Id = Guid.NewGuid(); - - _logger = logger; - TaskCompletionSource = new TaskCompletionSource<bool>(); - } - - public override void Dispose() - { - DisposeLiveStream(); - DisposeLogStream(); - DisposeIsoMount(); - } - - private void DisposeLogStream() - { - if (LogFileStream != null) - { - try - { - LogFileStream.Dispose(); - } - catch (Exception ex) - { - _logger.LogError(ex, "Error disposing log stream"); - } - - LogFileStream = null; - } - } - - private async void DisposeLiveStream() - { - if (MediaSource.RequiresClosing && string.IsNullOrWhiteSpace(Options.LiveStreamId) && !string.IsNullOrWhiteSpace(MediaSource.LiveStreamId)) - { - try - { - await _mediaSourceManager.CloseLiveStream(MediaSource.LiveStreamId).ConfigureAwait(false); - } - catch (Exception ex) - { - _logger.LogError(ex, "Error closing media source"); - } - } - } - - - private void DisposeIsoMount() - { - if (IsoMount != null) - { - try - { - IsoMount.Dispose(); - } - catch (Exception ex) - { - _logger.LogError("Error disposing iso mount", ex); - } - - IsoMount = null; - } - } - - public void ReportTranscodingProgress(TimeSpan? transcodingPosition, float? framerate, double? percentComplete, long? bytesTranscoded, int? bitRate) - { - var ticks = transcodingPosition.HasValue ? transcodingPosition.Value.Ticks : (long?)null; - - //job.Framerate = framerate; - - if (!percentComplete.HasValue && ticks.HasValue && RunTimeTicks.HasValue) - { - var pct = ticks.Value / RunTimeTicks.Value; - percentComplete = pct * 100; - } - - if (percentComplete.HasValue) - { - Progress.Report(percentComplete.Value); - } - - /* - job.TranscodingPositionTicks = ticks; - job.BytesTranscoded = bytesTranscoded; - - var deviceId = Options.DeviceId; - - if (!string.IsNullOrWhiteSpace(deviceId)) - { - var audioCodec = ActualOutputVideoCodec; - var videoCodec = ActualOutputVideoCodec; - - SessionManager.ReportTranscodingInfo(deviceId, new TranscodingInfo - { - Bitrate = job.TotalOutputBitrate, - AudioCodec = audioCodec, - VideoCodec = videoCodec, - Container = job.Options.OutputContainer, - Framerate = framerate, - CompletionPercentage = percentComplete, - Width = job.OutputWidth, - Height = job.OutputHeight, - AudioChannels = job.OutputAudioChannels, - IsAudioDirect = string.Equals(job.OutputAudioCodec, "copy", StringComparison.OrdinalIgnoreCase), - IsVideoDirect = string.Equals(job.OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase) - }); - }*/ - } - } -} diff --git a/MediaBrowser.MediaEncoding/Encoder/EncodingJobFactory.cs b/MediaBrowser.MediaEncoding/Encoder/EncodingJobFactory.cs deleted file mode 100644 index 95454c447..000000000 --- a/MediaBrowser.MediaEncoding/Encoder/EncodingJobFactory.cs +++ /dev/null @@ -1,307 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Globalization; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using MediaBrowser.Common.Configuration; -using MediaBrowser.Controller.Library; -using MediaBrowser.Controller.MediaEncoding; -using MediaBrowser.Model.Configuration; -using MediaBrowser.Model.Dlna; -using MediaBrowser.Model.Entities; -using Microsoft.Extensions.Logging; - -namespace MediaBrowser.MediaEncoding.Encoder -{ - public class EncodingJobFactory - { - private readonly ILogger _logger; - private readonly ILibraryManager _libraryManager; - private readonly IMediaSourceManager _mediaSourceManager; - private readonly IConfigurationManager _config; - private readonly IMediaEncoder _mediaEncoder; - - protected static readonly CultureInfo UsCulture = new CultureInfo("en-US"); - - public EncodingJobFactory(ILogger logger, ILibraryManager libraryManager, IMediaSourceManager mediaSourceManager, IConfigurationManager config, IMediaEncoder mediaEncoder) - { - _logger = logger; - _libraryManager = libraryManager; - _mediaSourceManager = mediaSourceManager; - _config = config; - _mediaEncoder = mediaEncoder; - } - - public async Task<EncodingJob> CreateJob(EncodingJobOptions options, EncodingHelper encodingHelper, bool isVideoRequest, IProgress<double> progress, CancellationToken cancellationToken) - { - var request = options; - - if (string.IsNullOrEmpty(request.AudioCodec)) - { - request.AudioCodec = InferAudioCodec(request.Container); - } - - var state = new EncodingJob(_logger, _mediaSourceManager) - { - Options = options, - IsVideoRequest = isVideoRequest, - Progress = progress - }; - - if (!string.IsNullOrWhiteSpace(request.VideoCodec)) - { - state.SupportedVideoCodecs = request.VideoCodec.Split(',').Where(i => !string.IsNullOrWhiteSpace(i)).ToArray(); - request.VideoCodec = state.SupportedVideoCodecs.FirstOrDefault(); - } - - if (!string.IsNullOrWhiteSpace(request.AudioCodec)) - { - state.SupportedAudioCodecs = request.AudioCodec.Split(',').Where(i => !string.IsNullOrWhiteSpace(i)).ToArray(); - request.AudioCodec = state.SupportedAudioCodecs.FirstOrDefault(); - } - - if (!string.IsNullOrWhiteSpace(request.SubtitleCodec)) - { - state.SupportedSubtitleCodecs = request.SubtitleCodec.Split(',').Where(i => !string.IsNullOrWhiteSpace(i)).ToArray(); - request.SubtitleCodec = state.SupportedSubtitleCodecs.FirstOrDefault(i => _mediaEncoder.CanEncodeToSubtitleCodec(i)) - ?? state.SupportedSubtitleCodecs.FirstOrDefault(); - } - - var item = _libraryManager.GetItemById(request.Id); - state.ItemType = item.GetType().Name; - - state.IsInputVideo = string.Equals(item.MediaType, MediaType.Video, StringComparison.OrdinalIgnoreCase); - - // TODO - // var primaryImage = item.GetImageInfo(ImageType.Primary, 0) ?? - // item.Parents.Select(i => i.GetImageInfo(ImageType.Primary, 0)).FirstOrDefault(i => i != null); - - // if (primaryImage != null) - // { - // state.AlbumCoverPath = primaryImage.Path; - // } - - // TODO network path substition useful ? - var mediaSources = await _mediaSourceManager.GetPlayackMediaSources(item, null, true, true, cancellationToken).ConfigureAwait(false); - - var mediaSource = string.IsNullOrEmpty(request.MediaSourceId) - ? mediaSources.First() - : mediaSources.First(i => string.Equals(i.Id, request.MediaSourceId)); - - var videoRequest = state.Options; - - encodingHelper.AttachMediaSourceInfo(state, mediaSource, null); - - //var container = Path.GetExtension(state.RequestedUrl); - - //if (string.IsNullOrEmpty(container)) - //{ - // container = request.Static ? - // state.InputContainer : - // (Path.GetExtension(GetOutputFilePath(state)) ?? string.Empty).TrimStart('.'); - //} - - //state.OutputContainer = (container ?? string.Empty).TrimStart('.'); - - state.OutputAudioBitrate = encodingHelper.GetAudioBitrateParam(state.Options, state.AudioStream); - - state.OutputAudioCodec = state.Options.AudioCodec; - - state.OutputAudioChannels = encodingHelper.GetNumAudioChannelsParam(state, state.AudioStream, state.OutputAudioCodec); - - if (videoRequest != null) - { - state.OutputVideoCodec = state.Options.VideoCodec; - state.OutputVideoBitrate = encodingHelper.GetVideoBitrateParamValue(state.Options, state.VideoStream, state.OutputVideoCodec); - - if (state.OutputVideoBitrate.HasValue) - { - var resolution = ResolutionNormalizer.Normalize( - state.VideoStream == null ? (int?)null : state.VideoStream.BitRate, - state.VideoStream == null ? (int?)null : state.VideoStream.Width, - state.VideoStream == null ? (int?)null : state.VideoStream.Height, - state.OutputVideoBitrate.Value, - state.VideoStream == null ? null : state.VideoStream.Codec, - state.OutputVideoCodec, - videoRequest.MaxWidth, - videoRequest.MaxHeight); - - videoRequest.MaxWidth = resolution.MaxWidth; - videoRequest.MaxHeight = resolution.MaxHeight; - } - } - - ApplyDeviceProfileSettings(state); - - if (videoRequest != null) - { - encodingHelper.TryStreamCopy(state); - } - - //state.OutputFilePath = GetOutputFilePath(state); - - return state; - } - - protected EncodingOptions GetEncodingOptions() - { - return _config.GetConfiguration<EncodingOptions>("encoding"); - } - - /// <summary> - /// Infers the video codec. - /// </summary> - /// <param name="container">The container.</param> - /// <returns>System.Nullable{VideoCodecs}.</returns> - private static string InferVideoCodec(string container) - { - var ext = "." + (container ?? string.Empty); - - if (string.Equals(ext, ".asf", StringComparison.OrdinalIgnoreCase)) - { - return "wmv"; - } - if (string.Equals(ext, ".webm", StringComparison.OrdinalIgnoreCase)) - { - return "vpx"; - } - if (string.Equals(ext, ".ogg", StringComparison.OrdinalIgnoreCase) || string.Equals(ext, ".ogv", StringComparison.OrdinalIgnoreCase)) - { - return "theora"; - } - if (string.Equals(ext, ".m3u8", StringComparison.OrdinalIgnoreCase) || string.Equals(ext, ".ts", StringComparison.OrdinalIgnoreCase)) - { - return "h264"; - } - - return "copy"; - } - - private string InferAudioCodec(string container) - { - var ext = "." + (container ?? string.Empty); - - if (string.Equals(ext, ".mp3", StringComparison.OrdinalIgnoreCase)) - { - return "mp3"; - } - if (string.Equals(ext, ".aac", StringComparison.OrdinalIgnoreCase)) - { - return "aac"; - } - if (string.Equals(ext, ".wma", StringComparison.OrdinalIgnoreCase)) - { - return "wma"; - } - if (string.Equals(ext, ".ogg", StringComparison.OrdinalIgnoreCase)) - { - return "vorbis"; - } - if (string.Equals(ext, ".oga", StringComparison.OrdinalIgnoreCase)) - { - return "vorbis"; - } - if (string.Equals(ext, ".ogv", StringComparison.OrdinalIgnoreCase)) - { - return "vorbis"; - } - if (string.Equals(ext, ".webm", StringComparison.OrdinalIgnoreCase)) - { - return "vorbis"; - } - if (string.Equals(ext, ".webma", StringComparison.OrdinalIgnoreCase)) - { - return "vorbis"; - } - - return "copy"; - } - - /// <summary> - /// Determines whether the specified stream is H264. - /// </summary> - /// <param name="stream">The stream.</param> - /// <returns><c>true</c> if the specified stream is H264; otherwise, <c>false</c>.</returns> - protected bool IsH264(MediaStream stream) - { - var codec = stream.Codec ?? string.Empty; - - return codec.IndexOf("264", StringComparison.OrdinalIgnoreCase) != -1 || - codec.IndexOf("avc", StringComparison.OrdinalIgnoreCase) != -1; - } - - private static int GetVideoProfileScore(string profile) - { - var list = new List<string> - { - "Constrained Baseline", - "Baseline", - "Extended", - "Main", - "High", - "Progressive High", - "Constrained High" - }; - - return Array.FindIndex(list.ToArray(), t => string.Equals(t, profile, StringComparison.OrdinalIgnoreCase)); - } - - private void ApplyDeviceProfileSettings(EncodingJob state) - { - var profile = state.Options.DeviceProfile; - - if (profile == null) - { - // Don't use settings from the default profile. - // Only use a specific profile if it was requested. - return; - } - - var audioCodec = state.ActualOutputAudioCodec; - - var videoCodec = state.ActualOutputVideoCodec; - var outputContainer = state.Options.Container; - - var mediaProfile = state.IsVideoRequest ? - profile.GetAudioMediaProfile(outputContainer, audioCodec, state.OutputAudioChannels, state.OutputAudioBitrate, state.OutputAudioSampleRate, state.OutputAudioBitDepth) : - profile.GetVideoMediaProfile(outputContainer, - audioCodec, - videoCodec, - state.OutputWidth, - state.OutputHeight, - state.TargetVideoBitDepth, - state.OutputVideoBitrate, - state.TargetVideoProfile, - state.TargetVideoLevel, - state.TargetFramerate, - state.TargetPacketLength, - state.TargetTimestamp, - state.IsTargetAnamorphic, - state.IsTargetInterlaced, - state.TargetRefFrames, - state.TargetVideoStreamCount, - state.TargetAudioStreamCount, - state.TargetVideoCodecTag, - state.IsTargetAVC); - - if (mediaProfile != null) - { - state.MimeType = mediaProfile.MimeType; - } - - var transcodingProfile = state.IsVideoRequest ? - profile.GetAudioTranscodingProfile(outputContainer, audioCodec) : - profile.GetVideoTranscodingProfile(outputContainer, audioCodec, videoCodec); - - if (transcodingProfile != null) - { - state.EstimateContentLength = transcodingProfile.EstimateContentLength; - //state.EnableMpegtsM2TsMode = transcodingProfile.EnableMpegtsM2TsMode; - state.TranscodeSeekInfo = transcodingProfile.TranscodeSeekInfo; - - state.Options.CopyTimestamps = transcodingProfile.CopyTimestamps; - } - } - } -} diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs index 54344424d..d922f1068 100644 --- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs @@ -878,49 +878,6 @@ namespace MediaBrowser.MediaEncoding.Encoder } } - public async Task<string> EncodeAudio(EncodingJobOptions options, - IProgress<double> progress, - CancellationToken cancellationToken) - { - var job = await new AudioEncoder(this, - _logger, - ConfigurationManager, - FileSystem, - IsoManager, - LibraryManager, - SessionManager, - SubtitleEncoder(), - MediaSourceManager(), - _processFactory) - .Start(options, progress, cancellationToken).ConfigureAwait(false); - - await job.TaskCompletionSource.Task.ConfigureAwait(false); - - return job.OutputFilePath; - } - - public async Task<string> EncodeVideo(EncodingJobOptions options, - IProgress<double> progress, - CancellationToken cancellationToken) - { - _logger.LogError("EncodeVideo"); - var job = await new VideoEncoder(this, - _logger, - ConfigurationManager, - FileSystem, - IsoManager, - LibraryManager, - SessionManager, - SubtitleEncoder(), - MediaSourceManager(), - _processFactory) - .Start(options, progress, cancellationToken).ConfigureAwait(false); - - await job.TaskCompletionSource.Task.ConfigureAwait(false); - - return job.OutputFilePath; - } - private void StartProcess(ProcessWrapper process) { process.Process.Start(); diff --git a/MediaBrowser.MediaEncoding/Encoder/VideoEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/VideoEncoder.cs deleted file mode 100644 index bf23a73bd..000000000 --- a/MediaBrowser.MediaEncoding/Encoder/VideoEncoder.cs +++ /dev/null @@ -1,59 +0,0 @@ -using System; -using MediaBrowser.Controller.Configuration; -using MediaBrowser.Controller.Library; -using MediaBrowser.Controller.MediaEncoding; -using MediaBrowser.Controller.Session; -using MediaBrowser.Model.Diagnostics; -using MediaBrowser.Model.IO; -using Microsoft.Extensions.Logging; - -namespace MediaBrowser.MediaEncoding.Encoder -{ - public class VideoEncoder : BaseEncoder - { - public VideoEncoder(MediaEncoder mediaEncoder, ILogger logger, IServerConfigurationManager configurationManager, IFileSystem fileSystem, IIsoManager isoManager, ILibraryManager libraryManager, ISessionManager sessionManager, ISubtitleEncoder subtitleEncoder, IMediaSourceManager mediaSourceManager, IProcessFactory processFactory) : base(mediaEncoder, logger, configurationManager, fileSystem, isoManager, libraryManager, sessionManager, subtitleEncoder, mediaSourceManager, processFactory) - { - } - - protected override string GetCommandLineArguments(EncodingJob state) - { - // Get the output codec name - var encodingOptions = GetEncodingOptions(); - - return EncodingHelper.GetProgressiveVideoFullCommandLine(state, encodingOptions, state.OutputFilePath, "superfast"); - } - - protected override string GetOutputFileExtension(EncodingJob state) - { - var ext = base.GetOutputFileExtension(state); - - if (!string.IsNullOrEmpty(ext)) - { - return ext; - } - - var videoCodec = state.Options.VideoCodec; - - if (string.Equals(videoCodec, "h264", StringComparison.OrdinalIgnoreCase)) - { - return ".ts"; - } - if (string.Equals(videoCodec, "theora", StringComparison.OrdinalIgnoreCase)) - { - return ".ogv"; - } - if (string.Equals(videoCodec, "vpx", StringComparison.OrdinalIgnoreCase)) - { - return ".webm"; - } - if (string.Equals(videoCodec, "wmv", StringComparison.OrdinalIgnoreCase)) - { - return ".asf"; - } - - return null; - } - - protected override bool IsVideoEncoder => true; - } -} diff --git a/MediaBrowser.MediaEncoding/Subtitles/SsaParser.cs b/MediaBrowser.MediaEncoding/Subtitles/SsaParser.cs index 2c18a02ef..0d696b906 100644 --- a/MediaBrowser.MediaEncoding/Subtitles/SsaParser.cs +++ b/MediaBrowser.MediaEncoding/Subtitles/SsaParser.cs @@ -44,7 +44,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles if (!eventsStarted) header.AppendLine(line); - if (line.Trim().ToLower() == "[events]") + if (line.Trim().ToLowerInvariant() == "[events]") { eventsStarted = true; } @@ -54,25 +54,25 @@ namespace MediaBrowser.MediaEncoding.Subtitles } else if (eventsStarted && line.Trim().Length > 0) { - string s = line.Trim().ToLower(); + string s = line.Trim().ToLowerInvariant(); if (s.StartsWith("format:")) { if (line.Length > 10) { - format = line.ToLower().Substring(8).Split(','); + format = line.ToLowerInvariant().Substring(8).Split(','); for (int i = 0; i < format.Length; i++) { - if (format[i].Trim().ToLower() == "layer") + if (format[i].Trim().ToLowerInvariant() == "layer") indexLayer = i; - else if (format[i].Trim().ToLower() == "start") + else if (format[i].Trim().ToLowerInvariant() == "start") indexStart = i; - else if (format[i].Trim().ToLower() == "end") + else if (format[i].Trim().ToLowerInvariant() == "end") indexEnd = i; - else if (format[i].Trim().ToLower() == "text") + else if (format[i].Trim().ToLowerInvariant() == "text") indexText = i; - else if (format[i].Trim().ToLower() == "effect") + else if (format[i].Trim().ToLowerInvariant() == "effect") indexEffect = i; - else if (format[i].Trim().ToLower() == "style") + else if (format[i].Trim().ToLowerInvariant() == "style") indexStyle = i; } } @@ -222,7 +222,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles // switch to rrggbb from bbggrr color = "#" + color.Remove(color.Length - 6) + color.Substring(color.Length - 2, 2) + color.Substring(color.Length - 4, 2) + color.Substring(color.Length - 6, 2); - color = color.ToLower(); + color = color.ToLowerInvariant(); text = text.Remove(start, end - start + 1); if (italic) @@ -252,7 +252,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles // switch to rrggbb from bbggrr color = "#" + color.Remove(color.Length - 6) + color.Substring(color.Length - 2, 2) + color.Substring(color.Length - 4, 2) + color.Substring(color.Length - 6, 2); - color = color.ToLower(); + color = color.ToLowerInvariant(); text = text.Remove(start, end - start + 1); if (italic) @@ -367,7 +367,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles color = color.PadLeft(6, '0'); // switch to rrggbb from bbggrr color = "#" + color.Remove(color.Length - 6) + color.Substring(color.Length - 2, 2) + color.Substring(color.Length - 4, 2) + color.Substring(color.Length - 6, 2); - color = color.ToLower(); + color = color.ToLowerInvariant(); extraTags += " color=\"" + color + "\""; } diff --git a/MediaBrowser.Model/Channels/ChannelMediaContentType.cs b/MediaBrowser.Model/Channels/ChannelMediaContentType.cs index 010ff8048..fc7c21706 100644 --- a/MediaBrowser.Model/Channels/ChannelMediaContentType.cs +++ b/MediaBrowser.Model/Channels/ChannelMediaContentType.cs @@ -16,8 +16,6 @@ namespace MediaBrowser.Model.Channels MovieExtra = 6, - TvExtra = 7, - - GameExtra = 8 + TvExtra = 7 } } diff --git a/MediaBrowser.Model/Configuration/UnratedItem.cs b/MediaBrowser.Model/Configuration/UnratedItem.cs index 2d0bce47f..107b4e520 100644 --- a/MediaBrowser.Model/Configuration/UnratedItem.cs +++ b/MediaBrowser.Model/Configuration/UnratedItem.cs @@ -6,7 +6,6 @@ namespace MediaBrowser.Model.Configuration Trailer, Series, Music, - Game, Book, LiveTvChannel, LiveTvProgram, diff --git a/MediaBrowser.Model/Connect/ConnectAuthorization.cs b/MediaBrowser.Model/Connect/ConnectAuthorization.cs deleted file mode 100644 index cdb3172d9..000000000 --- a/MediaBrowser.Model/Connect/ConnectAuthorization.cs +++ /dev/null @@ -1,21 +0,0 @@ -using System; - -namespace MediaBrowser.Model.Connect -{ - public class ConnectAuthorization - { - public string ConnectUserId { get; set; } - public string UserName { get; set; } - public string ImageUrl { get; set; } - public string Id { get; set; } - public string[] EnabledLibraries { get; set; } - public bool EnableLiveTv { get; set; } - public string[] EnabledChannels { get; set; } - - public ConnectAuthorization() - { - EnabledLibraries = Array.Empty<string>(); - EnabledChannels = Array.Empty<string>(); - } - } -} diff --git a/MediaBrowser.Model/Connect/ConnectUser.cs b/MediaBrowser.Model/Connect/ConnectUser.cs deleted file mode 100644 index 4c536c6b0..000000000 --- a/MediaBrowser.Model/Connect/ConnectUser.cs +++ /dev/null @@ -1,11 +0,0 @@ -namespace MediaBrowser.Model.Connect -{ - public class ConnectUser - { - public string Id { get; set; } - public string Name { get; set; } - public string Email { get; set; } - public bool IsActive { get; set; } - public string ImageUrl { get; set; } - } -} diff --git a/MediaBrowser.Model/Connect/ConnectUserQuery.cs b/MediaBrowser.Model/Connect/ConnectUserQuery.cs deleted file mode 100644 index 4f04934d6..000000000 --- a/MediaBrowser.Model/Connect/ConnectUserQuery.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace MediaBrowser.Model.Connect -{ - public class ConnectUserQuery - { - public string Id { get; set; } - public string Name { get; set; } - public string Email { get; set; } - public string NameOrEmail { get; set; } - } -} diff --git a/MediaBrowser.Model/Connect/UserLinkType.cs b/MediaBrowser.Model/Connect/UserLinkType.cs deleted file mode 100644 index 19b4b67e6..000000000 --- a/MediaBrowser.Model/Connect/UserLinkType.cs +++ /dev/null @@ -1,14 +0,0 @@ -namespace MediaBrowser.Model.Connect -{ - public enum UserLinkType - { - /// <summary> - /// The linked user - /// </summary> - LinkedUser = 0, - /// <summary> - /// The guest - /// </summary> - Guest = 1 - } -} diff --git a/MediaBrowser.Model/Dlna/StreamInfo.cs b/MediaBrowser.Model/Dlna/StreamInfo.cs index 6d03a03b0..10efb9b38 100644 --- a/MediaBrowser.Model/Dlna/StreamInfo.cs +++ b/MediaBrowser.Model/Dlna/StreamInfo.cs @@ -223,7 +223,7 @@ namespace MediaBrowser.Model.Dlna list.Add(new NameValuePair("DeviceProfileId", item.DeviceProfileId ?? string.Empty)); list.Add(new NameValuePair("DeviceId", item.DeviceId ?? string.Empty)); list.Add(new NameValuePair("MediaSourceId", item.MediaSourceId ?? string.Empty)); - list.Add(new NameValuePair("Static", item.IsDirectStream.ToString().ToLower())); + list.Add(new NameValuePair("Static", item.IsDirectStream.ToString(CultureInfo.InvariantCulture).ToLowerInvariant())); list.Add(new NameValuePair("VideoCodec", videoCodecs)); list.Add(new NameValuePair("AudioCodec", audioCodecs)); list.Add(new NameValuePair("AudioStreamIndex", item.AudioStreamIndex.HasValue ? item.AudioStreamIndex.Value.ToString(CultureInfo.InvariantCulture) : string.Empty)); @@ -251,7 +251,7 @@ namespace MediaBrowser.Model.Dlna list.Add(new NameValuePair("PlaySessionId", item.PlaySessionId ?? string.Empty)); list.Add(new NameValuePair("api_key", accessToken ?? string.Empty)); - string liveStreamId = item.MediaSource == null ? null : item.MediaSource.LiveStreamId; + string liveStreamId = item.MediaSource?.LiveStreamId; list.Add(new NameValuePair("LiveStreamId", liveStreamId ?? string.Empty)); list.Add(new NameValuePair("SubtitleMethod", item.SubtitleStreamIndex.HasValue && item.SubtitleDeliveryMethod != SubtitleDeliveryMethod.External ? item.SubtitleDeliveryMethod.ToString() : string.Empty)); @@ -261,37 +261,37 @@ namespace MediaBrowser.Model.Dlna { if (item.RequireNonAnamorphic) { - list.Add(new NameValuePair("RequireNonAnamorphic", item.RequireNonAnamorphic.ToString().ToLower())); + list.Add(new NameValuePair("RequireNonAnamorphic", item.RequireNonAnamorphic.ToString(CultureInfo.InvariantCulture).ToLowerInvariant())); } list.Add(new NameValuePair("TranscodingMaxAudioChannels", item.TranscodingMaxAudioChannels.HasValue ? item.TranscodingMaxAudioChannels.Value.ToString(CultureInfo.InvariantCulture) : string.Empty)); if (item.EnableSubtitlesInManifest) { - list.Add(new NameValuePair("EnableSubtitlesInManifest", item.EnableSubtitlesInManifest.ToString().ToLower())); + list.Add(new NameValuePair("EnableSubtitlesInManifest", item.EnableSubtitlesInManifest.ToString(CultureInfo.InvariantCulture).ToLowerInvariant())); } if (item.EnableMpegtsM2TsMode) { - list.Add(new NameValuePair("EnableMpegtsM2TsMode", item.EnableMpegtsM2TsMode.ToString().ToLower())); + list.Add(new NameValuePair("EnableMpegtsM2TsMode", item.EnableMpegtsM2TsMode.ToString(CultureInfo.InvariantCulture).ToLowerInvariant())); } if (item.EstimateContentLength) { - list.Add(new NameValuePair("EstimateContentLength", item.EstimateContentLength.ToString().ToLower())); + list.Add(new NameValuePair("EstimateContentLength", item.EstimateContentLength.ToString(CultureInfo.InvariantCulture).ToLowerInvariant())); } if (item.TranscodeSeekInfo != TranscodeSeekInfo.Auto) { - list.Add(new NameValuePair("TranscodeSeekInfo", item.TranscodeSeekInfo.ToString().ToLower())); + list.Add(new NameValuePair("TranscodeSeekInfo", item.TranscodeSeekInfo.ToString().ToLowerInvariant())); } if (item.CopyTimestamps) { - list.Add(new NameValuePair("CopyTimestamps", item.CopyTimestamps.ToString().ToLower())); + list.Add(new NameValuePair("CopyTimestamps", item.CopyTimestamps.ToString(CultureInfo.InvariantCulture).ToLowerInvariant())); } - list.Add(new NameValuePair("RequireAvc", item.RequireAvc.ToString().ToLower())); + list.Add(new NameValuePair("RequireAvc", item.RequireAvc.ToString(CultureInfo.InvariantCulture).ToLowerInvariant())); } list.Add(new NameValuePair("Tag", item.MediaSource.ETag ?? string.Empty)); @@ -316,7 +316,7 @@ namespace MediaBrowser.Model.Dlna list.Add(new NameValuePair("MinSegments", item.MinSegments.Value.ToString(CultureInfo.InvariantCulture))); } - list.Add(new NameValuePair("BreakOnNonKeyFrames", item.BreakOnNonKeyFrames.ToString())); + list.Add(new NameValuePair("BreakOnNonKeyFrames", item.BreakOnNonKeyFrames.ToString(CultureInfo.InvariantCulture))); } foreach (var pair in item.StreamOptions) @@ -332,7 +332,7 @@ namespace MediaBrowser.Model.Dlna if (!item.IsDirectStream) { - list.Add(new NameValuePair("TranscodeReasons", string.Join(",", item.TranscodeReasons.Distinct().Select(i => i.ToString()).ToArray()))); + list.Add(new NameValuePair("TranscodeReasons", string.Join(",", item.TranscodeReasons.Distinct().Select(i => i.ToString())))); } return list; diff --git a/MediaBrowser.Model/Dto/BaseItemDto.cs b/MediaBrowser.Model/Dto/BaseItemDto.cs index 3e267a39d..b382d9d4a 100644 --- a/MediaBrowser.Model/Dto/BaseItemDto.cs +++ b/MediaBrowser.Model/Dto/BaseItemDto.cs @@ -116,16 +116,8 @@ namespace MediaBrowser.Model.Dto /// <value>The critic rating.</value> public float? CriticRating { get; set; } - /// <summary> - /// Gets or sets the game system. - /// </summary> - /// <value>The game system.</value> - public string GameSystem { get; set; } - public string[] ProductionLocations { get; set; } - public string[] MultiPartGameFiles { get; set; } - /// <summary> /// Gets or sets the path. /// </summary> @@ -604,11 +596,6 @@ namespace MediaBrowser.Model.Dto /// <value>The episode count.</value> public int? EpisodeCount { get; set; } /// <summary> - /// Gets or sets the game count. - /// </summary> - /// <value>The game count.</value> - public int? GameCount { get; set; } - /// <summary> /// Gets or sets the song count. /// </summary> /// <value>The song count.</value> diff --git a/MediaBrowser.Model/Dto/GameSystemSummary.cs b/MediaBrowser.Model/Dto/GameSystemSummary.cs deleted file mode 100644 index e2400a744..000000000 --- a/MediaBrowser.Model/Dto/GameSystemSummary.cs +++ /dev/null @@ -1,48 +0,0 @@ -using System; - -namespace MediaBrowser.Model.Dto -{ - /// <summary> - /// Class GameSystemSummary - /// </summary> - public class GameSystemSummary - { - /// <summary> - /// Gets or sets the name. - /// </summary> - /// <value>The name.</value> - public string Name { get; set; } - - /// <summary> - /// Gets or sets the name. - /// </summary> - /// <value>The name.</value> - public string DisplayName { get; set; } - - /// <summary> - /// Gets or sets the game count. - /// </summary> - /// <value>The game count.</value> - public int GameCount { get; set; } - - /// <summary> - /// Gets or sets the game extensions. - /// </summary> - /// <value>The game extensions.</value> - public string[] GameFileExtensions { get; set; } - - /// <summary> - /// Gets or sets the client installed game count. - /// </summary> - /// <value>The client installed game count.</value> - public int ClientInstalledGameCount { get; set; } - - /// <summary> - /// Initializes a new instance of the <see cref="GameSystemSummary"/> class. - /// </summary> - public GameSystemSummary() - { - GameFileExtensions = Array.Empty<string>(); - } - } -} diff --git a/MediaBrowser.Model/Dto/ItemCounts.cs b/MediaBrowser.Model/Dto/ItemCounts.cs index da941d258..ec5adab85 100644 --- a/MediaBrowser.Model/Dto/ItemCounts.cs +++ b/MediaBrowser.Model/Dto/ItemCounts.cs @@ -20,19 +20,9 @@ namespace MediaBrowser.Model.Dto /// </summary> /// <value>The episode count.</value> public int EpisodeCount { get; set; } - /// <summary> - /// Gets or sets the game count. - /// </summary> - /// <value>The game count.</value> - public int GameCount { get; set; } public int ArtistCount { get; set; } public int ProgramCount { get; set; } /// <summary> - /// Gets or sets the game system count. - /// </summary> - /// <value>The game system count.</value> - public int GameSystemCount { get; set; } - /// <summary> /// Gets or sets the trailer count. /// </summary> /// <value>The trailer count.</value> diff --git a/MediaBrowser.Model/Dto/UserDto.cs b/MediaBrowser.Model/Dto/UserDto.cs index b00f5919f..13da018a6 100644 --- a/MediaBrowser.Model/Dto/UserDto.cs +++ b/MediaBrowser.Model/Dto/UserDto.cs @@ -1,6 +1,5 @@ using System; using MediaBrowser.Model.Configuration; -using MediaBrowser.Model.Connect; using MediaBrowser.Model.Users; namespace MediaBrowser.Model.Dto @@ -30,22 +29,6 @@ namespace MediaBrowser.Model.Dto public string ServerName { get; set; } /// <summary> - /// Gets or sets the name of the connect user. - /// </summary> - /// <value>The name of the connect user.</value> - public string ConnectUserName { get; set; } - /// <summary> - /// Gets or sets the connect user identifier. - /// </summary> - /// <value>The connect user identifier.</value> - public string ConnectUserId { get; set; } - /// <summary> - /// Gets or sets the type of the connect link. - /// </summary> - /// <value>The type of the connect link.</value> - public UserLinkType? ConnectLinkType { get; set; } - - /// <summary> /// Gets or sets the id. /// </summary> /// <value>The id.</value> diff --git a/MediaBrowser.Model/Entities/CollectionType.cs b/MediaBrowser.Model/Entities/CollectionType.cs index bda166118..e26d1b8c3 100644 --- a/MediaBrowser.Model/Entities/CollectionType.cs +++ b/MediaBrowser.Model/Entities/CollectionType.cs @@ -18,7 +18,6 @@ namespace MediaBrowser.Model.Entities public const string Books = "books"; public const string Photos = "photos"; - public const string Games = "games"; public const string LiveTv = "livetv"; public const string Playlists = "playlists"; public const string Folders = "folders"; diff --git a/MediaBrowser.Model/Entities/MediaStream.cs b/MediaBrowser.Model/Entities/MediaStream.cs index e0c3bead1..fc346df37 100644 --- a/MediaBrowser.Model/Entities/MediaStream.cs +++ b/MediaBrowser.Model/Entities/MediaStream.cs @@ -104,7 +104,7 @@ namespace MediaBrowser.Model.Entities attributes.Add("Default"); } - return string.Join(" ", attributes.ToArray()); + return string.Join(" ", attributes); } if (Type == MediaStreamType.Video) @@ -120,10 +120,10 @@ namespace MediaBrowser.Model.Entities if (!string.IsNullOrEmpty(Codec)) { - attributes.Add(Codec.ToUpper()); + attributes.Add(Codec.ToUpperInvariant()); } - return string.Join(" ", attributes.ToArray()); + return string.Join(" ", attributes); } if (Type == MediaStreamType.Subtitle) diff --git a/MediaBrowser.Model/Entities/MediaType.cs b/MediaBrowser.Model/Entities/MediaType.cs index af233e61e..c56c8f8f2 100644 --- a/MediaBrowser.Model/Entities/MediaType.cs +++ b/MediaBrowser.Model/Entities/MediaType.cs @@ -14,10 +14,6 @@ namespace MediaBrowser.Model.Entities /// </summary> public const string Audio = "Audio"; /// <summary> - /// The game - /// </summary> - public const string Game = "Game"; - /// <summary> /// The photo /// </summary> public const string Photo = "Photo"; diff --git a/MediaBrowser.Model/Entities/MetadataProviders.cs b/MediaBrowser.Model/Entities/MetadataProviders.cs index 399961603..e9802cf46 100644 --- a/MediaBrowser.Model/Entities/MetadataProviders.cs +++ b/MediaBrowser.Model/Entities/MetadataProviders.cs @@ -5,7 +5,6 @@ namespace MediaBrowser.Model.Entities /// </summary> public enum MetadataProviders { - Gamesdb = 1, /// <summary> /// The imdb /// </summary> diff --git a/MediaBrowser.Model/Extensions/LinqExtensions.cs b/MediaBrowser.Model/Extensions/LinqExtensions.cs deleted file mode 100644 index f0febf1d0..000000000 --- a/MediaBrowser.Model/Extensions/LinqExtensions.cs +++ /dev/null @@ -1,85 +0,0 @@ -using System; -using System.Collections.Generic; - -// TODO: @bond Remove -namespace MediaBrowser.Model.Extensions -{ - // MoreLINQ - Extensions to LINQ to Objects - // Copyright (c) 2008 Jonathan Skeet. All rights reserved. - // - // Licensed under the Apache License, Version 2.0 (the "License"); - // you may not use this file except in compliance with the License. - // You may obtain a copy of the License at - // - // http://www.apache.org/licenses/LICENSE-2.0 - // - // Unless required by applicable law or agreed to in writing, software - // distributed under the License is distributed on an "AS IS" BASIS, - // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - // See the License for the specific language governing permissions and - // limitations under the License. - - public static class LinqExtensions - { - /// <summary> - /// Returns all distinct elements of the given source, where "distinctness" - /// is determined via a projection and the default equality comparer for the projected type. - /// </summary> - /// <remarks> - /// This operator uses deferred execution and streams the results, although - /// a set of already-seen keys is retained. If a key is seen multiple times, - /// only the first element with that key is returned. - /// </remarks> - /// <typeparam name="TSource">Type of the source sequence</typeparam> - /// <typeparam name="TKey">Type of the projected element</typeparam> - /// <param name="source">Source sequence</param> - /// <param name="keySelector">Projection for determining "distinctness"</param> - /// <returns>A sequence consisting of distinct elements from the source sequence, - /// comparing them by the specified key projection.</returns> - - public static IEnumerable<TSource> DistinctBy<TSource, TKey>(this IEnumerable<TSource> source, - Func<TSource, TKey> keySelector) - { - return source.DistinctBy(keySelector, null); - } - - /// <summary> - /// Returns all distinct elements of the given source, where "distinctness" - /// is determined via a projection and the specified comparer for the projected type. - /// </summary> - /// <remarks> - /// This operator uses deferred execution and streams the results, although - /// a set of already-seen keys is retained. If a key is seen multiple times, - /// only the first element with that key is returned. - /// </remarks> - /// <typeparam name="TSource">Type of the source sequence</typeparam> - /// <typeparam name="TKey">Type of the projected element</typeparam> - /// <param name="source">Source sequence</param> - /// <param name="keySelector">Projection for determining "distinctness"</param> - /// <param name="comparer">The equality comparer to use to determine whether or not keys are equal. - /// If null, the default equality comparer for <c>TSource</c> is used.</param> - /// <returns>A sequence consisting of distinct elements from the source sequence, - /// comparing them by the specified key projection.</returns> - - public static IEnumerable<TSource> DistinctBy<TSource, TKey>(this IEnumerable<TSource> source, - Func<TSource, TKey> keySelector, IEqualityComparer<TKey> comparer) - { - if (source == null) throw new ArgumentNullException(nameof(source)); - if (keySelector == null) throw new ArgumentNullException(nameof(keySelector)); - return DistinctByImpl(source, keySelector, comparer); - } - - private static IEnumerable<TSource> DistinctByImpl<TSource, TKey>(IEnumerable<TSource> source, - Func<TSource, TKey> keySelector, IEqualityComparer<TKey> comparer) - { - var knownKeys = new HashSet<TKey>(comparer); - foreach (var element in source) - { - if (knownKeys.Add(keySelector(element))) - { - yield return element; - } - } - } - } -} diff --git a/MediaBrowser.Model/Extensions/StringHelper.cs b/MediaBrowser.Model/Extensions/StringHelper.cs index 78e23e767..75ba12a17 100644 --- a/MediaBrowser.Model/Extensions/StringHelper.cs +++ b/MediaBrowser.Model/Extensions/StringHelper.cs @@ -51,7 +51,7 @@ namespace MediaBrowser.Model.Extensions public static string FirstToUpper(this string str) { - return string.IsNullOrEmpty(str) ? "" : str.Substring(0, 1).ToUpper() + str.Substring(1); + return string.IsNullOrEmpty(str) ? string.Empty : str.Substring(0, 1).ToUpperInvariant() + str.Substring(1); } } } diff --git a/MediaBrowser.Model/MediaInfo/AudioCodec.cs b/MediaBrowser.Model/MediaInfo/AudioCodec.cs index 5ed67fd78..5ebdb99cb 100644 --- a/MediaBrowser.Model/MediaInfo/AudioCodec.cs +++ b/MediaBrowser.Model/MediaInfo/AudioCodec.cs @@ -8,9 +8,12 @@ namespace MediaBrowser.Model.MediaInfo public static string GetFriendlyName(string codec) { - if (string.IsNullOrEmpty(codec)) return ""; + if (string.IsNullOrEmpty(codec)) + { + return string.Empty; + } - switch (codec.ToLower()) + switch (codec.ToLowerInvariant()) { case "ac3": return "Dolby Digital"; @@ -19,7 +22,7 @@ namespace MediaBrowser.Model.MediaInfo case "dca": return "DTS"; default: - return codec.ToUpper(); + return codec.ToUpperInvariant(); } } } diff --git a/MediaBrowser.Model/Net/MimeTypes.cs b/MediaBrowser.Model/Net/MimeTypes.cs index fe13413e2..659abe84c 100644 --- a/MediaBrowser.Model/Net/MimeTypes.cs +++ b/MediaBrowser.Model/Net/MimeTypes.cs @@ -158,7 +158,7 @@ namespace MediaBrowser.Model.Net // Catch-all for all video types that don't require specific mime types if (VideoFileExtensionsDictionary.ContainsKey(ext)) { - return "video/" + ext.TrimStart('.').ToLower(); + return "video/" + ext.TrimStart('.').ToLowerInvariant(); } // Type text diff --git a/MediaBrowser.Model/Notifications/NotificationType.cs b/MediaBrowser.Model/Notifications/NotificationType.cs index 9d16e4a16..38b519a14 100644 --- a/MediaBrowser.Model/Notifications/NotificationType.cs +++ b/MediaBrowser.Model/Notifications/NotificationType.cs @@ -5,10 +5,8 @@ namespace MediaBrowser.Model.Notifications ApplicationUpdateAvailable, ApplicationUpdateInstalled, AudioPlayback, - GamePlayback, VideoPlayback, AudioPlaybackStopped, - GamePlaybackStopped, VideoPlaybackStopped, InstallationFailed, PluginError, diff --git a/MediaBrowser.Model/Providers/RemoteSearchResult.cs b/MediaBrowser.Model/Providers/RemoteSearchResult.cs index 88e3bc69c..6e46b1556 100644 --- a/MediaBrowser.Model/Providers/RemoteSearchResult.cs +++ b/MediaBrowser.Model/Providers/RemoteSearchResult.cs @@ -30,8 +30,6 @@ namespace MediaBrowser.Model.Providers public string ImageUrl { get; set; } public string SearchProviderName { get; set; } - - public string GameSystem { get; set; } public string Overview { get; set; } public RemoteSearchResult AlbumArtist { get; set; } diff --git a/MediaBrowser.Model/Querying/ItemSortBy.cs b/MediaBrowser.Model/Querying/ItemSortBy.cs index 1b20f43ac..6a71e3bb3 100644 --- a/MediaBrowser.Model/Querying/ItemSortBy.cs +++ b/MediaBrowser.Model/Querying/ItemSortBy.cs @@ -71,8 +71,6 @@ namespace MediaBrowser.Model.Querying public const string VideoBitRate = "VideoBitRate"; public const string AirTime = "AirTime"; public const string Studio = "Studio"; - public const string Players = "Players"; - public const string GameSystem = "GameSystem"; public const string IsFavoriteOrLiked = "IsFavoriteOrLiked"; public const string DateLastContentAdded = "DateLastContentAdded"; public const string SeriesDatePlayed = "SeriesDatePlayed"; diff --git a/MediaBrowser.Providers/GameGenres/GameGenreMetadataService.cs b/MediaBrowser.Providers/GameGenres/GameGenreMetadataService.cs deleted file mode 100644 index 2034848de..000000000 --- a/MediaBrowser.Providers/GameGenres/GameGenreMetadataService.cs +++ /dev/null @@ -1,23 +0,0 @@ -using MediaBrowser.Controller.Configuration; -using MediaBrowser.Controller.Entities; -using MediaBrowser.Controller.Library; -using MediaBrowser.Controller.Providers; -using MediaBrowser.Model.Entities; -using MediaBrowser.Model.IO; -using MediaBrowser.Providers.Manager; -using Microsoft.Extensions.Logging; - -namespace MediaBrowser.Providers.GameGenres -{ - public class GameGenreMetadataService : MetadataService<GameGenre, ItemLookupInfo> - { - protected override void MergeData(MetadataResult<GameGenre> source, MetadataResult<GameGenre> target, MetadataFields[] lockedFields, bool replaceData, bool mergeMetadataSettings) - { - ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings); - } - - public GameGenreMetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, IFileSystem fileSystem, IUserDataManager userDataManager, ILibraryManager libraryManager) : base(serverConfigurationManager, logger, providerManager, fileSystem, userDataManager, libraryManager) - { - } - } -} diff --git a/MediaBrowser.Providers/Games/GameMetadataService.cs b/MediaBrowser.Providers/Games/GameMetadataService.cs deleted file mode 100644 index 764394a21..000000000 --- a/MediaBrowser.Providers/Games/GameMetadataService.cs +++ /dev/null @@ -1,36 +0,0 @@ -using MediaBrowser.Controller.Configuration; -using MediaBrowser.Controller.Entities; -using MediaBrowser.Controller.Library; -using MediaBrowser.Controller.Providers; -using MediaBrowser.Model.Entities; -using MediaBrowser.Model.IO; -using MediaBrowser.Providers.Manager; -using Microsoft.Extensions.Logging; - -namespace MediaBrowser.Providers.Games -{ - public class GameMetadataService : MetadataService<Game, GameInfo> - { - protected override void MergeData(MetadataResult<Game> source, MetadataResult<Game> target, MetadataFields[] lockedFields, bool replaceData, bool mergeMetadataSettings) - { - ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings); - - var sourceItem = source.Item; - var targetItem = target.Item; - - if (replaceData || string.IsNullOrEmpty(targetItem.GameSystem)) - { - targetItem.GameSystem = sourceItem.GameSystem; - } - - if (replaceData || !targetItem.PlayersSupported.HasValue) - { - targetItem.PlayersSupported = sourceItem.PlayersSupported; - } - } - - public GameMetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, IFileSystem fileSystem, IUserDataManager userDataManager, ILibraryManager libraryManager) : base(serverConfigurationManager, logger, providerManager, fileSystem, userDataManager, libraryManager) - { - } - } -} diff --git a/MediaBrowser.Providers/Games/GameSystemMetadataService.cs b/MediaBrowser.Providers/Games/GameSystemMetadataService.cs deleted file mode 100644 index 5bca4731c..000000000 --- a/MediaBrowser.Providers/Games/GameSystemMetadataService.cs +++ /dev/null @@ -1,31 +0,0 @@ -using MediaBrowser.Controller.Configuration; -using MediaBrowser.Controller.Entities; -using MediaBrowser.Controller.Library; -using MediaBrowser.Controller.Providers; -using MediaBrowser.Model.Entities; -using MediaBrowser.Model.IO; -using MediaBrowser.Providers.Manager; -using Microsoft.Extensions.Logging; - -namespace MediaBrowser.Providers.Games -{ - public class GameSystemMetadataService : MetadataService<GameSystem, GameSystemInfo> - { - protected override void MergeData(MetadataResult<GameSystem> source, MetadataResult<GameSystem> target, MetadataFields[] lockedFields, bool replaceData, bool mergeMetadataSettings) - { - ProviderUtils.MergeBaseItemData(source, target, lockedFields, replaceData, mergeMetadataSettings); - - var sourceItem = source.Item; - var targetItem = target.Item; - - if (replaceData || string.IsNullOrEmpty(targetItem.GameSystemName)) - { - targetItem.GameSystemName = sourceItem.GameSystemName; - } - } - - public GameSystemMetadataService(IServerConfigurationManager serverConfigurationManager, ILogger logger, IProviderManager providerManager, IFileSystem fileSystem, IUserDataManager userDataManager, ILibraryManager libraryManager) : base(serverConfigurationManager, logger, providerManager, fileSystem, userDataManager, libraryManager) - { - } - } -} diff --git a/MediaBrowser.Providers/Manager/ImageSaver.cs b/MediaBrowser.Providers/Manager/ImageSaver.cs index dee473374..ab906809f 100644 --- a/MediaBrowser.Providers/Manager/ImageSaver.cs +++ b/MediaBrowser.Providers/Manager/ImageSaver.cs @@ -420,7 +420,7 @@ namespace MediaBrowser.Providers.Manager filename = GetBackdropSaveFilename(item.GetImages(type), "screenshot", "screenshot", imageIndex); break; default: - filename = type.ToString().ToLower(); + filename = type.ToString().ToLowerInvariant(); break; } @@ -429,7 +429,7 @@ namespace MediaBrowser.Providers.Manager extension = ".jpg"; } - extension = extension.ToLower(); + extension = extension.ToLowerInvariant(); string path = null; diff --git a/MediaBrowser.Providers/Manager/ItemImageProvider.cs b/MediaBrowser.Providers/Manager/ItemImageProvider.cs index 493c97b6e..033aea146 100644 --- a/MediaBrowser.Providers/Manager/ItemImageProvider.cs +++ b/MediaBrowser.Providers/Manager/ItemImageProvider.cs @@ -148,7 +148,7 @@ namespace MediaBrowser.Providers.Manager } else { - var mimeType = "image/" + response.Format.ToString().ToLower(); + var mimeType = "image/" + response.Format.ToString().ToLowerInvariant(); await _providerManager.SaveImage(item, response.Stream, mimeType, imageType, null, cancellationToken).ConfigureAwait(false); } diff --git a/MediaBrowser.Providers/Manager/ProviderManager.cs b/MediaBrowser.Providers/Manager/ProviderManager.cs index eda5163f0..f26087fda 100644 --- a/MediaBrowser.Providers/Manager/ProviderManager.cs +++ b/MediaBrowser.Providers/Manager/ProviderManager.cs @@ -471,8 +471,6 @@ namespace MediaBrowser.Providers.Manager { return new MetadataPluginSummary[] { - GetPluginSummary<Game>(), - GetPluginSummary<GameSystem>(), GetPluginSummary<Movie>(), GetPluginSummary<BoxSet>(), GetPluginSummary<Book>(), diff --git a/MediaBrowser.Providers/MediaInfo/SubtitleResolver.cs b/MediaBrowser.Providers/MediaInfo/SubtitleResolver.cs index b6f862f9a..cd026b39b 100644 --- a/MediaBrowser.Providers/MediaInfo/SubtitleResolver.cs +++ b/MediaBrowser.Providers/MediaInfo/SubtitleResolver.cs @@ -119,7 +119,7 @@ namespace MediaBrowser.Providers.MediaInfo continue; } - var codec = Path.GetExtension(fullName).ToLower().TrimStart('.'); + var codec = Path.GetExtension(fullName).ToLowerInvariant().TrimStart('.'); if (string.Equals(codec, "txt", StringComparison.OrdinalIgnoreCase)) { diff --git a/MediaBrowser.Providers/MediaInfo/SubtitleScheduledTask.cs b/MediaBrowser.Providers/MediaInfo/SubtitleScheduledTask.cs index b7598ef22..74f41f9df 100644 --- a/MediaBrowser.Providers/MediaInfo/SubtitleScheduledTask.cs +++ b/MediaBrowser.Providers/MediaInfo/SubtitleScheduledTask.cs @@ -36,12 +36,6 @@ namespace MediaBrowser.Providers.MediaInfo _json = json; } - public string Name => "Download missing subtitles"; - - public string Description => "Searches the internet for missing subtitles based on metadata configuration."; - - public string Category => "Library"; - private SubtitleOptions GetOptions() { return _config.GetConfiguration<SubtitleOptions>("subtitles"); @@ -204,6 +198,18 @@ namespace MediaBrowser.Providers.MediaInfo }; } + public string Name => "Download missing subtitles"; + + public string Description => "Searches the internet for missing subtitles based on metadata configuration."; + + public string Category => "Library"; + public string Key => "DownloadSubtitles"; + + public bool IsHidden => false; + + public bool IsEnabled => true; + + public bool IsLogged => true; } } diff --git a/MediaBrowser.Providers/Movies/MovieDbProvider.cs b/MediaBrowser.Providers/Movies/MovieDbProvider.cs index c5af5ef36..3ff63a4bf 100644 --- a/MediaBrowser.Providers/Movies/MovieDbProvider.cs +++ b/MediaBrowser.Providers/Movies/MovieDbProvider.cs @@ -285,7 +285,7 @@ namespace MediaBrowser.Providers.Movies if (parts.Length == 2) { - language = parts[0] + "-" + parts[1].ToUpper(); + language = parts[0] + "-" + parts[1].ToUpperInvariant(); } } diff --git a/MediaBrowser.Providers/Movies/MovieDbSearch.cs b/MediaBrowser.Providers/Movies/MovieDbSearch.cs index 47d3d21bd..e466d40a0 100644 --- a/MediaBrowser.Providers/Movies/MovieDbSearch.cs +++ b/MediaBrowser.Providers/Movies/MovieDbSearch.cs @@ -72,7 +72,7 @@ namespace MediaBrowser.Providers.Movies } _logger.LogInformation("MovieDbProvider: Finding id for item: " + name); - var language = idInfo.MetadataLanguage.ToLower(); + var language = idInfo.MetadataLanguage.ToLowerInvariant(); //nope - search for it //var searchType = item is BoxSet ? "collection" : "movie"; diff --git a/MediaBrowser.Providers/Subtitles/SubtitleManager.cs b/MediaBrowser.Providers/Subtitles/SubtitleManager.cs index e247c4f86..7fc6909f5 100644 --- a/MediaBrowser.Providers/Subtitles/SubtitleManager.cs +++ b/MediaBrowser.Providers/Subtitles/SubtitleManager.cs @@ -159,14 +159,14 @@ namespace MediaBrowser.Providers.Subtitles memoryStream.Position = 0; var savePaths = new List<string>(); - var saveFileName = Path.GetFileNameWithoutExtension(video.Path) + "." + response.Language.ToLower(); + var saveFileName = Path.GetFileNameWithoutExtension(video.Path) + "." + response.Language.ToLowerInvariant(); if (response.IsForced) { saveFileName += ".forced"; } - saveFileName += "." + response.Format.ToLower(); + saveFileName += "." + response.Format.ToLowerInvariant(); if (saveInMediaFolder) { @@ -296,7 +296,7 @@ namespace MediaBrowser.Providers.Subtitles private string GetProviderId(string name) { - return name.ToLower().GetMD5().ToString("N"); + return name.ToLowerInvariant().GetMD5().ToString("N"); } private ISubtitleProvider GetProvider(string id) diff --git a/MediaBrowser.Providers/TV/TheTVDB/TvdbSeriesProvider.cs b/MediaBrowser.Providers/TV/TheTVDB/TvdbSeriesProvider.cs index 496e0bb72..6006ed052 100644 --- a/MediaBrowser.Providers/TV/TheTVDB/TvdbSeriesProvider.cs +++ b/MediaBrowser.Providers/TV/TheTVDB/TvdbSeriesProvider.cs @@ -66,7 +66,7 @@ namespace MediaBrowser.Providers.TV } // pt-br is just pt to tvdb - return language.Split('-')[0].ToLower(); + return language.Split('-')[0].ToLowerInvariant(); } public async Task<IEnumerable<RemoteSearchResult>> GetSearchResults(SeriesInfo searchInfo, CancellationToken cancellationToken) @@ -776,7 +776,7 @@ namespace MediaBrowser.Providers.TV /// <returns>System.String.</returns> private string GetComparableName(string name) { - name = name.ToLower(); + name = name.ToLowerInvariant(); name = _localizationManager.NormalizeFormKD(name); var sb = new StringBuilder(); foreach (var c in name) @@ -1620,7 +1620,7 @@ namespace MediaBrowser.Providers.TV { var seriesDataPath = GetSeriesDataPath(_config.ApplicationPaths, seriesProviderIds); - var seriesXmlFilename = language.ToLower() + ".xml"; + var seriesXmlFilename = language.ToLowerInvariant() + ".xml"; return Path.Combine(seriesDataPath, seriesXmlFilename); } diff --git a/MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs b/MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs index 96b906b3c..4925c7cd1 100644 --- a/MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs +++ b/MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs @@ -82,7 +82,6 @@ namespace MediaBrowser.XbmcMetadata.Savers "lockedfields", "zap2itid", "tvrageid", - "gamesdbid", "musicbrainzartistid", "musicbrainzalbumartistid", @@ -290,7 +289,7 @@ namespace MediaBrowser.XbmcMetadata.Savers foreach (var stream in mediaStreams) { - writer.WriteStartElement(stream.Type.ToString().ToLower()); + writer.WriteStartElement(stream.Type.ToString().ToLowerInvariant()); if (!string.IsNullOrEmpty(stream.Codec)) { @@ -471,7 +470,7 @@ namespace MediaBrowser.XbmcMetadata.Savers writer.WriteElementString("customrating", item.CustomRating); } - writer.WriteElementString("lockdata", item.IsLocked.ToString().ToLower()); + writer.WriteElementString("lockdata", item.IsLocked.ToString(CultureInfo.InvariantCulture).ToLowerInvariant()); if (item.LockedFields.Length > 0) { @@ -737,13 +736,6 @@ namespace MediaBrowser.XbmcMetadata.Savers writtenProviderIds.Add(MetadataProviders.MusicBrainzReleaseGroup.ToString()); } - externalId = item.GetProviderId(MetadataProviders.Gamesdb); - if (!string.IsNullOrEmpty(externalId)) - { - writer.WriteElementString("gamesdbid", externalId); - writtenProviderIds.Add(MetadataProviders.Gamesdb.ToString()); - } - externalId = item.GetProviderId(MetadataProviders.TvRage); if (!string.IsNullOrEmpty(externalId)) { @@ -871,21 +863,21 @@ namespace MediaBrowser.XbmcMetadata.Savers var userdata = userDataRepo.GetUserData(user, item); - writer.WriteElementString("isuserfavorite", userdata.IsFavorite.ToString().ToLower()); + writer.WriteElementString("isuserfavorite", userdata.IsFavorite.ToString(CultureInfo.InvariantCulture).ToLowerInvariant()); if (userdata.Rating.HasValue) { - writer.WriteElementString("userrating", userdata.Rating.Value.ToString(CultureInfo.InvariantCulture).ToLower()); + writer.WriteElementString("userrating", userdata.Rating.Value.ToString(CultureInfo.InvariantCulture).ToLowerInvariant()); } if (!item.IsFolder) { writer.WriteElementString("playcount", userdata.PlayCount.ToString(UsCulture)); - writer.WriteElementString("watched", userdata.Played.ToString().ToLower()); + writer.WriteElementString("watched", userdata.Played.ToString(CultureInfo.InvariantCulture).ToLowerInvariant()); if (userdata.LastPlayedDate.HasValue) { - writer.WriteElementString("lastplayed", userdata.LastPlayedDate.Value.ToLocalTime().ToString("yyyy-MM-dd HH:mm:ss").ToLower()); + writer.WriteElementString("lastplayed", userdata.LastPlayedDate.Value.ToLocalTime().ToString("yyyy-MM-dd HH:mm:ss").ToLowerInvariant()); } writer.WriteStartElement("resume"); @@ -901,12 +893,13 @@ namespace MediaBrowser.XbmcMetadata.Savers private void AddActors(List<PersonInfo> people, XmlWriter writer, ILibraryManager libraryManager, IFileSystem fileSystem, IServerConfigurationManager config, bool saveImagePath) { - var actors = people - .Where(i => !IsPersonType(i, PersonType.Director) && !IsPersonType(i, PersonType.Writer)) - .ToList(); - - foreach (var person in actors) + foreach (var person in people) { + if (IsPersonType(person, PersonType.Director) || IsPersonType(person, PersonType.Writer)) + { + continue; + } + writer.WriteStartElement("actor"); if (!string.IsNullOrWhiteSpace(person.Name)) @@ -1021,7 +1014,7 @@ namespace MediaBrowser.XbmcMetadata.Savers private string GetTagForProviderKey(string providerKey) { - return providerKey.ToLower() + "id"; + return providerKey.ToLowerInvariant() + "id"; } } } diff --git a/SocketHttpListener/Ext.cs b/SocketHttpListener/Ext.cs index b051b6718..a02b48061 100644 --- a/SocketHttpListener/Ext.cs +++ b/SocketHttpListener/Ext.cs @@ -486,7 +486,7 @@ namespace SocketHttpListener if (method == CompressionMethod.None) return string.Empty; - var m = string.Format("permessage-{0}", method.ToString().ToLower()); + var m = string.Format("permessage-{0}", method.ToString().ToLowerInvariant()); if (parameters == null || parameters.Length == 0) return m; diff --git a/SocketHttpListener/Net/HttpListenerRequest.cs b/SocketHttpListener/Net/HttpListenerRequest.cs index faeca78b2..667d58ea7 100644 --- a/SocketHttpListener/Net/HttpListenerRequest.cs +++ b/SocketHttpListener/Net/HttpListenerRequest.cs @@ -155,7 +155,7 @@ namespace SocketHttpListener.Net } else { - header = header.ToLower(CultureInfo.InvariantCulture); + header = header.ToLowerInvariant(); _keepAlive = header.IndexOf("close", StringComparison.OrdinalIgnoreCase) < 0 || header.IndexOf("keep-alive", StringComparison.OrdinalIgnoreCase) >= 0; diff --git a/deployment/debian-package-x64/pkg-src/conf/jellyfin b/deployment/debian-package-x64/pkg-src/conf/jellyfin index 861865aae..c237e2d69 100644 --- a/deployment/debian-package-x64/pkg-src/conf/jellyfin +++ b/deployment/debian-package-x64/pkg-src/conf/jellyfin @@ -1,4 +1,5 @@ # Jellyfin default configuration options +# This is a POSIX shell fragment # Use this file to override the default configurations; add additional # options with JELLYFIN_ADD_OPTS. @@ -8,10 +9,6 @@ # to override the user or this config file's location. # -# This is a POSIX shell fragment -# - -# # General options # @@ -19,10 +16,16 @@ JELLYFIN_DATA_DIRECTORY="/var/lib/jellyfin" JELLYFIN_CONFIG_DIRECTORY="/etc/jellyfin" JELLYFIN_LOG_DIRECTORY="/var/log/jellyfin" +JELLYFIN_CACHE_DIRECTORY="/var/cache/jellyfin" + # Restart script for in-app server control -JELLYFIN_RESTART_SCRIPT="/usr/lib/jellyfin/restart.sh" -# Additional options for the binary -JELLYFIN_ADD_OPTS="" +JELLYFIN_RESTART_OPT="--restartpath /usr/lib/jellyfin/restart.sh" + +# [OPTIONAL] ffmpeg binary paths +#JELLYFIN_FFMPEG_OPTS="--ffmpeg /usr/bin/ffmpeg --ffprobe /usr/bin/ffprobe" + +# [OPTIONAL] Additional user-defined options for the binary +#JELLYFIN_ADD_OPTS="" # # SysV init/Upstart options @@ -31,4 +34,4 @@ JELLYFIN_ADD_OPTS="" # Application username JELLYFIN_USER="jellyfin" # Full application command -JELLYFIN_ARGS="-programdata $JELLYFIN_DATA_DIRECTORY -configdir $JELLYFIN_CONFIG_DIRECTORY -logdir $JELLYFIN_LOG_DIRECTORY -restartpath $JELLYFIN_RESTART_SCRIPT $JELLYFIN_ADD_OPTS" +JELLYFIN_ARGS="--datadir $JELLYFIN_DATA_DIRECTORY --configdir $JELLYFIN_CONFIG_DIRECTORY --logdir $JELLYFIN_LOG_DIRECTORY --cachedir $JELLYFIN_CACHE_DIRECTORY $JELLYFIN_RESTART_OPT $JELLYFIN_FFMPEG_OPTS $JELLYFIN_ADD_OPTS" diff --git a/deployment/debian-package-x64/pkg-src/bin/jellyfin-sudoers b/deployment/debian-package-x64/pkg-src/conf/jellyfin-sudoers index 4eb91366b..4eb91366b 100644 --- a/deployment/debian-package-x64/pkg-src/bin/jellyfin-sudoers +++ b/deployment/debian-package-x64/pkg-src/conf/jellyfin-sudoers diff --git a/deployment/debian-package-x64/pkg-src/install b/deployment/debian-package-x64/pkg-src/install index adaff7b26..994322d14 100644 --- a/deployment/debian-package-x64/pkg-src/install +++ b/deployment/debian-package-x64/pkg-src/install @@ -2,5 +2,5 @@ usr/lib/jellyfin usr/lib/ debian/conf/jellyfin etc/default/ debian/conf/logging.json etc/jellyfin/ debian/conf/jellyfin.service.conf etc/systemd/system/jellyfin.service.d/ -debian/bin/jellyfin-sudoers etc/sudoers.d/ +debian/conf/jellyfin-sudoers etc/sudoers.d/ debian/bin/restart.sh usr/lib/jellyfin/ diff --git a/deployment/debian-package-x64/pkg-src/jellyfin.service b/deployment/debian-package-x64/pkg-src/jellyfin.service index c17422029..ee89d7d4b 100644 --- a/deployment/debian-package-x64/pkg-src/jellyfin.service +++ b/deployment/debian-package-x64/pkg-src/jellyfin.service @@ -6,7 +6,7 @@ After = network.target Type = simple EnvironmentFile = /etc/default/jellyfin User = jellyfin -ExecStart = /usr/bin/jellyfin -programdata ${JELLYFIN_DATA_DIRECTORY} -configdir ${JELLYFIN_CONFIG_DIRECTORY} -logdir ${JELLYFIN_LOG_DIRECTORY} -restartpath ${JELLYFIN_RESTART_SCRIPT} ${JELLYFIN_ADD_OPTS} +ExecStart = /usr/bin/jellyfin --datadir ${JELLYFIN_DATA_DIRECTORY} --configdir ${JELLYFIN_CONFIG_DIRECTORY} --logdir ${JELLYFIN_LOG_DIRECTORY} --cachedir ${JELLYFIN_CACHE_DIRECTORY} ${JELLYFIN_RESTART_OPT} ${JELLYFIN_FFMPEG_OPTS} ${JELLYFIN_ADD_OPTS} Restart = on-failure TimeoutSec = 15 diff --git a/deployment/debian-package-x64/pkg-src/postinst b/deployment/debian-package-x64/pkg-src/postinst index 3690d20ba..860222e05 100644 --- a/deployment/debian-package-x64/pkg-src/postinst +++ b/deployment/debian-package-x64/pkg-src/postinst @@ -13,6 +13,7 @@ fi PROGRAMDATA=${JELLYFIN_DATA_DIRECTORY-/var/lib/$NAME} CONFIGDATA=${JELLYFIN_CONFIG_DIRECTORY-/etc/$NAME} LOGDATA=${JELLYFIN_LOG_DIRECTORY-/var/log/$NAME} +CACHEDATA=${JELLYFIN_CACHE_DIRECTORY-/var/cache/$NAME} case "$1" in configure) @@ -37,10 +38,14 @@ case "$1" in if [[ ! -d $LOGDATA ]]; then mkdir $LOGDATA fi + # ensure $CACHEDATA exists + if [[ ! -d $CACHEDATA ]]; then + mkdir $CACHEDATA + fi # Ensure permissions are correct on all config directories - chown -R jellyfin:jellyfin $PROGRAMDATA - chown -R jellyfin:jellyfin $CONFIGDATA - chown -R jellyfin:jellyfin $LOGDATA + chown -R jellyfin $PROGRAMDATA $CONFIGDATA $LOGDATA $CACHEDATA + chgrp adm $PROGRAMDATA $CONFIGDATA $LOGDATA $CACHEDATA + chmod 0750 $PROGRAMDATA $CONFIGDATA $LOGDATA $CACHEDATA chmod +x /usr/lib/jellyfin/restart.sh > /dev/null 2>&1 || true diff --git a/deployment/debian-package-x64/pkg-src/postrm b/deployment/debian-package-x64/pkg-src/postrm index 690f5d587..1d00a984e 100644 --- a/deployment/debian-package-x64/pkg-src/postrm +++ b/deployment/debian-package-x64/pkg-src/postrm @@ -12,7 +12,8 @@ fi # Data directories for program data (cache, db), configs, and logs PROGRAMDATA=${JELLYFIN_DATA_DIRECTORY-/var/lib/$NAME} CONFIGDATA=${JELLYFIN_CONFIG_DIRECTORY-/etc/$NAME} -LOGDATA=${JELLYFIN_DATA_DIRECTORY-/var/log/$NAME} +LOGDATA=${JELLYFIN_LOG_DIRECTORY-/var/log/$NAME} +CACHEDATA=${JELLYFIN_CACHE_DIRECTORY-/var/cache/$NAME} # In case this system is running systemd, we make systemd reload the unit files # to pick up changes. @@ -44,6 +45,10 @@ case "$1" in if [[ -d $LOGDATA ]]; then rm -rf $LOGDATA fi + # Remove cache dir + if [[ -d $CACHEDATA ]]; then + rm -rf $CACHEDATA + fi # Remove program data dir if [[ -d $PROGRAMDATA ]]; then rm -rf $PROGRAMDATA @@ -55,6 +60,7 @@ case "$1" in # Remove anything at the default locations; catches situations where the user moved the defaults [[ -e /etc/jellyfin ]] && rm -rf /etc/jellyfin [[ -e /var/log/jellyfin ]] && rm -rf /var/log/jellyfin + [[ -e /var/cache/jellyfin ]] && rm -rf /var/cache/jellyfin [[ -e /var/lib/jellyfin ]] && rm -rf /var/lib/jellyfin ;; remove) diff --git a/deployment/debian-package-x64/pkg-src/preinst b/deployment/debian-package-x64/pkg-src/preinst index 0063e0e63..2713fb9b8 100644 --- a/deployment/debian-package-x64/pkg-src/preinst +++ b/deployment/debian-package-x64/pkg-src/preinst @@ -12,7 +12,8 @@ fi # Data directories for program data (cache, db), configs, and logs PROGRAMDATA=${JELLYFIN_DATA_DIRECTORY-/var/lib/$NAME} CONFIGDATA=${JELLYFIN_CONFIG_DIRECTORY-/etc/$NAME} -LOGDATA=${JELLYFIN_DATA_DIRECTORY-/var/log/$NAME} +LOGDATA=${JELLYFIN_LOG_DIRECTORY-/var/log/$NAME} +CACHEDATA=${JELLYFIN_CACHE_DIRECTORY-/var/cache/$NAME} # In case this system is running systemd, we make systemd reload the unit files # to pick up changes. @@ -53,13 +54,16 @@ case "$1" in # Clean up old Emby cruft that can break the user's system [[ -f /etc/sudoers.d/emby ]] && rm -f /etc/sudoers.d/emby - # If we have existing config or log dirs in /var/lib/jellyfin, move them into the right place + # If we have existing config, log, or cache dirs in /var/lib/jellyfin, move them into the right place if [[ -d $PROGRAMDATA/config ]]; then mv $PROGRAMDATA/config $CONFIGDATA fi if [[ -d $PROGRAMDATA/logs ]]; then mv $PROGRAMDATA/logs $LOGDATA fi + if [[ -d $PROGRAMDATA/logs ]]; then + mv $PROGRAMDATA/cache $CACHEDATA + fi ;; abort-upgrade) diff --git a/deployment/debian-package-x64/pkg-src/prerm b/deployment/debian-package-x64/pkg-src/prerm index 4770c03c4..e965cb7d7 100644 --- a/deployment/debian-package-x64/pkg-src/prerm +++ b/deployment/debian-package-x64/pkg-src/prerm @@ -12,7 +12,8 @@ fi # Data directories for program data (cache, db), configs, and logs PROGRAMDATA=${JELLYFIN_DATA_DIRECTORY-/var/lib/$NAME} CONFIGDATA=${JELLYFIN_CONFIG_DIRECTORY-/etc/$NAME} -LOGDATA=${JELLYFIN_DATA_DIRECTORY-/var/log/$NAME} +LOGDATA=${JELLYFIN_LOG_DIRECTORY-/var/log/$NAME} +CACHEDATA=${JELLYFIN_CACHE_DIRECTORY-/var/cache/$NAME} case "$1" in remove|upgrade|deconfigure) diff --git a/deployment/fedora-package-x64/pkg-src/jellyfin.env b/deployment/fedora-package-x64/pkg-src/jellyfin.env index 827a33f46..f7f041f75 100644 --- a/deployment/fedora-package-x64/pkg-src/jellyfin.env +++ b/deployment/fedora-package-x64/pkg-src/jellyfin.env @@ -15,13 +15,14 @@ # # Tell jellyfin wich ffmpeg/ffprobe to use -# JELLYFIN_FFMPEG="-ffmpeg /usr/bin/ffmpeg -ffprobe /usr/bin/ffprobe" +# JELLYFIN_FFMPEG="--ffmpeg /usr/bin/ffmpeg --ffprobe /usr/bin/ffprobe" # Program directories JELLYFIN_DATA_DIRECTORY="/var/lib/jellyfin" JELLYFIN_CONFIG_DIRECTORY="/etc/jellyfin" JELLYFIN_LOG_DIRECTORY="/var/log/jellyfin" +JELLYFIN_CACHE_DIRECTORY="/var/log/jellyfin" # In-App service control -JELLYFIN_RESTART_OPT="-restartpath /usr/libexec/jellyfin/restart.sh" +JELLYFIN_RESTART_OPT="--restartpath /usr/libexec/jellyfin/restart.sh" # Additional options for the binary -JELLYFIN_ADD_OPTS=""
\ No newline at end of file +JELLYFIN_ADD_OPTS="" diff --git a/deployment/fedora-package-x64/pkg-src/jellyfin.service b/deployment/fedora-package-x64/pkg-src/jellyfin.service index 0ece5b57f..56703a98a 100644 --- a/deployment/fedora-package-x64/pkg-src/jellyfin.service +++ b/deployment/fedora-package-x64/pkg-src/jellyfin.service @@ -5,7 +5,7 @@ Description=Jellyfin is a free software media system that puts you in control of [Service] EnvironmentFile=/etc/sysconfig/jellyfin WorkingDirectory=/var/lib/jellyfin -ExecStart=/usr/bin/jellyfin -programdata ${JELLYFIN_DATA_DIRECTORY} -configdir ${JELLYFIN_CONFIG_DIRECTORY} -logdir ${JELLYFIN_LOG_DIRECTORY} ${JELLYFIN_RESTART_OPT} ${JELLYFIN_ADD_OPTS} ${JELLYFIN_FFMPEG} +ExecStart=/usr/bin/jellyfin --datadir ${JELLYFIN_DATA_DIRECTORY} --configdir ${JELLYFIN_CONFIG_DIRECTORY} --logdir ${JELLYFIN_LOG_DIRECTORY} --cachedir ${JELLYFIN_CACHE_DIRECTORY} ${JELLYFIN_RESTART_OPT} ${JELLYFIN_ADD_OPTS} ${JELLYFIN_FFMPEG} TimeoutSec=15 Restart=on-failure User=jellyfin diff --git a/deployment/win-generic/install-jellyfin.ps1 b/deployment/win-generic/install-jellyfin.ps1 index 56c098462..b6e00e056 100644 --- a/deployment/win-generic/install-jellyfin.ps1 +++ b/deployment/win-generic/install-jellyfin.ps1 @@ -93,12 +93,12 @@ if($Quiet.IsPresent -or $Quiet -eq $true){ Copy-Item -Path $PSScriptRoot/* -DestinationPath "$Script:DefaultJellyfinInstallDirectory/" -Force -Recurse if($Script:InstallAsService){ if($Script:InstallServiceAsUser){ - &"$Script:DefaultJellyfinInstallDirectory\nssm.exe" install Jellyfin `"$Script:DefaultJellyfinInstallDirectory\jellyfin.exe`" -programdata `"$Script:JellyfinDataDir`" + &"$Script:DefaultJellyfinInstallDirectory\nssm.exe" install Jellyfin `"$Script:DefaultJellyfinInstallDirectory\jellyfin.exe`" --datadir `"$Script:JellyfinDataDir`" Start-Sleep -Milliseconds 500 &sc.exe config Jellyfin obj=".\$($Script:UserCredentials.UserName)" password="$($Script:UserCredentials.GetNetworkCredential().Password)" &"$Script:DefaultJellyfinInstallDirectory\nssm.exe" set Jellyfin Start SERVICE_DELAYED_AUTO_START }else{ - &"$Script:DefaultJellyfinInstallDirectory\nssm.exe" install Jellyfin `"$Script:DefaultJellyfinInstallDirectory\jellyfin.exe`" -programdata `"$Script:JellyfinDataDir`" + &"$Script:DefaultJellyfinInstallDirectory\nssm.exe" install Jellyfin `"$Script:DefaultJellyfinInstallDirectory\jellyfin.exe`" --datadir `"$Script:JellyfinDataDir`" Start-Sleep -Milliseconds 500 #&"$Script:DefaultJellyfinInstallDirectory\nssm.exe" set Jellyfin ObjectName $Script:UserCredentials.UserName $Script:UserCredentials.GetNetworkCredential().Password #Set-Service -Name Jellyfin -Credential $Script:UserCredentials @@ -171,13 +171,13 @@ function InstallJellyfin { if($Script:InstallAsService){ if($Script:InstallServiceAsUser){ Write-Host "Installing Service as user $($Script:UserCredentials.UserName)" - &"$Script:DefaultJellyfinInstallDirectory\nssm.exe" install Jellyfin `"$Script:DefaultJellyfinInstallDirectory\jellyfin.exe`" -programdata `"$Script:JellyfinDataDir`" + &"$Script:DefaultJellyfinInstallDirectory\nssm.exe" install Jellyfin `"$Script:DefaultJellyfinInstallDirectory\jellyfin.exe`" --datadir `"$Script:JellyfinDataDir`" Start-Sleep -Milliseconds 2000 &sc.exe config Jellyfin obj=".\$($Script:UserCredentials.UserName)" password="$($Script:UserCredentials.GetNetworkCredential().Password)" &"$Script:DefaultJellyfinInstallDirectory\nssm.exe" set Jellyfin Start SERVICE_DELAYED_AUTO_START }else{ Write-Host "Installing Service as LocalSystem" - &"$Script:DefaultJellyfinInstallDirectory\nssm.exe" install Jellyfin `"$Script:DefaultJellyfinInstallDirectory\jellyfin.exe`" -programdata `"$Script:JellyfinDataDir`" + &"$Script:DefaultJellyfinInstallDirectory\nssm.exe" install Jellyfin `"$Script:DefaultJellyfinInstallDirectory\jellyfin.exe`" --datadir `"$Script:JellyfinDataDir`" Start-Sleep -Milliseconds 2000 &"$Script:DefaultJellyfinInstallDirectory\nssm.exe" set Jellyfin Start SERVICE_DELAYED_AUTO_START } @@ -457,4 +457,4 @@ $StartProgramCheck.Add_CheckedChanged({StartJellyFinBoxCheckChanged}) #endregion GUI } -[void]$InstallForm.ShowDialog()
\ No newline at end of file +[void]$InstallForm.ShowDialog() |
