diff options
318 files changed, 1551 insertions, 4770 deletions
diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 4abd39cfc..137a689e8 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -8,23 +8,23 @@ assignees: '' --- **Describe the bug** -A clear and concise description of what the bug is. +<!-- A clear and concise description of what the bug is. --> **To Reproduce** -Steps to reproduce the behavior: +<!-- Steps to reproduce the behavior: --> 1. Go to '...' 2. Click on '....' 3. Scroll down to '....' 4. See error **Expected behavior** -A clear and concise description of what you expected to happen. +<!-- A clear and concise description of what you expected to happen. --> **Logs** -Please paste any log errors. +<!-- Please paste any log errors. --> **Screenshots** -If applicable, add screenshots to help explain your problem. +<!-- If applicable, add screenshots to help explain your problem. --> **System (please complete the following information):** - OS: [e.g. Docker, Debian, Windows] @@ -32,4 +32,4 @@ If applicable, add screenshots to help explain your problem. - Jellyfin Version: [e.g. 10.0.1] **Additional context** -Add any other context about the problem here. +<!-- Add any other context about the problem here. --> diff --git a/.github/ISSUE_TEMPLATE/enhancement-request.md b/.github/ISSUE_TEMPLATE/enhancement-request.md index 57c0d4cae..a655b60f5 100644 --- a/.github/ISSUE_TEMPLATE/enhancement-request.md +++ b/.github/ISSUE_TEMPLATE/enhancement-request.md @@ -8,13 +8,13 @@ assignees: '' --- **Is your feature request related to a problem? Please describe.** -A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] +<!-- A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] --> **Describe the solution you'd like** -A clear and concise description of what you want to happen. +<!-- A clear and concise description of what you want to happen. --> **Describe alternatives you've considered** -A clear and concise description of any alternative solutions or features you've considered. +<!-- A clear and concise description of any alternative solutions or features you've considered. --> **Additional context** -Add any other context or screenshots about the feature request here. +<!-- Add any other context or screenshots about the feature request here. --> diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md index a2ce07245..3cbc8cbb9 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -8,7 +8,7 @@ assignees: '' --- **Describe the feature you'd like** -A clear and concise description of what you want to happen. +<!-- A clear and concise description of what you want to happen. --> **Additional context** -Add any other context or screenshots about the feature request here. +<!-- Add any other context or screenshots about the feature request here. --> diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index b2b3cf241..967be0fb7 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -1,9 +1,11 @@ +<!-- Ensure your title is short, descriptive, and in the imperative mood (Fix X, Change Y, instead of Fixed X, Changed Y). For a good inspiration of what to write in commit messages and PRs please review https://chris.beams.io/posts/git-commit/ and our https://jellyfin.readthedocs.io/en/latest/developer-docs/contributing/ page. +--> **Changes** -Describe your changes here in 1-5 sentences. +<!-- Describe your changes here in 1-5 sentences. --> **Issues** -Tag any issues that this PR solves here. -Fixes # +<!-- Tag any issues that this PR solves here. +ex. Fixes # --> diff --git a/BDInfo/BDROM.cs b/BDInfo/BDROM.cs index 4cd636023..4360ff1d4 100644 --- a/BDInfo/BDROM.cs +++ b/BDInfo/BDROM.cs @@ -92,7 +92,7 @@ namespace BDInfo } DirectoryRoot = - _fileSystem.GetDirectoryInfo(_fileSystem.GetDirectoryName(DirectoryBDMV.FullName)); + _fileSystem.GetDirectoryInfo(Path.GetDirectoryName(DirectoryBDMV.FullName)); DirectoryBDJO = GetDirectory("BDJO", DirectoryBDMV, 0); DirectoryCLIPINF = @@ -150,7 +150,7 @@ namespace BDInfo Is3D = true; } - if (_fileSystem.FileExists(Path.Combine(DirectoryRoot.FullName, "FilmIndex.xml"))) + if (File.Exists(Path.Combine(DirectoryRoot.FullName, "FilmIndex.xml"))) { IsDBOX = true; } @@ -345,7 +345,7 @@ namespace BDInfo { return dir; } - var parentFolder = _fileSystem.GetDirectoryName(dir.FullName); + var parentFolder = Path.GetDirectoryName(dir.FullName); if (string.IsNullOrEmpty(parentFolder)) { dir = null; diff --git a/BDInfo/TSPlaylistFile.cs b/BDInfo/TSPlaylistFile.cs index 8c98d44d7..6e91f6e40 100644 --- a/BDInfo/TSPlaylistFile.cs +++ b/BDInfo/TSPlaylistFile.cs @@ -1,4 +1,4 @@ -//============================================================================ +//============================================================================ // BDInfo - Blu-ray Video and Audio Analysis Tool // Copyright © 2010 Cinema Squid // @@ -231,7 +231,7 @@ namespace BDInfo Streams.Clear(); StreamClips.Clear(); - fileStream = _fileSystem.OpenRead(FileInfo.FullName); + fileStream = File.OpenRead(FileInfo.FullName); fileReader = new BinaryReader(fileStream); byte[] data = new byte[fileStream.Length]; diff --git a/BDInfo/TSStreamClipFile.cs b/BDInfo/TSStreamClipFile.cs index 3396f4c71..d840542ba 100644 --- a/BDInfo/TSStreamClipFile.cs +++ b/BDInfo/TSStreamClipFile.cs @@ -1,4 +1,4 @@ -//============================================================================ +//============================================================================ // BDInfo - Blu-ray Video and Audio Analysis Tool // Copyright © 2010 Cinema Squid // @@ -57,7 +57,7 @@ namespace BDInfo #endif Streams.Clear(); - fileStream = _fileSystem.OpenRead(FileInfo.FullName); + fileStream = File.OpenRead(FileInfo.FullName); fileReader = new BinaryReader(fileStream); byte[] data = new byte[fileStream.Length]; diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index d918b7b95..5e3455fba 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -15,7 +15,9 @@ - [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) # Emby Contributors diff --git a/Dockerfile b/Dockerfile index 4f727b4b4..37388fda9 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,15 +1,5 @@ ARG DOTNET_VERSION=2 - -# Download ffmpeg first to allow quicker rebuild of other layers -FROM alpine as ffmpeg -ARG FFMPEG_URL=https://www.johnvansickle.com/ffmpeg/old-releases/ffmpeg-4.0.3-64bit-static.tar.xz -RUN wget ${FFMPEG_URL} -O - | tar Jxf - \ - && mkdir ffmpeg-bin \ - && mv ffmpeg*/ffmpeg ffmpeg-bin \ - && mv ffmpeg*/ffprobe ffmpeg-bin - - FROM microsoft/dotnet:${DOTNET_VERSION}-sdk as builder WORKDIR /repo COPY . . @@ -20,7 +10,7 @@ RUN export DOTNET_CLI_TELEMETRY_OPTOUT=1 \ --output /jellyfin \ Jellyfin.Server - +FROM jrottenberg/ffmpeg:4.0-scratch as ffmpeg FROM microsoft/dotnet:${DOTNET_VERSION}-runtime # libfontconfig1 is required for Skia RUN apt-get update \ @@ -29,8 +19,8 @@ RUN apt-get update \ && apt-get clean autoclean \ && apt-get autoremove \ && rm -rf /var/lib/{apt,dpkg,cache,log} +COPY --from=ffmpeg / / COPY --from=builder /jellyfin /jellyfin -COPY --from=ffmpeg /ffmpeg-bin/* /usr/bin/ 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 440f96b3f..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++; @@ -932,7 +932,7 @@ namespace Emby.Dlna.Didl private void AddCover(BaseItem item, BaseItem context, StubType? stubType, XmlWriter writer) { - ImageDownloadInfo imageInfo = GetImageInfo(item);; + ImageDownloadInfo imageInfo = GetImageInfo(item); if (imageInfo == null) { @@ -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 3be596865..c507b14e9 100644 --- a/Emby.Dlna/DlnaManager.cs +++ b/Emby.Dlna/DlnaManager.cs @@ -301,7 +301,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); @@ -353,7 +353,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 } @@ -380,7 +380,7 @@ namespace Emby.Dlna if (!fileInfo.Exists || fileInfo.Length != stream.Length) { - _fileSystem.CreateDirectory(systemProfilesPath); + Directory.CreateDirectory(systemProfilesPath); using (var fileStream = _fileSystem.GetFileStream(path, FileOpenMode.Create, FileAccessMode.Write, FileShareMode.Read)) { @@ -391,7 +391,7 @@ namespace Emby.Dlna } // Not necessary, but just to make it easy to find - _fileSystem.CreateDirectory(UserProfilesPath); + Directory.CreateDirectory(UserProfilesPath); } public void DeleteProfile(string id) @@ -507,7 +507,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 89cba4c47..7398b24cd 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 8ac2b9b27..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) { @@ -244,7 +244,7 @@ namespace Emby.Drawing try { - if (!_fileSystem.FileExists(cacheFilePath)) + if (!File.Exists(cacheFilePath)) { if (options.CropWhiteSpace && !SupportsTransparency(originalImagePath)) { @@ -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) @@ -626,12 +626,12 @@ namespace Emby.Drawing try { // Check again in case of contention - if (_fileSystem.FileExists(enhancedImagePath)) + if (File.Exists(enhancedImagePath)) { return (enhancedImagePath, treatmentRequiresTransparency); } - _fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(enhancedImagePath)); + Directory.CreateDirectory(Path.GetDirectoryName(enhancedImagePath)); await ExecuteImageEnhancers(supportedEnhancers, originalImagePath, enhancedImagePath, item, imageType, imageIndex).ConfigureAwait(false); diff --git a/Emby.IsoMounting/IsoMounter/LinuxIsoManager.cs b/Emby.IsoMounting/IsoMounter/LinuxIsoManager.cs index ac486f167..a6fc53953 100644 --- a/Emby.IsoMounting/IsoMounter/LinuxIsoManager.cs +++ b/Emby.IsoMounting/IsoMounter/LinuxIsoManager.cs @@ -39,7 +39,7 @@ namespace IsoMounter _logger = logger; ProcessFactory = processFactory; - MountPointRoot = FileSystem.DirectorySeparatorChar + "tmp" + FileSystem.DirectorySeparatorChar + "Emby"; + MountPointRoot = Path.DirectorySeparatorChar + "tmp" + Path.DirectorySeparatorChar + "Emby"; _logger.LogDebug( "[{0}] System PATH is currently set to [{1}].", @@ -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) @@ -214,9 +214,9 @@ namespace IsoMounter { string path = test.Trim(); - if (!string.IsNullOrEmpty(path) && FileSystem.FileExists(path = Path.Combine(path, name))) + if (!string.IsNullOrEmpty(path) && File.Exists(path = Path.Combine(path, name))) { - return FileSystem.GetFullPath(path); + return Path.GetFullPath(path); } } @@ -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 ); @@ -327,7 +326,7 @@ namespace IsoMounter try { - FileSystem.CreateDirectory(mountPoint); + Directory.CreateDirectory(mountPoint); } catch (UnauthorizedAccessException) { @@ -377,7 +376,7 @@ namespace IsoMounter try { - FileSystem.DeleteDirectory(mountPoint, false); + Directory.Delete(mountPoint, false); } catch (Exception ex) { @@ -455,7 +454,7 @@ namespace IsoMounter try { - FileSystem.DeleteDirectory(mount.MountedPath, false); + Directory.Delete(mount.MountedPath, false); } catch (Exception ex) { diff --git a/Emby.Naming/Video/VideoListResolver.cs b/Emby.Naming/Video/VideoListResolver.cs index 0506d0734..ef97b8739 100644 --- a/Emby.Naming/Video/VideoListResolver.cs +++ b/Emby.Naming/Video/VideoListResolver.cs @@ -175,71 +175,23 @@ namespace Emby.Naming.Video return videos; } - var list = new List<VideoInfo>(); - var folderName = Path.GetFileName(Path.GetDirectoryName(videos[0].Files[0].Path)); if (!string.IsNullOrEmpty(folderName) && folderName.Length > 1) { - if (videos.All(i => i.Files.Count == 1 && IsEligibleForMultiVersion(folderName, i.Files[0].Path))) - { - // Enforce the multi-version limit - if (videos.Count <= 8 && HaveSameYear(videos)) - { - var ordered = videos.OrderBy(i => i.Name).ToList(); - - list.Add(ordered[0]); - - list[0].AlternateVersions = ordered.Skip(1).Select(i => i.Files[0]).ToList(); - list[0].Name = folderName; - list[0].Extras.AddRange(ordered.Skip(1).SelectMany(i => i.Extras)); + var ordered = videos.OrderBy(i => i.Name); - return list; - } - } + return ordered.GroupBy(v => new {v.Name, v.Year}).Select(group => new VideoInfo + { + Name = folderName, + Year = group.First().Year, + Files = group.First().Files, + AlternateVersions = group.Skip(1).Select(i => i.Files[0]).ToList(), + Extras = group.First().Extras.Concat(group.Skip(1).SelectMany(i => i.Extras)).ToList() + }); } return videos; - //foreach (var video in videos.OrderBy(i => i.Name)) - //{ - // var match = list - // .FirstOrDefault(i => string.Equals(i.Name, video.Name, StringComparison.OrdinalIgnoreCase)); - - // if (match != null && video.Files.Count == 1 && match.Files.Count == 1) - // { - // match.AlternateVersions.Add(video.Files[0]); - // match.Extras.AddRange(video.Extras); - // } - // else - // { - // list.Add(video); - // } - //} - - //return list; - } - - private bool HaveSameYear(List<VideoInfo> videos) - { - return videos.Select(i => i.Year ?? -1).Distinct().Count() < 2; - } - - private bool IsEligibleForMultiVersion(string folderName, string testFilename) - { - testFilename = Path.GetFileNameWithoutExtension(testFilename); - - if (string.Equals(folderName, testFilename, StringComparison.OrdinalIgnoreCase)) - { - return true; - } - - if (testFilename.StartsWith(folderName, StringComparison.OrdinalIgnoreCase)) - { - testFilename = testFilename.Substring(folderName.Length).Trim(); - return testFilename.StartsWith("-", StringComparison.OrdinalIgnoreCase) || Regex.Replace(testFilename, @"\[([^]]*)\]", "").Trim() == string.Empty; - } - - return false; } private List<VideoFileInfo> GetExtras(IEnumerable<VideoFileInfo> remainingFiles, List<string> baseNames) 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 9cdb3b1b5..739f68767 100644 --- a/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs +++ b/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs @@ -210,10 +210,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(); @@ -228,10 +224,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(); @@ -504,7 +496,6 @@ namespace Emby.Server.Implementations.Activity _sessionManager.PlaybackStart -= _sessionManager_PlaybackStart; _sessionManager.PlaybackStopped -= _sessionManager_PlaybackStopped; - _subManager.SubtitlesDownloaded -= _subManager_SubtitlesDownloaded; _subManager.SubtitleDownloadFailure -= _subManager_SubtitleDownloadFailure; _userManager.UserCreated -= _userManager_UserCreated; 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 59c7c655f..460809e93 100644 --- a/Emby.Server.Implementations/AppBase/BaseConfigurationManager.cs +++ b/Emby.Server.Implementations/AppBase/BaseConfigurationManager.cs @@ -127,7 +127,7 @@ namespace Emby.Server.Implementations.AppBase Logger.LogInformation("Saving system configuration"); var path = CommonApplicationPaths.SystemConfigurationFilePath; - FileSystem.CreateDirectory(FileSystem.GetDirectoryName(path)); + Directory.CreateDirectory(Path.GetDirectoryName(path)); lock (_configurationSyncLock) { @@ -197,7 +197,7 @@ namespace Emby.Server.Implementations.AppBase && !string.Equals(CommonConfiguration.CachePath ?? string.Empty, newPath)) { // Validate - if (!FileSystem.DirectoryExists(newPath)) + if (!Directory.Exists(newPath)) { throw new FileNotFoundException(string.Format("{0} does not exist.", newPath)); } @@ -209,8 +209,7 @@ namespace Emby.Server.Implementations.AppBase protected void EnsureWriteAccess(string path) { var file = Path.Combine(path, Guid.NewGuid().ToString()); - - FileSystem.WriteAllText(file, string.Empty); + File.WriteAllText(file, string.Empty); FileSystem.DeleteFile(file); } @@ -218,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) @@ -246,13 +245,14 @@ namespace Emby.Server.Implementations.AppBase private object LoadConfiguration(string path, Type configurationType) { - try + if (!File.Exists(path)) { - return XmlSerializer.DeserializeFromFile(configurationType, path); + return Activator.CreateInstance(configurationType); } - catch (FileNotFoundException) + + try { - return Activator.CreateInstance(configurationType); + return XmlSerializer.DeserializeFromFile(configurationType, path); } catch (IOException) { @@ -293,7 +293,7 @@ namespace Emby.Server.Implementations.AppBase _configurations.AddOrUpdate(key, configuration, (k, v) => configuration); var path = GetConfigurationFile(key); - FileSystem.CreateDirectory(FileSystem.GetDirectoryName(path)); + Directory.CreateDirectory(Path.GetDirectoryName(path)); lock (_configurationSyncLock) { diff --git a/Emby.Server.Implementations/AppBase/ConfigurationHelper.cs b/Emby.Server.Implementations/AppBase/ConfigurationHelper.cs index ee6da95fe..3faad76e7 100644 --- a/Emby.Server.Implementations/AppBase/ConfigurationHelper.cs +++ b/Emby.Server.Implementations/AppBase/ConfigurationHelper.cs @@ -29,7 +29,7 @@ namespace Emby.Server.Implementations.AppBase // Use try/catch to avoid the extra file system lookup using File.Exists try { - buffer = fileSystem.ReadAllBytes(path); + buffer = File.ReadAllBytes(path); configuration = xmlSerializer.DeserializeFromBytes(type, buffer); } @@ -48,10 +48,10 @@ namespace Emby.Server.Implementations.AppBase // If the file didn't exist before, or if something has changed, re-save if (buffer == null || !buffer.SequenceEqual(newBytes)) { - fileSystem.CreateDirectory(fileSystem.GetDirectoryName(path)); + Directory.CreateDirectory(Path.GetDirectoryName(path)); // Save it after load in case we got new items - fileSystem.WriteAllBytes(path, newBytes); + File.WriteAllBytes(path, newBytes); } return configuration; diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs index c71b917b8..365eb5856 100644 --- a/Emby.Server.Implementations/ApplicationHost.cs +++ b/Emby.Server.Implementations/ApplicationHost.cs @@ -110,9 +110,7 @@ using MediaBrowser.XbmcMetadata.Providers; using Microsoft.Extensions.Logging; using ServiceStack; using ServiceStack.Text.Jsv; -using StringExtensions = MediaBrowser.Controller.Extensions.StringExtensions; using X509Certificate = System.Security.Cryptography.X509Certificates.X509Certificate; -using UtfUnknown; namespace Emby.Server.Implementations { @@ -142,7 +140,7 @@ namespace Emby.Server.Implementations return false; } - if (StartupOptions.ContainsOption("-service")) + if (StartupOptions.IsService) { return false; } @@ -303,7 +301,7 @@ namespace Emby.Server.Implementations private ILiveTvManager LiveTvManager { get; set; } - public ILocalizationManager LocalizationManager { get; set; } + public LocalizationManager LocalizationManager { get; set; } private IEncodingManager EncodingManager { get; set; } private IChannelManager ChannelManager { get; set; } @@ -344,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; } @@ -365,7 +363,7 @@ namespace Emby.Server.Implementations /// </summary> public ApplicationHost(ServerApplicationPaths applicationPaths, ILoggerFactory loggerFactory, - StartupOptions options, + IStartupOptions options, IFileSystem fileSystem, IEnvironmentInfo environmentInfo, IImageEncoder imageEncoder, @@ -697,7 +695,7 @@ namespace Emby.Server.Implementations } } - public void Init() + public async Task Init() { HttpPort = ServerConfigurationManager.Configuration.HttpServerPortNumber; HttpsPort = ServerConfigurationManager.Configuration.HttpsPortNumber; @@ -727,7 +725,7 @@ namespace Emby.Server.Implementations SetHttpLimit(); - RegisterResources(); + await RegisterResources(); FindParts(); } @@ -742,7 +740,7 @@ namespace Emby.Server.Implementations /// <summary> /// Registers resources that classes will depend on /// </summary> - protected void RegisterResources() + protected async Task RegisterResources() { RegisterSingleInstance(ConfigurationManager); RegisterSingleInstance<IApplicationHost>(this); @@ -803,9 +801,9 @@ namespace Emby.Server.Implementations IAssemblyInfo assemblyInfo = new AssemblyInfo(); RegisterSingleInstance(assemblyInfo); - LocalizationManager = new LocalizationManager(ServerConfigurationManager, FileSystemManager, JsonSerializer, LoggerFactory, assemblyInfo, new TextLocalizer()); - StringExtensions.LocalizationManager = LocalizationManager; - RegisterSingleInstance(LocalizationManager); + LocalizationManager = new LocalizationManager(ServerConfigurationManager, FileSystemManager, JsonSerializer, LoggerFactory); + await LocalizationManager.LoadAll(); + RegisterSingleInstance<ILocalizationManager>(LocalizationManager); BlurayExaminer = new BdInfoExaminer(FileSystemManager); RegisterSingleInstance(BlurayExaminer); @@ -874,7 +872,7 @@ namespace Emby.Server.Implementations MediaSourceManager = new MediaSourceManager(ItemRepository, ApplicationPaths, LocalizationManager, UserManager, LibraryManager, LoggerFactory, JsonSerializer, FileSystemManager, UserDataManager, TimerFactory, () => MediaEncoder); RegisterSingleInstance(MediaSourceManager); - SubtitleManager = new SubtitleManager(LoggerFactory, FileSystemManager, LibraryMonitor, MediaSourceManager, ServerConfigurationManager, LocalizationManager); + SubtitleManager = new SubtitleManager(LoggerFactory, FileSystemManager, LibraryMonitor, MediaSourceManager, LocalizationManager); RegisterSingleInstance(SubtitleManager); ProviderManager = new ProviderManager(HttpClient, SubtitleManager, ServerConfigurationManager, LibraryMonitor, LoggerFactory, FileSystemManager, ApplicationPaths, () => LibraryManager, JsonSerializer); @@ -898,7 +896,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); @@ -1001,7 +999,7 @@ namespace Emby.Server.Implementations try { - if (!FileSystemManager.FileExists(certificateLocation)) + if (!File.Exists(certificateLocation)) { return null; } @@ -1427,7 +1425,7 @@ namespace Emby.Server.Implementations //if (generateCertificate) //{ - // if (!FileSystemManager.FileExists(certPath)) + // if (!File.Exists(certPath)) // { // FileSystemManager.CreateDirectory(FileSystemManager.GetDirectoryName(certPath)); @@ -1557,7 +1555,7 @@ namespace Emby.Server.Implementations /// <returns>IEnumerable{Assembly}.</returns> protected List<Tuple<Assembly, string>> GetComposablePartAssemblies() { - var list = GetPluginAssemblies(); + var list = GetPluginAssemblies(ApplicationPaths.PluginsPath); // Gets all plugin assemblies by first reading all bytes of the .dll and calling Assembly.Load against that // This will prevent the .dll file from getting locked, and allow us to replace it when needed @@ -1608,79 +1606,6 @@ namespace Emby.Server.Implementations protected abstract IEnumerable<Assembly> GetAssembliesWithPartsInternal(); - /// <summary> - /// Gets the plugin assemblies. - /// </summary> - /// <returns>IEnumerable{Assembly}.</returns> - private List<Tuple<Assembly, string>> GetPluginAssemblies() - { - // Copy pre-installed plugins - var sourcePath = Path.Combine(ApplicationPaths.ApplicationResourcesPath, "plugins"); - CopyPlugins(sourcePath, ApplicationPaths.PluginsPath); - - return GetPluginAssemblies(ApplicationPaths.PluginsPath); - } - - private void CopyPlugins(string source, string target) - { - List<string> files; - - try - { - files = Directory.EnumerateFiles(source, "*.dll", SearchOption.TopDirectoryOnly) - .ToList(); - - } - catch (DirectoryNotFoundException) - { - return; - } - - if (files.Count == 0) - { - return; - } - - foreach (var sourceFile in files) - { - var filename = Path.GetFileName(sourceFile); - var targetFile = Path.Combine(target, filename); - - var targetFileExists = File.Exists(targetFile); - - if (!targetFileExists && ServerConfigurationManager.Configuration.UninstalledPlugins.Contains(filename, StringComparer.OrdinalIgnoreCase)) - { - continue; - } - - if (targetFileExists && GetDllVersion(targetFile) >= GetDllVersion(sourceFile)) - { - continue; - } - - Directory.CreateDirectory(target); - File.Copy(sourceFile, targetFile, true); - } - } - - private Version GetDllVersion(string path) - { - try - { - var result = Version.Parse(FileVersionInfo.GetVersionInfo(path).FileVersion); - - Logger.LogInformation("File {Path} has version {Version}", path, result); - - return result; - } - catch (Exception ex) - { - Logger.LogError(ex, "Error getting version number from {Path}", path); - - return new Version(1, 0); - } - } - private List<Tuple<Assembly, string>> GetPluginAssemblies(string path) { try @@ -1738,7 +1663,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) } }; @@ -1814,7 +1738,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/Archiving/ZipClient.cs b/Emby.Server.Implementations/Archiving/ZipClient.cs index 84072cde6..1135cf694 100644 --- a/Emby.Server.Implementations/Archiving/ZipClient.cs +++ b/Emby.Server.Implementations/Archiving/ZipClient.cs @@ -29,7 +29,7 @@ namespace Emby.Server.Implementations.Archiving /// <param name="overwriteExistingFiles">if set to <c>true</c> [overwrite existing files].</param> public void ExtractAll(string sourceFile, string targetPath, bool overwriteExistingFiles) { - using (var fileStream = _fileSystem.OpenRead(sourceFile)) + using (var fileStream = File.OpenRead(sourceFile)) { ExtractAll(fileStream, targetPath, overwriteExistingFiles); } @@ -115,7 +115,7 @@ namespace Emby.Server.Implementations.Archiving /// <param name="overwriteExistingFiles">if set to <c>true</c> [overwrite existing files].</param> public void ExtractAllFrom7z(string sourceFile, string targetPath, bool overwriteExistingFiles) { - using (var fileStream = _fileSystem.OpenRead(sourceFile)) + using (var fileStream = File.OpenRead(sourceFile)) { ExtractAllFrom7z(fileStream, targetPath, overwriteExistingFiles); } @@ -155,7 +155,7 @@ namespace Emby.Server.Implementations.Archiving /// <param name="overwriteExistingFiles">if set to <c>true</c> [overwrite existing files].</param> public void ExtractAllFromTar(string sourceFile, string targetPath, bool overwriteExistingFiles) { - using (var fileStream = _fileSystem.OpenRead(sourceFile)) + using (var fileStream = File.OpenRead(sourceFile)) { ExtractAllFromTar(fileStream, targetPath, overwriteExistingFiles); } diff --git a/Emby.Server.Implementations/Channels/ChannelManager.cs b/Emby.Server.Implementations/Channels/ChannelManager.cs index a306b0169..949b89226 100644 --- a/Emby.Server.Implementations/Channels/ChannelManager.cs +++ b/Emby.Server.Implementations/Channels/ChannelManager.cs @@ -355,7 +355,7 @@ namespace Emby.Server.Implementations.Channels return; } - _fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(path)); + Directory.CreateDirectory(Path.GetDirectoryName(path)); _jsonSerializer.SerializeToFile(mediaSources, path); } @@ -834,7 +834,7 @@ namespace Emby.Server.Implementations.Channels { try { - _fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(path)); + Directory.CreateDirectory(Path.GetDirectoryName(path)); _jsonSerializer.SerializeToFile(result, path); } 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/Collections/CollectionManager.cs b/Emby.Server.Implementations/Collections/CollectionManager.cs index 7268811f8..812e48a1f 100644 --- a/Emby.Server.Implementations/Collections/CollectionManager.cs +++ b/Emby.Server.Implementations/Collections/CollectionManager.cs @@ -76,7 +76,7 @@ namespace Emby.Server.Implementations.Collections return null; } - _fileSystem.CreateDirectory(path); + Directory.CreateDirectory(path); var libraryOptions = new LibraryOptions { @@ -133,7 +133,7 @@ namespace Emby.Server.Implementations.Collections try { - _fileSystem.CreateDirectory(path); + Directory.CreateDirectory(path); var collection = new BoxSet { @@ -359,7 +359,7 @@ namespace Emby.Server.Implementations.Collections { var path = _collectionManager.GetCollectionsFolderPath(); - if (_fileSystem.DirectoryExists(path)) + if (Directory.Exists(path)) { try { diff --git a/Emby.Server.Implementations/Configuration/ServerConfigurationManager.cs b/Emby.Server.Implementations/Configuration/ServerConfigurationManager.cs index ab2e1c9a9..18e279c2f 100644 --- a/Emby.Server.Implementations/Configuration/ServerConfigurationManager.cs +++ b/Emby.Server.Implementations/Configuration/ServerConfigurationManager.cs @@ -148,7 +148,7 @@ namespace Emby.Server.Implementations.Configuration && !string.Equals(Configuration.CertificatePath ?? string.Empty, newPath)) { // Validate - if (!FileSystem.FileExists(newPath)) + if (!File.Exists(newPath)) { throw new FileNotFoundException(string.Format("Certificate file '{0}' does not exist.", newPath)); } @@ -168,7 +168,7 @@ namespace Emby.Server.Implementations.Configuration && !string.Equals(Configuration.MetadataPath ?? string.Empty, newPath)) { // Validate - if (!FileSystem.DirectoryExists(newPath)) + if (!Directory.Exists(newPath)) { throw new FileNotFoundException(string.Format("{0} does not exist.", newPath)); } 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/Devices/DeviceId.cs b/Emby.Server.Implementations/Devices/DeviceId.cs index 00761809a..866bd137f 100644 --- a/Emby.Server.Implementations/Devices/DeviceId.cs +++ b/Emby.Server.Implementations/Devices/DeviceId.cs @@ -53,11 +53,11 @@ namespace Emby.Server.Implementations.Devices { var path = CachePath; - _fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(path)); + Directory.CreateDirectory(Path.GetDirectoryName(path)); lock (_syncLock) { - _fileSystem.WriteAllText(path, id, Encoding.UTF8); + File.WriteAllText(path, id, Encoding.UTF8); } } catch (Exception ex) diff --git a/Emby.Server.Implementations/Devices/DeviceManager.cs b/Emby.Server.Implementations/Devices/DeviceManager.cs index 46d36f9f6..ec3649bca 100644 --- a/Emby.Server.Implementations/Devices/DeviceManager.cs +++ b/Emby.Server.Implementations/Devices/DeviceManager.cs @@ -76,7 +76,7 @@ namespace Emby.Server.Implementations.Devices public void SaveCapabilities(string deviceId, ClientCapabilities capabilities) { var path = Path.Combine(GetDevicePath(deviceId), "capabilities.json"); - _fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(path)); + Directory.CreateDirectory(Path.GetDirectoryName(path)); lock (_capabilitiesSyncLock) { @@ -239,7 +239,7 @@ namespace Emby.Server.Implementations.Devices path = Path.Combine(path, file.Name); path = Path.ChangeExtension(path, MimeTypes.ToExtension(file.MimeType) ?? "jpg"); - _fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(path)); + Directory.CreateDirectory(Path.GetDirectoryName(path)); await EnsureLibraryFolder(uploadPathInfo.Item2, uploadPathInfo.Item3).ConfigureAwait(false); @@ -275,7 +275,7 @@ namespace Emby.Server.Implementations.Devices private void AddCameraUpload(string deviceId, LocalFileInfo file) { var path = Path.Combine(GetDevicePath(deviceId), "camerauploads.json"); - _fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(path)); + Directory.CreateDirectory(Path.GetDirectoryName(path)); lock (_cameraUploadSyncLock) { @@ -317,7 +317,7 @@ namespace Emby.Server.Implementations.Devices return Task.CompletedTask; } - _fileSystem.CreateDirectory(path); + Directory.CreateDirectory(path); var libraryOptions = new LibraryOptions { @@ -431,7 +431,7 @@ namespace Emby.Server.Implementations.Devices { var path = _deviceManager.GetUploadsPath(); - if (_fileSystem.DirectoryExists(path)) + if (Directory.Exists(path)) { try { 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 98c08e6ba..9b61809c7 100644 --- a/Emby.Server.Implementations/EntryPoints/LibraryChangedNotifier.cs +++ b/Emby.Server.Implementations/EntryPoints/LibraryChangedNotifier.cs @@ -280,14 +280,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 1d44bffbb..8be6db87d 100644 --- a/Emby.Server.Implementations/EntryPoints/StartupWizard.cs +++ b/Emby.Server.Implementations/EntryPoints/StartupWizard.cs @@ -48,7 +48,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 d1d05eeb0..d91a2d581 100644 --- a/Emby.Server.Implementations/EntryPoints/UserDataChangeNotifier.cs +++ b/Emby.Server.Implementations/EntryPoints/UserDataChangeNotifier.cs @@ -123,7 +123,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 9a4aec958..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)) { @@ -48,7 +48,7 @@ namespace Emby.Server.Implementations.FFMpeg var prebuiltFolder = _appPaths.ProgramSystemPath; var prebuiltffmpeg = Path.Combine(prebuiltFolder, downloadInfo.FFMpegFilename); var prebuiltffprobe = Path.Combine(prebuiltFolder, downloadInfo.FFProbeFilename); - if (_fileSystem.FileExists(prebuiltffmpeg) && _fileSystem.FileExists(prebuiltffprobe)) + if (File.Exists(prebuiltffmpeg) && File.Exists(prebuiltffprobe)) { return new FFMpegInfo { @@ -75,11 +75,11 @@ namespace Emby.Server.Implementations.FFMpeg Version = version }; - _fileSystem.CreateDirectory(versionedDirectoryPath); + Directory.CreateDirectory(versionedDirectoryPath); var excludeFromDeletions = new List<string> { versionedDirectoryPath }; - if (!_fileSystem.FileExists(info.ProbePath) || !_fileSystem.FileExists(info.EncoderPath)) + if (!File.Exists(info.ProbePath) || !File.Exists(info.EncoderPath)) { // ffmpeg not present. See if there's an older version we can start with var existingVersion = GetExistingVersion(info, rootEncoderPath); @@ -92,7 +92,7 @@ namespace Emby.Server.Implementations.FFMpeg else { info = existingVersion; - versionedDirectoryPath = _fileSystem.GetDirectoryName(info.EncoderPath); + versionedDirectoryPath = Path.GetDirectoryName(info.EncoderPath); excludeFromDeletions.Add(versionedDirectoryPath); } } @@ -130,7 +130,7 @@ namespace Emby.Server.Implementations.FFMpeg { EncoderPath = encoder, ProbePath = probe, - Version = Path.GetFileName(_fileSystem.GetDirectoryName(probe)) + Version = Path.GetFileName(Path.GetDirectoryName(probe)) }; } } diff --git a/Emby.Server.Implementations/HttpClientManager/HttpClientManager.cs b/Emby.Server.Implementations/HttpClientManager/HttpClientManager.cs index ea620cb2e..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); @@ -286,28 +286,18 @@ namespace Emby.Server.Implementations.HttpClientManager private HttpResponseInfo GetCachedResponse(string responseCachePath, TimeSpan cacheLength, string url) { - try - { - if (_fileSystem.GetLastWriteTimeUtc(responseCachePath).Add(cacheLength) > DateTime.UtcNow) - { - var stream = _fileSystem.GetFileStream(responseCachePath, FileOpenMode.Open, FileAccessMode.Read, FileShareMode.Read, true); - - return new HttpResponseInfo - { - ResponseUrl = url, - Content = stream, - StatusCode = HttpStatusCode.OK, - ContentLength = stream.Length - }; - } - } - catch (FileNotFoundException) // REVIEW: @bond Is this really faster? - { - - } - catch (DirectoryNotFoundException) + if (File.Exists(responseCachePath) + && _fileSystem.GetLastWriteTimeUtc(responseCachePath).Add(cacheLength) > DateTime.UtcNow) { + var stream = _fileSystem.GetFileStream(responseCachePath, FileOpenMode.Open, FileAccessMode.Read, FileShareMode.Read, true); + return new HttpResponseInfo + { + ResponseUrl = url, + Content = stream, + StatusCode = HttpStatusCode.OK, + ContentLength = stream.Length + }; } return null; @@ -315,7 +305,7 @@ namespace Emby.Server.Implementations.HttpClientManager private async Task CacheResponse(HttpResponseInfo response, string responseCachePath) { - _fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(responseCachePath)); + Directory.CreateDirectory(Path.GetDirectoryName(responseCachePath)); using (var fileStream = _fileSystem.GetFileStream(responseCachePath, FileOpenMode.Create, FileAccessMode.Write, FileShareMode.None, true)) { @@ -384,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); } } @@ -523,7 +513,7 @@ namespace Emby.Server.Implementations.HttpClientManager { ValidateParams(options); - _fileSystem.CreateDirectory(_appPaths.TempDirectory); + Directory.CreateDirectory(_appPaths.TempDirectory); var tempFile = Path.Combine(_appPaths.TempDirectory, Guid.NewGuid() + ".tmp"); 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 6bee178ea..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) { @@ -189,13 +189,13 @@ namespace Emby.Server.Implementations.IO { item = LibraryManager.FindByPath(path, null); - path = _fileSystem.GetDirectoryName(path); + path = System.IO.Path.GetDirectoryName(path); } if (item != null) { // If the item has been deleted find the first valid parent that still exists - while (!_fileSystem.DirectoryExists(item.Path) && !_fileSystem.FileExists(item.Path)) + while (!Directory.Exists(item.Path) && !File.Exists(item.Path)) { item = item.GetOwner() ?? item.GetParent(); diff --git a/Emby.Server.Implementations/IO/LibraryMonitor.cs b/Emby.Server.Implementations/IO/LibraryMonitor.cs index e432b31da..3a746ef60 100644 --- a/Emby.Server.Implementations/IO/LibraryMonitor.cs +++ b/Emby.Server.Implementations/IO/LibraryMonitor.cs @@ -277,7 +277,7 @@ namespace Emby.Server.Implementations.IO /// <param name="path">The path.</param> private void StartWatchingPath(string path) { - if (!_fileSystem.DirectoryExists(path)) + if (!Directory.Exists(path)) { // Seeing a crash in the mono runtime due to an exception being thrown on a different thread Logger.LogInformation("Skipping realtime monitor for {0} because the path does not exist", path); @@ -483,7 +483,7 @@ namespace Emby.Server.Implementations.IO } // Go up a level - var parent = _fileSystem.GetDirectoryName(i); + var parent = Path.GetDirectoryName(i); if (!string.IsNullOrEmpty(parent)) { if (_fileSystem.AreEqual(parent, path)) @@ -509,7 +509,7 @@ namespace Emby.Server.Implementations.IO private void CreateRefresher(string path) { - var parentPath = _fileSystem.GetDirectoryName(path); + var parentPath = Path.GetDirectoryName(path); lock (_activeRefreshers) { @@ -538,7 +538,7 @@ namespace Emby.Server.Implementations.IO } // They are siblings. Rebase the refresher to the parent folder. - if (string.Equals(parentPath, _fileSystem.GetDirectoryName(refresher.Path), StringComparison.Ordinal)) + if (string.Equals(parentPath, Path.GetDirectoryName(refresher.Path), StringComparison.Ordinal)) { refresher.ResetPath(parentPath, path); return; @@ -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/IO/ManagedFileSystem.cs b/Emby.Server.Implementations/IO/ManagedFileSystem.cs index 3e7774abf..7c44878ec 100644 --- a/Emby.Server.Implementations/IO/ManagedFileSystem.cs +++ b/Emby.Server.Implementations/IO/ManagedFileSystem.cs @@ -50,7 +50,7 @@ namespace Emby.Server.Implementations.IO _isEnvironmentCaseInsensitive = environmentInfo.OperatingSystem == MediaBrowser.Model.System.OperatingSystem.Windows; } - public string DefaultDirectory + public virtual string DefaultDirectory { get { @@ -60,7 +60,7 @@ namespace Emby.Server.Implementations.IO { try { - if (DirectoryExists(value)) + if (Directory.Exists(value)) { return value; } @@ -75,7 +75,7 @@ namespace Emby.Server.Implementations.IO } } - public void AddShortcutHandler(IShortcutHandler handler) + public virtual void AddShortcutHandler(IShortcutHandler handler) { _shortcutHandlers.Add(handler); } @@ -94,13 +94,6 @@ namespace Emby.Server.Implementations.IO } } - public char DirectorySeparatorChar => Path.DirectorySeparatorChar; - - public string GetFullPath(string path) - { - return Path.GetFullPath(path); - } - /// <summary> /// Determines whether the specified filename is shortcut. /// </summary> @@ -142,7 +135,7 @@ namespace Emby.Server.Implementations.IO return null; } - public string MakeAbsolutePath(string folderPath, string filePath) + public virtual string MakeAbsolutePath(string folderPath, string filePath) { if (string.IsNullOrWhiteSpace(filePath)) return filePath; @@ -195,7 +188,7 @@ namespace Emby.Server.Implementations.IO /// or /// target /// </exception> - public void CreateShortcut(string shortcutPath, string target) + public virtual void CreateShortcut(string shortcutPath, string target) { if (string.IsNullOrEmpty(shortcutPath)) { @@ -227,7 +220,7 @@ namespace Emby.Server.Implementations.IO /// <returns>A <see cref="FileSystemMetadata"/> object.</returns> /// <remarks>If the specified path points to a directory, the returned <see cref="FileSystemMetadata"/> object's /// <see cref="FileSystemMetadata.IsDirectory"/> property will be set to true and all other properties will reflect the properties of the directory.</remarks> - public FileSystemMetadata GetFileSystemInfo(string path) + public virtual FileSystemMetadata GetFileSystemInfo(string path) { // Take a guess to try and avoid two file system hits, but we'll double-check by calling Exists if (Path.HasExtension(path)) @@ -262,7 +255,7 @@ namespace Emby.Server.Implementations.IO /// <remarks><para>If the specified path points to a directory, the returned <see cref="FileSystemMetadata"/> object's /// <see cref="FileSystemMetadata.IsDirectory"/> property and the <see cref="FileSystemMetadata.Exists"/> property will both be set to false.</para> /// <para>For automatic handling of files <b>and</b> directories, use <see cref="GetFileSystemInfo"/>.</para></remarks> - public FileSystemMetadata GetFileInfo(string path) + public virtual FileSystemMetadata GetFileInfo(string path) { var fileInfo = new FileInfo(path); @@ -277,7 +270,7 @@ namespace Emby.Server.Implementations.IO /// <remarks><para>If the specified path points to a file, the returned <see cref="FileSystemMetadata"/> object's /// <see cref="FileSystemMetadata.IsDirectory"/> property will be set to true and the <see cref="FileSystemMetadata.Exists"/> property will be set to false.</para> /// <para>For automatic handling of files <b>and</b> directories, use <see cref="GetFileSystemInfo"/>.</para></remarks> - public FileSystemMetadata GetDirectoryInfo(string path) + public virtual FileSystemMetadata GetDirectoryInfo(string path) { var fileInfo = new DirectoryInfo(path); @@ -340,23 +333,18 @@ namespace Emby.Server.Implementations.IO } /// <summary> - /// The space char - /// </summary> - private const char SpaceChar = ' '; - - /// <summary> /// Takes a filename and removes invalid characters /// </summary> /// <param name="filename">The filename.</param> /// <returns>System.String.</returns> /// <exception cref="ArgumentNullException">filename</exception> - public string GetValidFilename(string filename) + public virtual string GetValidFilename(string filename) { var builder = new StringBuilder(filename); foreach (var c in _invalidFileNameChars) { - builder = builder.Replace(c, SpaceChar); + builder = builder.Replace(c, ' '); } return builder.ToString(); @@ -386,17 +374,17 @@ namespace Emby.Server.Implementations.IO /// </summary> /// <param name="path">The path.</param> /// <returns>DateTime.</returns> - public DateTime GetCreationTimeUtc(string path) + public virtual DateTime GetCreationTimeUtc(string path) { return GetCreationTimeUtc(GetFileSystemInfo(path)); } - public DateTime GetCreationTimeUtc(FileSystemMetadata info) + public virtual DateTime GetCreationTimeUtc(FileSystemMetadata info) { return info.CreationTimeUtc; } - public DateTime GetLastWriteTimeUtc(FileSystemMetadata info) + public virtual DateTime GetLastWriteTimeUtc(FileSystemMetadata info) { return info.LastWriteTimeUtc; } @@ -425,7 +413,7 @@ namespace Emby.Server.Implementations.IO /// </summary> /// <param name="path">The path.</param> /// <returns>DateTime.</returns> - public DateTime GetLastWriteTimeUtc(string path) + public virtual DateTime GetLastWriteTimeUtc(string path) { return GetLastWriteTimeUtc(GetFileSystemInfo(path)); } @@ -439,7 +427,7 @@ namespace Emby.Server.Implementations.IO /// <param name="share">The share.</param> /// <param name="isAsync">if set to <c>true</c> [is asynchronous].</param> /// <returns>FileStream.</returns> - public Stream GetFileStream(string path, FileOpenMode mode, FileAccessMode access, FileShareMode share, bool isAsync = false) + public virtual Stream GetFileStream(string path, FileOpenMode mode, FileAccessMode access, FileShareMode share, bool isAsync = false) { if (_supportsAsyncFileStreams && isAsync) { @@ -449,7 +437,7 @@ namespace Emby.Server.Implementations.IO return GetFileStream(path, mode, access, share, FileOpenOptions.None); } - public Stream GetFileStream(string path, FileOpenMode mode, FileAccessMode access, FileShareMode share, FileOpenOptions fileOpenOptions) + public virtual Stream GetFileStream(string path, FileOpenMode mode, FileAccessMode access, FileShareMode share, FileOpenOptions fileOpenOptions) => new FileStream(path, GetFileMode(mode), GetFileAccess(access), GetFileShare(share), 4096, GetFileOptions(fileOpenOptions)); private static FileOptions GetFileOptions(FileOpenOptions mode) @@ -511,7 +499,7 @@ namespace Emby.Server.Implementations.IO } } - public void SetHidden(string path, bool isHidden) + public virtual void SetHidden(string path, bool isHidden) { if (_environmentInfo.OperatingSystem != MediaBrowser.Model.System.OperatingSystem.Windows) { @@ -535,7 +523,7 @@ namespace Emby.Server.Implementations.IO } } - public void SetReadOnly(string path, bool isReadOnly) + public virtual void SetReadOnly(string path, bool isReadOnly) { if (_environmentInfo.OperatingSystem != MediaBrowser.Model.System.OperatingSystem.Windows) { @@ -559,7 +547,7 @@ namespace Emby.Server.Implementations.IO } } - public void SetAttributes(string path, bool isHidden, bool isReadOnly) + public virtual void SetAttributes(string path, bool isHidden, bool isReadOnly) { if (_environmentInfo.OperatingSystem != MediaBrowser.Model.System.OperatingSystem.Windows) { @@ -611,7 +599,7 @@ namespace Emby.Server.Implementations.IO /// </summary> /// <param name="file1">The file1.</param> /// <param name="file2">The file2.</param> - public void SwapFiles(string file1, string file2) + public virtual void SwapFiles(string file1, string file2) { if (string.IsNullOrEmpty(file1)) { @@ -630,18 +618,13 @@ namespace Emby.Server.Implementations.IO SetHidden(file2, false); Directory.CreateDirectory(_tempPath); - CopyFile(file1, temp1, true); + File.Copy(file1, temp1, true); - CopyFile(file2, file1, true); - CopyFile(temp1, file2, true); + File.Copy(file2, file1, true); + File.Copy(temp1, file2, true); } - private static char GetDirectorySeparatorChar(string path) - { - return Path.DirectorySeparatorChar; - } - - public bool ContainsSubPath(string parentPath, string path) + public virtual bool ContainsSubPath(string parentPath, string path) { if (string.IsNullOrEmpty(parentPath)) { @@ -653,19 +636,19 @@ namespace Emby.Server.Implementations.IO throw new ArgumentNullException(nameof(path)); } - var separatorChar = GetDirectorySeparatorChar(parentPath); + var separatorChar = Path.DirectorySeparatorChar; return path.IndexOf(parentPath.TrimEnd(separatorChar) + separatorChar, StringComparison.OrdinalIgnoreCase) != -1; } - public bool IsRootPath(string path) + public virtual bool IsRootPath(string path) { if (string.IsNullOrEmpty(path)) { throw new ArgumentNullException(nameof(path)); } - var parent = GetDirectoryName(path); + var parent = Path.GetDirectoryName(path); if (!string.IsNullOrEmpty(parent)) { @@ -675,12 +658,7 @@ namespace Emby.Server.Implementations.IO return true; } - public string GetDirectoryName(string path) - { - return Path.GetDirectoryName(path); - } - - public string NormalizePath(string path) + public virtual string NormalizePath(string path) { if (string.IsNullOrEmpty(path)) { @@ -692,10 +670,10 @@ namespace Emby.Server.Implementations.IO return path; } - return path.TrimEnd(GetDirectorySeparatorChar(path)); + return path.TrimEnd(Path.DirectorySeparatorChar); } - public bool AreEqual(string path1, string path2) + public virtual bool AreEqual(string path1, string path2) { if (path1 == null && path2 == null) { @@ -710,7 +688,7 @@ namespace Emby.Server.Implementations.IO return string.Equals(NormalizePath(path1), NormalizePath(path2), StringComparison.OrdinalIgnoreCase); } - public string GetFileNameWithoutExtension(FileSystemMetadata info) + public virtual string GetFileNameWithoutExtension(FileSystemMetadata info) { if (info.IsDirectory) { @@ -720,12 +698,7 @@ namespace Emby.Server.Implementations.IO return Path.GetFileNameWithoutExtension(info.FullName); } - public string GetFileNameWithoutExtension(string path) - { - return Path.GetFileNameWithoutExtension(path); - } - - public bool IsPathFile(string path) + public virtual bool IsPathFile(string path) { // Cannot use Path.IsPathRooted because it returns false under mono when using windows-based paths, e.g. C:\\ @@ -740,23 +713,13 @@ namespace Emby.Server.Implementations.IO //return Path.IsPathRooted(path); } - public void DeleteFile(string path) + public virtual void DeleteFile(string path) { SetAttributes(path, false, false); File.Delete(path); } - - public void DeleteDirectory(string path, bool recursive) - { - Directory.Delete(path, recursive); - } - - public void CreateDirectory(string path) - { - Directory.CreateDirectory(path); - } - - public List<FileSystemMetadata> GetDrives() + + public virtual List<FileSystemMetadata> GetDrives() { // Only include drives in the ready state or this method could end up being very slow, waiting for drives to timeout return DriveInfo.GetDrives().Where(d => d.IsReady).Select(d => new FileSystemMetadata @@ -768,19 +731,19 @@ namespace Emby.Server.Implementations.IO }).ToList(); } - public IEnumerable<FileSystemMetadata> GetDirectories(string path, bool recursive = false) + public virtual IEnumerable<FileSystemMetadata> GetDirectories(string path, bool recursive = false) { var searchOption = recursive ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly; return ToMetadata(new DirectoryInfo(path).EnumerateDirectories("*", searchOption)); } - public IEnumerable<FileSystemMetadata> GetFiles(string path, bool recursive = false) + public virtual IEnumerable<FileSystemMetadata> GetFiles(string path, bool recursive = false) { return GetFiles(path, null, false, recursive); } - public IEnumerable<FileSystemMetadata> GetFiles(string path, string[] extensions, bool enableCaseSensitiveExtensions, bool recursive = false) + public virtual IEnumerable<FileSystemMetadata> GetFiles(string path, string[] extensions, bool enableCaseSensitiveExtensions, bool recursive = false) { var searchOption = recursive ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly; @@ -809,7 +772,7 @@ namespace Emby.Server.Implementations.IO return ToMetadata(files); } - public IEnumerable<FileSystemMetadata> GetFileSystemEntries(string path, bool recursive = false) + public virtual IEnumerable<FileSystemMetadata> GetFileSystemEntries(string path, bool recursive = false) { var directoryInfo = new DirectoryInfo(path); var searchOption = recursive ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly; @@ -827,89 +790,19 @@ namespace Emby.Server.Implementations.IO { return infos.Select(GetFileSystemMetadata); } - - public string[] ReadAllLines(string path) - { - return File.ReadAllLines(path); - } - - public void WriteAllLines(string path, IEnumerable<string> lines) - { - File.WriteAllLines(path, lines); - } - - public Stream OpenRead(string path) - { - return File.OpenRead(path); - } - - public void CopyFile(string source, string target, bool overwrite) - { - File.Copy(source, target, overwrite); - } - - public void MoveFile(string source, string target) - { - File.Move(source, target); - } - - public void MoveDirectory(string source, string target) - { - Directory.Move(source, target); - } - - public bool DirectoryExists(string path) - { - return Directory.Exists(path); - } - - public bool FileExists(string path) - { - return File.Exists(path); - } - - public string ReadAllText(string path) - { - return File.ReadAllText(path); - } - - public byte[] ReadAllBytes(string path) - { - return File.ReadAllBytes(path); - } - - public void WriteAllText(string path, string text, Encoding encoding) - { - File.WriteAllText(path, text, encoding); - } - - public void WriteAllText(string path, string text) - { - File.WriteAllText(path, text); - } - - public void WriteAllBytes(string path, byte[] bytes) - { - File.WriteAllBytes(path, bytes); - } - - public string ReadAllText(string path, Encoding encoding) - { - return File.ReadAllText(path, encoding); - } - - public IEnumerable<string> GetDirectoryPaths(string path, bool recursive = false) + + public virtual IEnumerable<string> GetDirectoryPaths(string path, bool recursive = false) { var searchOption = recursive ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly; return Directory.EnumerateDirectories(path, "*", searchOption); } - public IEnumerable<string> GetFilePaths(string path, bool recursive = false) + public virtual IEnumerable<string> GetFilePaths(string path, bool recursive = false) { return GetFilePaths(path, null, false, recursive); } - public IEnumerable<string> GetFilePaths(string path, string[] extensions, bool enableCaseSensitiveExtensions, bool recursive = false) + public virtual IEnumerable<string> GetFilePaths(string path, string[] extensions, bool enableCaseSensitiveExtensions, bool recursive = false) { var searchOption = recursive ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly; @@ -938,7 +831,7 @@ namespace Emby.Server.Implementations.IO return files; } - public IEnumerable<string> GetFileSystemEntryPaths(string path, bool recursive = false) + public virtual IEnumerable<string> GetFileSystemEntryPaths(string path, bool recursive = false) { var searchOption = recursive ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly; return Directory.EnumerateFileSystemEntries(path, "*", searchOption); @@ -948,7 +841,7 @@ namespace Emby.Server.Implementations.IO { if (_environmentInfo.OperatingSystem == MediaBrowser.Model.System.OperatingSystem.OSX) { - RunProcess("chmod", "+x \"" + path + "\"", GetDirectoryName(path)); + RunProcess("chmod", "+x \"" + path + "\"", Path.GetDirectoryName(path)); } } diff --git a/Emby.Server.Implementations/IO/MbLinkShortcutHandler.cs b/Emby.Server.Implementations/IO/MbLinkShortcutHandler.cs index a306f94b3..5e5e91bb3 100644 --- a/Emby.Server.Implementations/IO/MbLinkShortcutHandler.cs +++ b/Emby.Server.Implementations/IO/MbLinkShortcutHandler.cs @@ -24,7 +24,7 @@ namespace Emby.Server.Implementations.IO if (string.Equals(Path.GetExtension(shortcutPath), ".mblink", StringComparison.OrdinalIgnoreCase)) { - var path = _fileSystem.ReadAllText(shortcutPath); + var path = File.ReadAllText(shortcutPath); return _fileSystem.NormalizePath(path); } @@ -44,7 +44,7 @@ namespace Emby.Server.Implementations.IO throw new ArgumentNullException(nameof(targetPath)); } - _fileSystem.WriteAllText(shortcutPath, targetPath); + File.WriteAllText(shortcutPath, targetPath); } } } 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 b99b98157..109c21f18 100644 --- a/Emby.Server.Implementations/Images/BaseDynamicImageProvider.cs +++ b/Emby.Server.Implementations/Images/BaseDynamicImageProvider.cs @@ -99,7 +99,7 @@ namespace Emby.Server.Implementations.Images CancellationToken cancellationToken) { var outputPathWithoutExtension = Path.Combine(ApplicationPaths.TempDirectory, Guid.NewGuid().ToString("N")); - FileSystem.CreateDirectory(FileSystem.GetDirectoryName(outputPathWithoutExtension)); + Directory.CreateDirectory(Path.GetDirectoryName(outputPathWithoutExtension)); string outputPath = CreateImage(item, itemsWithImages, outputPathWithoutExtension, imageType, 0); if (string.IsNullOrEmpty(outputPath)) @@ -165,7 +165,7 @@ namespace Emby.Server.Implementations.Images private string CreateCollage(BaseItem primaryItem, List<BaseItem> items, string outputPath, int width, int height) { - FileSystem.CreateDirectory(FileSystem.GetDirectoryName(outputPath)); + Directory.CreateDirectory(Path.GetDirectoryName(outputPath)); var options = new ImageCollageOptions { @@ -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); } @@ -300,7 +300,7 @@ namespace Emby.Server.Implementations.Images var ext = Path.GetExtension(image); var outputPath = Path.ChangeExtension(outputPathWithoutExtension, ext); - FileSystem.CopyFile(image, outputPath, true); + File.Copy(image, outputPath, true); return outputPath; } diff --git a/Emby.Server.Implementations/Library/CoreResolutionIgnoreRule.cs b/Emby.Server.Implementations/Library/CoreResolutionIgnoreRule.cs index c0a126b84..80f746c7a 100644 --- a/Emby.Server.Implementations/Library/CoreResolutionIgnoreRule.cs +++ b/Emby.Server.Implementations/Library/CoreResolutionIgnoreRule.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.IO; using System.Linq; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; @@ -146,7 +147,7 @@ namespace Emby.Server.Implementations.Library if (parent != null) { // Don't resolve these into audio files - if (string.Equals(_fileSystem.GetFileNameWithoutExtension(filename), BaseItem.ThemeSongFilename) && _libraryManager.IsAudioFile(filename)) + if (string.Equals(Path.GetFileNameWithoutExtension(filename), BaseItem.ThemeSongFilename) && _libraryManager.IsAudioFile(filename)) { return true; } diff --git a/Emby.Server.Implementations/Library/LibraryManager.cs b/Emby.Server.Implementations/Library/LibraryManager.cs index ad070ed79..064006ebd 100644 --- a/Emby.Server.Implementations/Library/LibraryManager.cs +++ b/Emby.Server.Implementations/Library/LibraryManager.cs @@ -375,7 +375,7 @@ namespace Emby.Server.Implementations.Library try { - _fileSystem.DeleteDirectory(metadataPath, true); + Directory.Delete(metadataPath, true); } catch (IOException) { @@ -395,38 +395,33 @@ namespace Emby.Server.Implementations.Library foreach (var fileSystemInfo in item.GetDeletePaths().ToList()) { - try + if (File.Exists(fileSystemInfo.FullName)) { - _logger.LogDebug("Deleting path {path}", fileSystemInfo.FullName); - if (fileSystemInfo.IsDirectory) - { - _fileSystem.DeleteDirectory(fileSystemInfo.FullName, true); - } - else + try { - _fileSystem.DeleteFile(fileSystemInfo.FullName); + _logger.LogDebug("Deleting path {path}", fileSystemInfo.FullName); + if (fileSystemInfo.IsDirectory) + { + Directory.Delete(fileSystemInfo.FullName, true); + } + else + { + File.Delete(fileSystemInfo.FullName); + } } - } - catch (FileNotFoundException) - { - // may have already been deleted manually by user - } - catch (DirectoryNotFoundException) - { - // may have already been deleted manually by user - } - catch (IOException) - { - if (isRequiredForDelete) + catch (IOException) { - throw; + if (isRequiredForDelete) + { + throw; + } } - } - catch (UnauthorizedAccessException) - { - if (isRequiredForDelete) + catch (UnauthorizedAccessException) { - throw; + if (isRequiredForDelete) + { + throw; + } } } @@ -517,7 +512,7 @@ namespace Emby.Server.Implementations.Library if (forceCaseInsensitive || !ConfigurationManager.Configuration.EnableCaseSensitiveItemIds) { - key = key.ToLower(); + key = key.ToLowerInvariant(); } key = type.FullName + key; @@ -725,7 +720,7 @@ namespace Emby.Server.Implementations.Library { var rootFolderPath = ConfigurationManager.ApplicationPaths.RootFolderPath; - _fileSystem.CreateDirectory(rootFolderPath); + Directory.CreateDirectory(rootFolderPath); var rootFolder = GetItemById(GetNewItemId(rootFolderPath, typeof(AggregateFolder))) as AggregateFolder ?? ((Folder)ResolvePath(_fileSystem.GetDirectoryInfo(rootFolderPath))).DeepCopy<Folder, AggregateFolder>(); @@ -739,7 +734,7 @@ namespace Emby.Server.Implementations.Library // Add in the plug-in folders var path = Path.Combine(ConfigurationManager.ApplicationPaths.DataPath, "playlists"); - _fileSystem.CreateDirectory(path); + Directory.CreateDirectory(path); Folder folder = new PlaylistsFolder { @@ -790,7 +785,7 @@ namespace Emby.Server.Implementations.Library { var userRootPath = ConfigurationManager.ApplicationPaths.DefaultUserViewsPath; - _fileSystem.CreateDirectory(userRootPath); + Directory.CreateDirectory(userRootPath); var tmpItem = GetItemById(GetNewItemId(userRootPath, typeof(UserRootFolder))) as UserRootFolder; @@ -874,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> @@ -900,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> @@ -1004,7 +984,7 @@ namespace Emby.Server.Implementations.Library public Task ValidatePeople(CancellationToken cancellationToken, IProgress<double> progress) { // Ensure the location is available. - _fileSystem.CreateDirectory(ConfigurationManager.ApplicationPaths.PeoplePath); + Directory.CreateDirectory(ConfigurationManager.ApplicationPaths.PeoplePath); return new PeopleValidator(this, _logger, ConfigurationManager, _fileSystem).ValidatePeople(cancellationToken, progress); } @@ -1233,7 +1213,7 @@ namespace Emby.Server.Implementations.Library private string GetCollectionType(string path) { return _fileSystem.GetFilePaths(path, new[] { ".collection" }, true, false) - .Select(i => _fileSystem.GetFileNameWithoutExtension(i)) + .Select(i => Path.GetFileNameWithoutExtension(i)) .FirstOrDefault(i => !string.IsNullOrEmpty(i)); } @@ -1375,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) @@ -2151,7 +2120,7 @@ namespace Emby.Server.Implementations.Library if (item == null || !string.Equals(item.Path, path, StringComparison.OrdinalIgnoreCase)) { - _fileSystem.CreateDirectory(path); + Directory.CreateDirectory(path); item = new UserView { @@ -2196,7 +2165,7 @@ namespace Emby.Server.Implementations.Library if (item == null) { - _fileSystem.CreateDirectory(path); + Directory.CreateDirectory(path); item = new UserView { @@ -2261,7 +2230,7 @@ namespace Emby.Server.Implementations.Library if (item == null) { - _fileSystem.CreateDirectory(path); + Directory.CreateDirectory(path); item = new UserView { @@ -2329,7 +2298,7 @@ namespace Emby.Server.Implementations.Library if (item == null) { - _fileSystem.CreateDirectory(path); + Directory.CreateDirectory(path); item = new UserView { @@ -2868,7 +2837,7 @@ namespace Emby.Server.Implementations.Library var rootFolderPath = ConfigurationManager.ApplicationPaths.DefaultUserViewsPath; var virtualFolderPath = Path.Combine(rootFolderPath, name); - while (_fileSystem.DirectoryExists(virtualFolderPath)) + while (Directory.Exists(virtualFolderPath)) { name += "1"; virtualFolderPath = Path.Combine(rootFolderPath, name); @@ -2877,7 +2846,7 @@ namespace Emby.Server.Implementations.Library var mediaPathInfos = options.PathInfos; if (mediaPathInfos != null) { - var invalidpath = mediaPathInfos.FirstOrDefault(i => !_fileSystem.DirectoryExists(i.Path)); + var invalidpath = mediaPathInfos.FirstOrDefault(i => !Directory.Exists(i.Path)); if (invalidpath != null) { throw new ArgumentException("The specified path does not exist: " + invalidpath.Path + "."); @@ -2888,13 +2857,13 @@ namespace Emby.Server.Implementations.Library try { - _fileSystem.CreateDirectory(virtualFolderPath); + Directory.CreateDirectory(virtualFolderPath); if (!string.IsNullOrEmpty(collectionType)) { var path = Path.Combine(virtualFolderPath, collectionType + ".collection"); - _fileSystem.WriteAllBytes(path, Array.Empty<byte>()); + File.WriteAllBytes(path, Array.Empty<byte>()); } CollectionFolder.SaveLibraryOptions(virtualFolderPath, options); @@ -2940,7 +2909,7 @@ namespace Emby.Server.Implementations.Library // // We can't validate protocol-based paths, so just allow them // if (path.IndexOf("://", StringComparison.OrdinalIgnoreCase) == -1) // { - // return _fileSystem.DirectoryExists(path); + // return Directory.Exists(path); // } //} @@ -2968,7 +2937,7 @@ namespace Emby.Server.Implementations.Library throw new ArgumentNullException(nameof(path)); } - if (!_fileSystem.DirectoryExists(path)) + if (!Directory.Exists(path)) { throw new FileNotFoundException("The path does not exist."); } @@ -2981,11 +2950,11 @@ namespace Emby.Server.Implementations.Library var rootFolderPath = ConfigurationManager.ApplicationPaths.DefaultUserViewsPath; var virtualFolderPath = Path.Combine(rootFolderPath, virtualFolderName); - var shortcutFilename = _fileSystem.GetFileNameWithoutExtension(path); + var shortcutFilename = Path.GetFileNameWithoutExtension(path); var lnk = Path.Combine(virtualFolderPath, shortcutFilename + ShortcutFileExtension); - while (_fileSystem.FileExists(lnk)) + while (File.Exists(lnk)) { shortcutFilename += "1"; lnk = Path.Combine(virtualFolderPath, shortcutFilename + ShortcutFileExtension); @@ -3078,7 +3047,7 @@ namespace Emby.Server.Implementations.Library var path = Path.Combine(rootFolderPath, name); - if (!_fileSystem.DirectoryExists(path)) + if (!Directory.Exists(path)) { throw new FileNotFoundException("The media folder does not exist"); } @@ -3087,7 +3056,7 @@ namespace Emby.Server.Implementations.Library try { - _fileSystem.DeleteDirectory(path, true); + Directory.Delete(path, true); } finally { @@ -3150,7 +3119,7 @@ namespace Emby.Server.Implementations.Library var rootFolderPath = ConfigurationManager.ApplicationPaths.DefaultUserViewsPath; var virtualFolderPath = Path.Combine(rootFolderPath, virtualFolderName); - if (!_fileSystem.DirectoryExists(virtualFolderPath)) + if (!Directory.Exists(virtualFolderPath)) { throw new FileNotFoundException(string.Format("The media collection {0} does not exist", virtualFolderName)); } diff --git a/Emby.Server.Implementations/Library/MediaSourceManager.cs b/Emby.Server.Implementations/Library/MediaSourceManager.cs index 1ed838893..4f72651d4 100644 --- a/Emby.Server.Implementations/Library/MediaSourceManager.cs +++ b/Emby.Server.Implementations/Library/MediaSourceManager.cs @@ -322,18 +322,18 @@ namespace Emby.Server.Implementations.Library private string[] NormalizeLanguage(string language) { - if (language != null) + if (language == null) { - var culture = _localizationManager.FindLanguageInfo(language); - if (culture != null) - { - return culture.ThreeLetterISOLanguageNames; - } + return Array.Empty<string>(); + } - return new string[] { language }; + var culture = _localizationManager.FindLanguageInfo(language); + if (culture != null) + { + return culture.ThreeLetterISOLanguageNames; } - return Array.Empty<string>(); + return new string[] { language }; } private void SetDefaultSubtitleStreamIndex(MediaSourceInfo source, UserItemData userData, User user, bool allowRememberingSelection) @@ -670,7 +670,7 @@ namespace Emby.Server.Implementations.Library if (cacheFilePath != null) { - _fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(cacheFilePath)); + Directory.CreateDirectory(Path.GetDirectoryName(cacheFilePath)); _jsonSerializer.SerializeToFile(mediaInfo, cacheFilePath); //_logger.LogDebug("Saved media info to {0}", cacheFilePath); diff --git a/Emby.Server.Implementations/Library/Resolvers/PhotoResolver.cs b/Emby.Server.Implementations/Library/Resolvers/PhotoResolver.cs index 78c1c6629..9de766767 100644 --- a/Emby.Server.Implementations/Library/Resolvers/PhotoResolver.cs +++ b/Emby.Server.Implementations/Library/Resolvers/PhotoResolver.cs @@ -43,7 +43,7 @@ namespace Emby.Server.Implementations.Library.Resolvers var filename = Path.GetFileNameWithoutExtension(args.Path); // Make sure the image doesn't belong to a video file - var files = args.DirectoryService.GetFiles(_fileSystem.GetDirectoryName(args.Path)); + var files = args.DirectoryService.GetFiles(Path.GetDirectoryName(args.Path)); var libraryOptions = args.GetLibraryOptions(); foreach (var file in files) 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 6e4450bb1..6dd9366b0 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); @@ -904,7 +888,7 @@ namespace Emby.Server.Implementations.Library // Tuesday, 22 August 2006 06:30 AM text.AppendLine("The pin code will expire at " + localExpirationTime.ToString("f1", CultureInfo.CurrentCulture)); - _fileSystem.WriteAllText(path, text.ToString(), Encoding.UTF8); + File.WriteAllText(path, text.ToString(), Encoding.UTF8); var result = new PasswordPinCreationResult { @@ -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); @@ -1029,6 +1005,11 @@ namespace Emby.Server.Implementations.Library { var path = GetPolicyFilePath(user); + if (!File.Exists(path)) + { + return GetDefaultPolicy(user); + } + try { lock (_policySyncLock) @@ -1036,10 +1017,6 @@ namespace Emby.Server.Implementations.Library return (UserPolicy)_xmlSerializer.DeserializeFromFile(typeof(UserPolicy), path); } } - catch (FileNotFoundException) - { - return GetDefaultPolicy(user); - } catch (IOException) { return GetDefaultPolicy(user); @@ -1079,7 +1056,7 @@ namespace Emby.Server.Implementations.Library var path = GetPolicyFilePath(user); - _fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(path)); + Directory.CreateDirectory(Path.GetDirectoryName(path)); lock (_policySyncLock) { @@ -1128,6 +1105,11 @@ namespace Emby.Server.Implementations.Library { var path = GetConfigurationFilePath(user); + if (!File.Exists(path)) + { + return new UserConfiguration(); + } + try { lock (_configSyncLock) @@ -1135,10 +1117,6 @@ namespace Emby.Server.Implementations.Library return (UserConfiguration)_xmlSerializer.DeserializeFromFile(typeof(UserConfiguration), path); } } - catch (FileNotFoundException) - { - return new UserConfiguration(); - } catch (IOException) { return new UserConfiguration(); @@ -1174,7 +1152,7 @@ namespace Emby.Server.Implementations.Library config = _jsonSerializer.DeserializeFromString<UserConfiguration>(json); } - _fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(path)); + Directory.CreateDirectory(Path.GetDirectoryName(path)); lock (_configSyncLock) { 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/DirectRecorder.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/DirectRecorder.cs index 7d7ef21e3..dd636e6cd 100644 --- a/Emby.Server.Implementations/LiveTv/EmbyTV/DirectRecorder.cs +++ b/Emby.Server.Implementations/LiveTv/EmbyTV/DirectRecorder.cs @@ -1,4 +1,5 @@ using System; +using System.IO; using System.Threading; using System.Threading.Tasks; using MediaBrowser.Common.Net; @@ -41,7 +42,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV private async Task RecordFromDirectStreamProvider(IDirectStreamProvider directStreamProvider, string targetFile, TimeSpan duration, Action onStarted, CancellationToken cancellationToken) { - _fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(targetFile)); + Directory.CreateDirectory(Path.GetDirectoryName(targetFile)); using (var output = _fileSystem.GetFileStream(targetFile, FileOpenMode.Create, FileAccessMode.Write, FileShareMode.Read)) { @@ -77,7 +78,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV { _logger.LogInformation("Opened recording stream from tuner provider"); - _fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(targetFile)); + Directory.CreateDirectory(Path.GetDirectoryName(targetFile)); using (var output = _fileSystem.GetFileStream(targetFile, FileOpenMode.Create, FileAccessMode.Write, FileShareMode.Read)) { diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs index 4e131c941..c5ab568ae 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) @@ -1427,7 +1428,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV timer.RetryCount++; _timerProvider.AddOrUpdate(timer); } - else if (_fileSystem.FileExists(recordPath)) + else if (File.Exists(recordPath)) { timer.RecordingPath = recordPath; timer.Status = RecordingStatus.Completed; @@ -1489,7 +1490,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV { _logger.LogInformation("Triggering refresh on {path}", path); - var item = GetAffectedBaseItem(_fileSystem.GetDirectoryName(path)); + var item = GetAffectedBaseItem(Path.GetDirectoryName(path)); if (item != null) { @@ -1500,8 +1501,8 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV RefreshPaths = new string[] { path, - _fileSystem.GetDirectoryName(path), - _fileSystem.GetDirectoryName(_fileSystem.GetDirectoryName(path)) + Path.GetDirectoryName(path), + Path.GetDirectoryName(Path.GetDirectoryName(path)) } }, RefreshPriority.High); @@ -1512,13 +1513,13 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV { BaseItem item = null; - var parentPath = _fileSystem.GetDirectoryName(path); + var parentPath = Path.GetDirectoryName(path); while (item == null && !string.IsNullOrEmpty(path)) { item = _libraryManager.FindByPath(path, null); - path = _fileSystem.GetDirectoryName(path); + path = Path.GetDirectoryName(path); } if (item != null) @@ -1573,7 +1574,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV .Where(i => i.Status == RecordingStatus.Completed && !string.IsNullOrWhiteSpace(i.RecordingPath)) .Where(i => string.Equals(i.SeriesTimerId, seriesTimerId, StringComparison.OrdinalIgnoreCase)) .OrderByDescending(i => i.EndDate) - .Where(i => _fileSystem.FileExists(i.RecordingPath)) + .Where(i => File.Exists(i.RecordingPath)) .Skip(seriesTimer.KeepUpTo - 1) .ToList(); @@ -1595,7 +1596,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV DtoOptions = new DtoOptions(true) })) - .Where(i => i.IsFileProtocol && _fileSystem.FileExists(i.Path)) + .Where(i => i.IsFileProtocol && File.Exists(i.Path)) .Skip(seriesTimer.KeepUpTo - 1) .ToList(); @@ -1676,7 +1677,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV while (FileExists(path, timerId)) { - var parent = _fileSystem.GetDirectoryName(originalPath); + var parent = Path.GetDirectoryName(originalPath); var name = Path.GetFileNameWithoutExtension(originalPath); name += " - " + index.ToString(CultureInfo.InvariantCulture); @@ -1689,7 +1690,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV private bool FileExists(string path, string timerId) { - if (_fileSystem.FileExists(path)) + if (File.Exists(path)) { return true; } @@ -1822,12 +1823,12 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV return; } - var imageSavePath = Path.Combine(_fileSystem.GetDirectoryName(recordingPath), imageSaveFilenameWithoutExtension); + var imageSavePath = Path.Combine(Path.GetDirectoryName(recordingPath), imageSaveFilenameWithoutExtension); // preserve original image extension imageSavePath = Path.ChangeExtension(imageSavePath, Path.GetExtension(image.Path)); - _fileSystem.CopyFile(image.Path, imageSavePath, true); + File.Copy(image.Path, imageSavePath, true); } private async Task SaveRecordingImages(string recordingPath, LiveTvProgram program) @@ -1961,7 +1962,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV { var nfoPath = Path.Combine(seriesPath, "tvshow.nfo"); - if (_fileSystem.FileExists(nfoPath)) + if (File.Exists(nfoPath)) { return; } @@ -2023,7 +2024,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV { var nfoPath = Path.ChangeExtension(recordingPath, ".nfo"); - if (_fileSystem.FileExists(nfoPath)) + if (File.Exists(nfoPath)) { return; } @@ -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>(); @@ -2688,7 +2688,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV var defaultFolder = RecordingPath; var defaultName = "Recordings"; - if (_fileSystem.DirectoryExists(defaultFolder)) + if (Directory.Exists(defaultFolder)) { list.Add(new VirtualFolderInfo { @@ -2698,7 +2698,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV } var customPath = GetConfiguration().MovieRecordingPath; - if ((!string.IsNullOrWhiteSpace(customPath) && !string.Equals(customPath, defaultFolder, StringComparison.OrdinalIgnoreCase)) && _fileSystem.DirectoryExists(customPath)) + if ((!string.IsNullOrWhiteSpace(customPath) && !string.Equals(customPath, defaultFolder, StringComparison.OrdinalIgnoreCase)) && Directory.Exists(customPath)) { list.Add(new VirtualFolderInfo { @@ -2709,7 +2709,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV } customPath = GetConfiguration().SeriesRecordingPath; - if ((!string.IsNullOrWhiteSpace(customPath) && !string.Equals(customPath, defaultFolder, StringComparison.OrdinalIgnoreCase)) && _fileSystem.DirectoryExists(customPath)) + if ((!string.IsNullOrWhiteSpace(customPath) && !string.Equals(customPath, defaultFolder, StringComparison.OrdinalIgnoreCase)) && Directory.Exists(customPath)) { list.Add(new VirtualFolderInfo { diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs index c11a85027..eed239514 100644 --- a/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs +++ b/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs @@ -79,7 +79,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV private Task RecordFromFile(MediaSourceInfo mediaSource, string inputFile, string targetFile, TimeSpan duration, Action onStarted, CancellationToken cancellationToken) { _targetPath = targetFile; - _fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(targetFile)); + Directory.CreateDirectory(Path.GetDirectoryName(targetFile)); var process = _processFactory.Create(new ProcessOptions { @@ -105,7 +105,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV _logger.LogInformation(commandLineLogMessage); var logFilePath = Path.Combine(_appPaths.LogDirectoryPath, "record-transcode-" + Guid.NewGuid() + ".txt"); - _fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(logFilePath)); + 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. _logFileStream = _fileSystem.GetFileStream(logFilePath, FileOpenMode.Create, FileAccessMode.Write, FileShareMode.Read, true); diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/ItemDataProvider.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/ItemDataProvider.cs index 1b8287ed1..6b02eaea8 100644 --- a/Emby.Server.Implementations/LiveTv/EmbyTV/ItemDataProvider.cs +++ b/Emby.Server.Implementations/LiveTv/EmbyTV/ItemDataProvider.cs @@ -70,7 +70,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV } var file = _dataPath + ".json"; - _fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(file)); + Directory.CreateDirectory(Path.GetDirectoryName(file)); lock (_fileDataLock) { diff --git a/Emby.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs b/Emby.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs index e7a3d748d..f152ac465 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs @@ -61,7 +61,7 @@ namespace Jellyfin.Server.Implementations.LiveTv.Listings string cacheFilename = DateTime.UtcNow.DayOfYear.ToString(CultureInfo.InvariantCulture) + "-" + DateTime.UtcNow.Hour.ToString(CultureInfo.InvariantCulture) + ".xml"; string cacheFile = Path.Combine(_config.ApplicationPaths.CachePath, "xmltv", cacheFilename); - if (_fileSystem.FileExists(cacheFile)) + if (File.Exists(cacheFile)) { return UnzipIfNeeded(path, cacheFile); } @@ -83,9 +83,9 @@ namespace Jellyfin.Server.Implementations.LiveTv.Listings }).ConfigureAwait(false); - _fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(cacheFile)); + Directory.CreateDirectory(Path.GetDirectoryName(cacheFile)); - _fileSystem.CopyFile(tempFile, cacheFile, true); + File.Copy(tempFile, cacheFile, true); return UnzipIfNeeded(path, cacheFile); } @@ -122,10 +122,10 @@ namespace Jellyfin.Server.Implementations.LiveTv.Listings private string ExtractFirstFileFromGz(string file) { - using (var stream = _fileSystem.OpenRead(file)) + using (var stream = File.OpenRead(file)) { string tempFolder = Path.Combine(_config.ApplicationPaths.TempDirectory, Guid.NewGuid().ToString()); - _fileSystem.CreateDirectory(tempFolder); + Directory.CreateDirectory(tempFolder); _zipClient.ExtractFirstFileFromGz(stream, tempFolder, "data.xml"); @@ -135,10 +135,10 @@ namespace Jellyfin.Server.Implementations.LiveTv.Listings private string ExtractGz(string file) { - using (var stream = _fileSystem.OpenRead(file)) + using (var stream = File.OpenRead(file)) { string tempFolder = Path.Combine(_config.ApplicationPaths.TempDirectory, Guid.NewGuid().ToString()); - _fileSystem.CreateDirectory(tempFolder); + Directory.CreateDirectory(tempFolder); _zipClient.ExtractAllFromGz(stream, tempFolder, true); @@ -255,7 +255,7 @@ namespace Jellyfin.Server.Implementations.LiveTv.Listings public Task Validate(ListingsProviderInfo info, bool validateLogin, bool validateListings) { // Assume all urls are valid. check files for existence - if (!info.Path.StartsWith("http", StringComparison.OrdinalIgnoreCase) && !_fileSystem.FileExists(info.Path)) + if (!info.Path.StartsWith("http", StringComparison.OrdinalIgnoreCase) && !File.Exists(info.Path)) { throw new FileNotFoundException("Could not find the XmlTv file specified:", info.Path); } 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/BaseTunerHost.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs index ee86f66e6..6d1eff187 100644 --- a/Emby.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs +++ b/Emby.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs @@ -95,7 +95,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts { try { - FileSystem.CreateDirectory(FileSystem.GetDirectoryName(channelCacheFile)); + Directory.CreateDirectory(Path.GetDirectoryName(channelCacheFile)); JsonSerializer.SerializeToFile(channels, channelCacheFile); } catch (IOException) diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs index 2542ddd2a..8774371d5 100644 --- a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs +++ b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs @@ -53,7 +53,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun var uri = new Uri(mediaSource.Path); var localPort = _networkManager.GetRandomUnusedUdpPort(); - FileSystem.CreateDirectory(FileSystem.GetDirectoryName(TempFilePath)); + Directory.CreateDirectory(Path.GetDirectoryName(TempFilePath)); Logger.LogInformation("Opening HDHR UDP Live stream from {host}", uri.Host); diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs index a54a53b25..9a01c42d3 100644 --- a/Emby.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs +++ b/Emby.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs @@ -61,7 +61,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts UserAgent = _appHost.ApplicationUserAgent }); } - return Task.FromResult(_fileSystem.OpenRead(url)); + return Task.FromResult((Stream)File.OpenRead(url)); } const string ExtInfPrefix = "#EXTINF:"; diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/SharedHttpStream.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/SharedHttpStream.cs index b39a9f679..4eff9252e 100644 --- a/Emby.Server.Implementations/LiveTv/TunerHosts/SharedHttpStream.cs +++ b/Emby.Server.Implementations/LiveTv/TunerHosts/SharedHttpStream.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.IO; using System.Threading; using System.Threading.Tasks; using MediaBrowser.Common.Net; @@ -35,7 +36,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts var url = mediaSource.Path; - FileSystem.CreateDirectory(FileSystem.GetDirectoryName(TempFilePath)); + Directory.CreateDirectory(Path.GetDirectoryName(TempFilePath)); var typeName = GetType().Name; Logger.LogInformation("Opening " + typeName + " Live stream from {0}", url); @@ -93,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 c408a47f6..262ca24ec 100644 --- a/Emby.Server.Implementations/Localization/LocalizationManager.cs +++ b/Emby.Server.Implementations/Localization/LocalizationManager.cs @@ -4,12 +4,14 @@ using System.Collections.Generic; using System.Globalization; using System.IO; using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; using MediaBrowser.Controller.Configuration; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Extensions; using MediaBrowser.Model.Globalization; using MediaBrowser.Model.IO; -using MediaBrowser.Model.Reflection; using MediaBrowser.Model.Serialization; using Microsoft.Extensions.Logging; @@ -36,8 +38,7 @@ namespace Emby.Server.Implementations.Localization private readonly IFileSystem _fileSystem; private readonly IJsonSerializer _jsonSerializer; private readonly ILogger _logger; - private readonly IAssemblyInfo _assemblyInfo; - private readonly ITextLocalizer _textLocalizer; + private static readonly Assembly _assembly = typeof(LocalizationManager).Assembly; /// <summary> /// Initializes a new instance of the <see cref="LocalizationManager" /> class. @@ -49,67 +50,57 @@ namespace Emby.Server.Implementations.Localization IServerConfigurationManager configurationManager, IFileSystem fileSystem, IJsonSerializer jsonSerializer, - ILoggerFactory loggerFactory, - IAssemblyInfo assemblyInfo, - ITextLocalizer textLocalizer) + ILoggerFactory loggerFactory) { _configurationManager = configurationManager; _fileSystem = fileSystem; _jsonSerializer = jsonSerializer; _logger = loggerFactory.CreateLogger(nameof(LocalizationManager)); - _assemblyInfo = assemblyInfo; - _textLocalizer = textLocalizer; - - ExtractAll(); } - private void ExtractAll() + public async Task LoadAll() { - var type = GetType(); - var resourcePath = type.Namespace + ".Ratings."; - - var localizationPath = LocalizationPath; + const string ratingsResource = "Emby.Server.Implementations.Ratings."; - _fileSystem.CreateDirectory(localizationPath); + Directory.CreateDirectory(LocalizationPath); - var existingFiles = GetRatingsFiles(localizationPath) - .Select(Path.GetFileName) - .ToList(); + var existingFiles = GetRatingsFiles(LocalizationPath).Select(Path.GetFileName); // Extract from the assembly - foreach (var resource in _assemblyInfo - .GetManifestResourceNames(type) - .Where(i => i.StartsWith(resourcePath))) + foreach (var resource in _assembly.GetManifestResourceNames() + .Where(i => i.StartsWith(ratingsResource))) { - var filename = "ratings-" + resource.Substring(resourcePath.Length); + string filename = "ratings-" + resource.Substring(ratingsResource.Length); if (!existingFiles.Contains(filename)) { - using (var stream = _assemblyInfo.GetManifestResourceStream(type, resource)) + using (var stream = _assembly.GetManifestResourceStream(resource)) { - var target = Path.Combine(localizationPath, filename); + string target = Path.Combine(LocalizationPath, filename); _logger.LogInformation("Extracting ratings to {0}", target); using (var fs = _fileSystem.GetFileStream(target, FileOpenMode.Create, FileAccessMode.Write, FileShareMode.Read)) { - stream.CopyTo(fs); + await stream.CopyToAsync(fs); } } } } - foreach (var file in GetRatingsFiles(localizationPath)) + foreach (var file in GetRatingsFiles(LocalizationPath)) { - LoadRatings(file); + await LoadRatings(file); } LoadAdditionalRatings(); + + await LoadCultures(); } private void LoadAdditionalRatings() { - LoadRatings("au", new[] { - + LoadRatings("au", new[] + { new ParentalRating("AU-G", 1), new ParentalRating("AU-PG", 5), new ParentalRating("AU-M", 6), @@ -120,8 +111,8 @@ namespace Emby.Server.Implementations.Localization new ParentalRating("AU-RC", 11) }); - LoadRatings("be", new[] { - + LoadRatings("be", new[] + { new ParentalRating("BE-AL", 1), new ParentalRating("BE-MG6", 2), new ParentalRating("BE-6", 3), @@ -130,8 +121,8 @@ namespace Emby.Server.Implementations.Localization new ParentalRating("BE-16", 8) }); - LoadRatings("de", new[] { - + LoadRatings("de", new[] + { new ParentalRating("DE-0", 1), new ParentalRating("FSK-0", 1), new ParentalRating("DE-6", 5), @@ -144,8 +135,8 @@ namespace Emby.Server.Implementations.Localization new ParentalRating("FSK-18", 9) }); - LoadRatings("ru", new[] { - + LoadRatings("ru", new[] + { new ParentalRating("RU-0+", 1), new ParentalRating("RU-6+", 3), new ParentalRating("RU-12+", 7), @@ -159,29 +150,20 @@ namespace Emby.Server.Implementations.Localization _allParentalRatings[country] = ratings.ToDictionary(i => i.Name); } - private List<string> GetRatingsFiles(string directory) - { - return _fileSystem.GetFilePaths(directory, false) - .Where(i => string.Equals(Path.GetExtension(i), ".txt", StringComparison.OrdinalIgnoreCase)) - .Where(i => Path.GetFileName(i).StartsWith("ratings-", StringComparison.OrdinalIgnoreCase)) - .ToList(); - } + private IEnumerable<string> GetRatingsFiles(string directory) + => _fileSystem.GetFilePaths(directory, false) + .Where(i => string.Equals(Path.GetExtension(i), ".csv", StringComparison.OrdinalIgnoreCase)) + .Where(i => Path.GetFileName(i).StartsWith("ratings-", StringComparison.OrdinalIgnoreCase)); /// <summary> /// Gets the localization path. /// </summary> /// <value>The localization path.</value> - public string LocalizationPath => Path.Combine(_configurationManager.ApplicationPaths.ProgramDataPath, "localization"); - - public string RemoveDiacritics(string text) - { - return _textLocalizer.RemoveDiacritics(text); - } + public string LocalizationPath + => Path.Combine(_configurationManager.ApplicationPaths.ProgramDataPath, "localization"); public string NormalizeFormKD(string text) - { - return _textLocalizer.NormalizeFormKD(text); - } + => text.Normalize(NormalizationForm.FormKD); private CultureDto[] _cultures; @@ -190,90 +172,88 @@ namespace Emby.Server.Implementations.Localization /// </summary> /// <returns>IEnumerable{CultureDto}.</returns> public CultureDto[] GetCultures() - { - var result = _cultures; - if (result != null) - { - return result; - } + => _cultures; - var type = GetType(); - var path = type.Namespace + ".iso6392.txt"; + private async Task LoadCultures() + { + List<CultureDto> list = new List<CultureDto>(); - var list = new List<CultureDto>(); + const string path = "Emby.Server.Implementations.Localization.iso6392.txt"; - using (var stream = _assemblyInfo.GetManifestResourceStream(type, path)) + using (var stream = _assembly.GetManifestResourceStream(path)) + using (var reader = new StreamReader(stream)) { - using (var reader = new StreamReader(stream)) + while (!reader.EndOfStream) { - while (!reader.EndOfStream) + var line = await reader.ReadLineAsync(); + + if (string.IsNullOrWhiteSpace(line)) + { + continue; + } + + var parts = line.Split('|'); + + if (parts.Length == 5) { - var line = reader.ReadLine(); + string name = parts[3]; + if (string.IsNullOrWhiteSpace(name)) + { + continue; + } - if (!string.IsNullOrWhiteSpace(line)) + string twoCharName = parts[2]; + if (string.IsNullOrWhiteSpace(twoCharName)) + { + continue; + } + + string[] threeletterNames; + if (string.IsNullOrWhiteSpace(parts[1])) + { + threeletterNames = new [] { parts[0] }; + } + else { - var parts = line.Split('|'); - - if (parts.Length == 5) - { - var threeletterNames = new List<string> { parts[0] }; - if (!string.IsNullOrWhiteSpace(parts[1])) - { - threeletterNames.Add(parts[1]); - } - - list.Add(new CultureDto - { - DisplayName = parts[3], - Name = parts[3], - ThreeLetterISOLanguageNames = threeletterNames.ToArray(), - TwoLetterISOLanguageName = parts[2] - }); - } + threeletterNames = new [] { parts[0], parts[1] }; } + + list.Add(new CultureDto + { + DisplayName = name, + Name = name, + ThreeLetterISOLanguageNames = threeletterNames, + TwoLetterISOLanguageName = twoCharName + }); } } } - result = list.Where(i => !string.IsNullOrWhiteSpace(i.Name) && - !string.IsNullOrWhiteSpace(i.DisplayName) && - i.ThreeLetterISOLanguageNames.Length > 0 && - !string.IsNullOrWhiteSpace(i.TwoLetterISOLanguageName)).ToArray(); - - _cultures = result; - - return result; + _cultures = list.ToArray(); } public CultureDto FindLanguageInfo(string language) - { - return GetCultures() - .FirstOrDefault(i => string.Equals(i.DisplayName, language, StringComparison.OrdinalIgnoreCase) || - string.Equals(i.Name, language, StringComparison.OrdinalIgnoreCase) || - i.ThreeLetterISOLanguageNames.Contains(language, StringComparer.OrdinalIgnoreCase) || - string.Equals(i.TwoLetterISOLanguageName, language, StringComparison.OrdinalIgnoreCase)); - } + => GetCultures() + .FirstOrDefault(i => + string.Equals(i.DisplayName, language, StringComparison.OrdinalIgnoreCase) + || string.Equals(i.Name, language, StringComparison.OrdinalIgnoreCase) + || i.ThreeLetterISOLanguageNames.Contains(language, StringComparer.OrdinalIgnoreCase) + || string.Equals(i.TwoLetterISOLanguageName, language, StringComparison.OrdinalIgnoreCase)); /// <summary> /// Gets the countries. /// </summary> /// <returns>IEnumerable{CountryInfo}.</returns> - public CountryInfo[] GetCountries() - { - // ToDo: DeserializeFromStream seems broken in this case - string jsonCountries = "[{\"Name\":\"AF\",\"DisplayName\":\"Afghanistan\",\"TwoLetterISORegionName\":\"AF\",\"ThreeLetterISORegionName\":\"AFG\"},{\"Name\":\"AL\",\"DisplayName\":\"Albania\",\"TwoLetterISORegionName\":\"AL\",\"ThreeLetterISORegionName\":\"ALB\"},{\"Name\":\"DZ\",\"DisplayName\":\"Algeria\",\"TwoLetterISORegionName\":\"DZ\",\"ThreeLetterISORegionName\":\"DZA\"},{\"Name\":\"AR\",\"DisplayName\":\"Argentina\",\"TwoLetterISORegionName\":\"AR\",\"ThreeLetterISORegionName\":\"ARG\"},{\"Name\":\"AM\",\"DisplayName\":\"Armenia\",\"TwoLetterISORegionName\":\"AM\",\"ThreeLetterISORegionName\":\"ARM\"},{\"Name\":\"AU\",\"DisplayName\":\"Australia\",\"TwoLetterISORegionName\":\"AU\",\"ThreeLetterISORegionName\":\"AUS\"},{\"Name\":\"AT\",\"DisplayName\":\"Austria\",\"TwoLetterISORegionName\":\"AT\",\"ThreeLetterISORegionName\":\"AUT\"},{\"Name\":\"AZ\",\"DisplayName\":\"Azerbaijan\",\"TwoLetterISORegionName\":\"AZ\",\"ThreeLetterISORegionName\":\"AZE\"},{\"Name\":\"BH\",\"DisplayName\":\"Bahrain\",\"TwoLetterISORegionName\":\"BH\",\"ThreeLetterISORegionName\":\"BHR\"},{\"Name\":\"BD\",\"DisplayName\":\"Bangladesh\",\"TwoLetterISORegionName\":\"BD\",\"ThreeLetterISORegionName\":\"BGD\"},{\"Name\":\"BY\",\"DisplayName\":\"Belarus\",\"TwoLetterISORegionName\":\"BY\",\"ThreeLetterISORegionName\":\"BLR\"},{\"Name\":\"BE\",\"DisplayName\":\"Belgium\",\"TwoLetterISORegionName\":\"BE\",\"ThreeLetterISORegionName\":\"BEL\"},{\"Name\":\"BZ\",\"DisplayName\":\"Belize\",\"TwoLetterISORegionName\":\"BZ\",\"ThreeLetterISORegionName\":\"BLZ\"},{\"Name\":\"VE\",\"DisplayName\":\"Bolivarian Republic of Venezuela\",\"TwoLetterISORegionName\":\"VE\",\"ThreeLetterISORegionName\":\"VEN\"},{\"Name\":\"BO\",\"DisplayName\":\"Bolivia\",\"TwoLetterISORegionName\":\"BO\",\"ThreeLetterISORegionName\":\"BOL\"},{\"Name\":\"BA\",\"DisplayName\":\"Bosnia and Herzegovina\",\"TwoLetterISORegionName\":\"BA\",\"ThreeLetterISORegionName\":\"BIH\"},{\"Name\":\"BW\",\"DisplayName\":\"Botswana\",\"TwoLetterISORegionName\":\"BW\",\"ThreeLetterISORegionName\":\"BWA\"},{\"Name\":\"BR\",\"DisplayName\":\"Brazil\",\"TwoLetterISORegionName\":\"BR\",\"ThreeLetterISORegionName\":\"BRA\"},{\"Name\":\"BN\",\"DisplayName\":\"Brunei Darussalam\",\"TwoLetterISORegionName\":\"BN\",\"ThreeLetterISORegionName\":\"BRN\"},{\"Name\":\"BG\",\"DisplayName\":\"Bulgaria\",\"TwoLetterISORegionName\":\"BG\",\"ThreeLetterISORegionName\":\"BGR\"},{\"Name\":\"KH\",\"DisplayName\":\"Cambodia\",\"TwoLetterISORegionName\":\"KH\",\"ThreeLetterISORegionName\":\"KHM\"},{\"Name\":\"CM\",\"DisplayName\":\"Cameroon\",\"TwoLetterISORegionName\":\"CM\",\"ThreeLetterISORegionName\":\"CMR\"},{\"Name\":\"CA\",\"DisplayName\":\"Canada\",\"TwoLetterISORegionName\":\"CA\",\"ThreeLetterISORegionName\":\"CAN\"},{\"Name\":\"029\",\"DisplayName\":\"Caribbean\",\"TwoLetterISORegionName\":\"029\",\"ThreeLetterISORegionName\":\"029\"},{\"Name\":\"CL\",\"DisplayName\":\"Chile\",\"TwoLetterISORegionName\":\"CL\",\"ThreeLetterISORegionName\":\"CHL\"},{\"Name\":\"CO\",\"DisplayName\":\"Colombia\",\"TwoLetterISORegionName\":\"CO\",\"ThreeLetterISORegionName\":\"COL\"},{\"Name\":\"CD\",\"DisplayName\":\"Congo [DRC]\",\"TwoLetterISORegionName\":\"CD\",\"ThreeLetterISORegionName\":\"COD\"},{\"Name\":\"CR\",\"DisplayName\":\"Costa Rica\",\"TwoLetterISORegionName\":\"CR\",\"ThreeLetterISORegionName\":\"CRI\"},{\"Name\":\"HR\",\"DisplayName\":\"Croatia\",\"TwoLetterISORegionName\":\"HR\",\"ThreeLetterISORegionName\":\"HRV\"},{\"Name\":\"CZ\",\"DisplayName\":\"Czech Republic\",\"TwoLetterISORegionName\":\"CZ\",\"ThreeLetterISORegionName\":\"CZE\"},{\"Name\":\"DK\",\"DisplayName\":\"Denmark\",\"TwoLetterISORegionName\":\"DK\",\"ThreeLetterISORegionName\":\"DNK\"},{\"Name\":\"DO\",\"DisplayName\":\"Dominican Republic\",\"TwoLetterISORegionName\":\"DO\",\"ThreeLetterISORegionName\":\"DOM\"},{\"Name\":\"EC\",\"DisplayName\":\"Ecuador\",\"TwoLetterISORegionName\":\"EC\",\"ThreeLetterISORegionName\":\"ECU\"},{\"Name\":\"EG\",\"DisplayName\":\"Egypt\",\"TwoLetterISORegionName\":\"EG\",\"ThreeLetterISORegionName\":\"EGY\"},{\"Name\":\"SV\",\"DisplayName\":\"El Salvador\",\"TwoLetterISORegionName\":\"SV\",\"ThreeLetterISORegionName\":\"SLV\"},{\"Name\":\"ER\",\"DisplayName\":\"Eritrea\",\"TwoLetterISORegionName\":\"ER\",\"ThreeLetterISORegionName\":\"ERI\"},{\"Name\":\"EE\",\"DisplayName\":\"Estonia\",\"TwoLetterISORegionName\":\"EE\",\"ThreeLetterISORegionName\":\"EST\"},{\"Name\":\"ET\",\"DisplayName\":\"Ethiopia\",\"TwoLetterISORegionName\":\"ET\",\"ThreeLetterISORegionName\":\"ETH\"},{\"Name\":\"FO\",\"DisplayName\":\"Faroe Islands\",\"TwoLetterISORegionName\":\"FO\",\"ThreeLetterISORegionName\":\"FRO\"},{\"Name\":\"FI\",\"DisplayName\":\"Finland\",\"TwoLetterISORegionName\":\"FI\",\"ThreeLetterISORegionName\":\"FIN\"},{\"Name\":\"FR\",\"DisplayName\":\"France\",\"TwoLetterISORegionName\":\"FR\",\"ThreeLetterISORegionName\":\"FRA\"},{\"Name\":\"GE\",\"DisplayName\":\"Georgia\",\"TwoLetterISORegionName\":\"GE\",\"ThreeLetterISORegionName\":\"GEO\"},{\"Name\":\"DE\",\"DisplayName\":\"Germany\",\"TwoLetterISORegionName\":\"DE\",\"ThreeLetterISORegionName\":\"DEU\"},{\"Name\":\"GR\",\"DisplayName\":\"Greece\",\"TwoLetterISORegionName\":\"GR\",\"ThreeLetterISORegionName\":\"GRC\"},{\"Name\":\"GL\",\"DisplayName\":\"Greenland\",\"TwoLetterISORegionName\":\"GL\",\"ThreeLetterISORegionName\":\"GRL\"},{\"Name\":\"GT\",\"DisplayName\":\"Guatemala\",\"TwoLetterISORegionName\":\"GT\",\"ThreeLetterISORegionName\":\"GTM\"},{\"Name\":\"HT\",\"DisplayName\":\"Haiti\",\"TwoLetterISORegionName\":\"HT\",\"ThreeLetterISORegionName\":\"HTI\"},{\"Name\":\"HN\",\"DisplayName\":\"Honduras\",\"TwoLetterISORegionName\":\"HN\",\"ThreeLetterISORegionName\":\"HND\"},{\"Name\":\"HK\",\"DisplayName\":\"Hong Kong S.A.R.\",\"TwoLetterISORegionName\":\"HK\",\"ThreeLetterISORegionName\":\"HKG\"},{\"Name\":\"HU\",\"DisplayName\":\"Hungary\",\"TwoLetterISORegionName\":\"HU\",\"ThreeLetterISORegionName\":\"HUN\"},{\"Name\":\"IS\",\"DisplayName\":\"Iceland\",\"TwoLetterISORegionName\":\"IS\",\"ThreeLetterISORegionName\":\"ISL\"},{\"Name\":\"IN\",\"DisplayName\":\"India\",\"TwoLetterISORegionName\":\"IN\",\"ThreeLetterISORegionName\":\"IND\"},{\"Name\":\"ID\",\"DisplayName\":\"Indonesia\",\"TwoLetterISORegionName\":\"ID\",\"ThreeLetterISORegionName\":\"IDN\"},{\"Name\":\"IR\",\"DisplayName\":\"Iran\",\"TwoLetterISORegionName\":\"IR\",\"ThreeLetterISORegionName\":\"IRN\"},{\"Name\":\"IQ\",\"DisplayName\":\"Iraq\",\"TwoLetterISORegionName\":\"IQ\",\"ThreeLetterISORegionName\":\"IRQ\"},{\"Name\":\"IE\",\"DisplayName\":\"Ireland\",\"TwoLetterISORegionName\":\"IE\",\"ThreeLetterISORegionName\":\"IRL\"},{\"Name\":\"PK\",\"DisplayName\":\"Islamic Republic of Pakistan\",\"TwoLetterISORegionName\":\"PK\",\"ThreeLetterISORegionName\":\"PAK\"},{\"Name\":\"IL\",\"DisplayName\":\"Israel\",\"TwoLetterISORegionName\":\"IL\",\"ThreeLetterISORegionName\":\"ISR\"},{\"Name\":\"IT\",\"DisplayName\":\"Italy\",\"TwoLetterISORegionName\":\"IT\",\"ThreeLetterISORegionName\":\"ITA\"},{\"Name\":\"CI\",\"DisplayName\":\"Ivory Coast\",\"TwoLetterISORegionName\":\"CI\",\"ThreeLetterISORegionName\":\"CIV\"},{\"Name\":\"JM\",\"DisplayName\":\"Jamaica\",\"TwoLetterISORegionName\":\"JM\",\"ThreeLetterISORegionName\":\"JAM\"},{\"Name\":\"JP\",\"DisplayName\":\"Japan\",\"TwoLetterISORegionName\":\"JP\",\"ThreeLetterISORegionName\":\"JPN\"},{\"Name\":\"JO\",\"DisplayName\":\"Jordan\",\"TwoLetterISORegionName\":\"JO\",\"ThreeLetterISORegionName\":\"JOR\"},{\"Name\":\"KZ\",\"DisplayName\":\"Kazakhstan\",\"TwoLetterISORegionName\":\"KZ\",\"ThreeLetterISORegionName\":\"KAZ\"},{\"Name\":\"KE\",\"DisplayName\":\"Kenya\",\"TwoLetterISORegionName\":\"KE\",\"ThreeLetterISORegionName\":\"KEN\"},{\"Name\":\"KR\",\"DisplayName\":\"Korea\",\"TwoLetterISORegionName\":\"KR\",\"ThreeLetterISORegionName\":\"KOR\"},{\"Name\":\"KW\",\"DisplayName\":\"Kuwait\",\"TwoLetterISORegionName\":\"KW\",\"ThreeLetterISORegionName\":\"KWT\"},{\"Name\":\"KG\",\"DisplayName\":\"Kyrgyzstan\",\"TwoLetterISORegionName\":\"KG\",\"ThreeLetterISORegionName\":\"KGZ\"},{\"Name\":\"LA\",\"DisplayName\":\"Lao P.D.R.\",\"TwoLetterISORegionName\":\"LA\",\"ThreeLetterISORegionName\":\"LAO\"},{\"Name\":\"419\",\"DisplayName\":\"Latin America\",\"TwoLetterISORegionName\":\"419\",\"ThreeLetterISORegionName\":\"419\"},{\"Name\":\"LV\",\"DisplayName\":\"Latvia\",\"TwoLetterISORegionName\":\"LV\",\"ThreeLetterISORegionName\":\"LVA\"},{\"Name\":\"LB\",\"DisplayName\":\"Lebanon\",\"TwoLetterISORegionName\":\"LB\",\"ThreeLetterISORegionName\":\"LBN\"},{\"Name\":\"LY\",\"DisplayName\":\"Libya\",\"TwoLetterISORegionName\":\"LY\",\"ThreeLetterISORegionName\":\"LBY\"},{\"Name\":\"LI\",\"DisplayName\":\"Liechtenstein\",\"TwoLetterISORegionName\":\"LI\",\"ThreeLetterISORegionName\":\"LIE\"},{\"Name\":\"LT\",\"DisplayName\":\"Lithuania\",\"TwoLetterISORegionName\":\"LT\",\"ThreeLetterISORegionName\":\"LTU\"},{\"Name\":\"LU\",\"DisplayName\":\"Luxembourg\",\"TwoLetterISORegionName\":\"LU\",\"ThreeLetterISORegionName\":\"LUX\"},{\"Name\":\"MO\",\"DisplayName\":\"Macao S.A.R.\",\"TwoLetterISORegionName\":\"MO\",\"ThreeLetterISORegionName\":\"MAC\"},{\"Name\":\"MK\",\"DisplayName\":\"Macedonia (FYROM)\",\"TwoLetterISORegionName\":\"MK\",\"ThreeLetterISORegionName\":\"MKD\"},{\"Name\":\"MY\",\"DisplayName\":\"Malaysia\",\"TwoLetterISORegionName\":\"MY\",\"ThreeLetterISORegionName\":\"MYS\"},{\"Name\":\"MV\",\"DisplayName\":\"Maldives\",\"TwoLetterISORegionName\":\"MV\",\"ThreeLetterISORegionName\":\"MDV\"},{\"Name\":\"ML\",\"DisplayName\":\"Mali\",\"TwoLetterISORegionName\":\"ML\",\"ThreeLetterISORegionName\":\"MLI\"},{\"Name\":\"MT\",\"DisplayName\":\"Malta\",\"TwoLetterISORegionName\":\"MT\",\"ThreeLetterISORegionName\":\"MLT\"},{\"Name\":\"MX\",\"DisplayName\":\"Mexico\",\"TwoLetterISORegionName\":\"MX\",\"ThreeLetterISORegionName\":\"MEX\"},{\"Name\":\"MN\",\"DisplayName\":\"Mongolia\",\"TwoLetterISORegionName\":\"MN\",\"ThreeLetterISORegionName\":\"MNG\"},{\"Name\":\"ME\",\"DisplayName\":\"Montenegro\",\"TwoLetterISORegionName\":\"ME\",\"ThreeLetterISORegionName\":\"MNE\"},{\"Name\":\"MA\",\"DisplayName\":\"Morocco\",\"TwoLetterISORegionName\":\"MA\",\"ThreeLetterISORegionName\":\"MAR\"},{\"Name\":\"NP\",\"DisplayName\":\"Nepal\",\"TwoLetterISORegionName\":\"NP\",\"ThreeLetterISORegionName\":\"NPL\"},{\"Name\":\"NL\",\"DisplayName\":\"Netherlands\",\"TwoLetterISORegionName\":\"NL\",\"ThreeLetterISORegionName\":\"NLD\"},{\"Name\":\"NZ\",\"DisplayName\":\"New Zealand\",\"TwoLetterISORegionName\":\"NZ\",\"ThreeLetterISORegionName\":\"NZL\"},{\"Name\":\"NI\",\"DisplayName\":\"Nicaragua\",\"TwoLetterISORegionName\":\"NI\",\"ThreeLetterISORegionName\":\"NIC\"},{\"Name\":\"NG\",\"DisplayName\":\"Nigeria\",\"TwoLetterISORegionName\":\"NG\",\"ThreeLetterISORegionName\":\"NGA\"},{\"Name\":\"NO\",\"DisplayName\":\"Norway\",\"TwoLetterISORegionName\":\"NO\",\"ThreeLetterISORegionName\":\"NOR\"},{\"Name\":\"OM\",\"DisplayName\":\"Oman\",\"TwoLetterISORegionName\":\"OM\",\"ThreeLetterISORegionName\":\"OMN\"},{\"Name\":\"PA\",\"DisplayName\":\"Panama\",\"TwoLetterISORegionName\":\"PA\",\"ThreeLetterISORegionName\":\"PAN\"},{\"Name\":\"PY\",\"DisplayName\":\"Paraguay\",\"TwoLetterISORegionName\":\"PY\",\"ThreeLetterISORegionName\":\"PRY\"},{\"Name\":\"CN\",\"DisplayName\":\"People's Republic of China\",\"TwoLetterISORegionName\":\"CN\",\"ThreeLetterISORegionName\":\"CHN\"},{\"Name\":\"PE\",\"DisplayName\":\"Peru\",\"TwoLetterISORegionName\":\"PE\",\"ThreeLetterISORegionName\":\"PER\"},{\"Name\":\"PH\",\"DisplayName\":\"Philippines\",\"TwoLetterISORegionName\":\"PH\",\"ThreeLetterISORegionName\":\"PHL\"},{\"Name\":\"PL\",\"DisplayName\":\"Poland\",\"TwoLetterISORegionName\":\"PL\",\"ThreeLetterISORegionName\":\"POL\"},{\"Name\":\"PT\",\"DisplayName\":\"Portugal\",\"TwoLetterISORegionName\":\"PT\",\"ThreeLetterISORegionName\":\"PRT\"},{\"Name\":\"MC\",\"DisplayName\":\"Principality of Monaco\",\"TwoLetterISORegionName\":\"MC\",\"ThreeLetterISORegionName\":\"MCO\"},{\"Name\":\"PR\",\"DisplayName\":\"Puerto Rico\",\"TwoLetterISORegionName\":\"PR\",\"ThreeLetterISORegionName\":\"PRI\"},{\"Name\":\"QA\",\"DisplayName\":\"Qatar\",\"TwoLetterISORegionName\":\"QA\",\"ThreeLetterISORegionName\":\"QAT\"},{\"Name\":\"MD\",\"DisplayName\":\"Republica Moldova\",\"TwoLetterISORegionName\":\"MD\",\"ThreeLetterISORegionName\":\"MDA\"},{\"Name\":\"RE\",\"DisplayName\":\"Réunion\",\"TwoLetterISORegionName\":\"RE\",\"ThreeLetterISORegionName\":\"REU\"},{\"Name\":\"RO\",\"DisplayName\":\"Romania\",\"TwoLetterISORegionName\":\"RO\",\"ThreeLetterISORegionName\":\"ROU\"},{\"Name\":\"RU\",\"DisplayName\":\"Russia\",\"TwoLetterISORegionName\":\"RU\",\"ThreeLetterISORegionName\":\"RUS\"},{\"Name\":\"RW\",\"DisplayName\":\"Rwanda\",\"TwoLetterISORegionName\":\"RW\",\"ThreeLetterISORegionName\":\"RWA\"},{\"Name\":\"SA\",\"DisplayName\":\"Saudi Arabia\",\"TwoLetterISORegionName\":\"SA\",\"ThreeLetterISORegionName\":\"SAU\"},{\"Name\":\"SN\",\"DisplayName\":\"Senegal\",\"TwoLetterISORegionName\":\"SN\",\"ThreeLetterISORegionName\":\"SEN\"},{\"Name\":\"RS\",\"DisplayName\":\"Serbia\",\"TwoLetterISORegionName\":\"RS\",\"ThreeLetterISORegionName\":\"SRB\"},{\"Name\":\"CS\",\"DisplayName\":\"Serbia and Montenegro (Former)\",\"TwoLetterISORegionName\":\"CS\",\"ThreeLetterISORegionName\":\"SCG\"},{\"Name\":\"SG\",\"DisplayName\":\"Singapore\",\"TwoLetterISORegionName\":\"SG\",\"ThreeLetterISORegionName\":\"SGP\"},{\"Name\":\"SK\",\"DisplayName\":\"Slovakia\",\"TwoLetterISORegionName\":\"SK\",\"ThreeLetterISORegionName\":\"SVK\"},{\"Name\":\"SI\",\"DisplayName\":\"Slovenia\",\"TwoLetterISORegionName\":\"SI\",\"ThreeLetterISORegionName\":\"SVN\"},{\"Name\":\"SO\",\"DisplayName\":\"Soomaaliya\",\"TwoLetterISORegionName\":\"SO\",\"ThreeLetterISORegionName\":\"SOM\"},{\"Name\":\"ZA\",\"DisplayName\":\"South Africa\",\"TwoLetterISORegionName\":\"ZA\",\"ThreeLetterISORegionName\":\"ZAF\"},{\"Name\":\"ES\",\"DisplayName\":\"Spain\",\"TwoLetterISORegionName\":\"ES\",\"ThreeLetterISORegionName\":\"ESP\"},{\"Name\":\"LK\",\"DisplayName\":\"Sri Lanka\",\"TwoLetterISORegionName\":\"LK\",\"ThreeLetterISORegionName\":\"LKA\"},{\"Name\":\"SE\",\"DisplayName\":\"Sweden\",\"TwoLetterISORegionName\":\"SE\",\"ThreeLetterISORegionName\":\"SWE\"},{\"Name\":\"CH\",\"DisplayName\":\"Switzerland\",\"TwoLetterISORegionName\":\"CH\",\"ThreeLetterISORegionName\":\"CHE\"},{\"Name\":\"SY\",\"DisplayName\":\"Syria\",\"TwoLetterISORegionName\":\"SY\",\"ThreeLetterISORegionName\":\"SYR\"},{\"Name\":\"TW\",\"DisplayName\":\"Taiwan\",\"TwoLetterISORegionName\":\"TW\",\"ThreeLetterISORegionName\":\"TWN\"},{\"Name\":\"TJ\",\"DisplayName\":\"Tajikistan\",\"TwoLetterISORegionName\":\"TJ\",\"ThreeLetterISORegionName\":\"TAJ\"},{\"Name\":\"TH\",\"DisplayName\":\"Thailand\",\"TwoLetterISORegionName\":\"TH\",\"ThreeLetterISORegionName\":\"THA\"},{\"Name\":\"TT\",\"DisplayName\":\"Trinidad and Tobago\",\"TwoLetterISORegionName\":\"TT\",\"ThreeLetterISORegionName\":\"TTO\"},{\"Name\":\"TN\",\"DisplayName\":\"Tunisia\",\"TwoLetterISORegionName\":\"TN\",\"ThreeLetterISORegionName\":\"TUN\"},{\"Name\":\"TR\",\"DisplayName\":\"Turkey\",\"TwoLetterISORegionName\":\"TR\",\"ThreeLetterISORegionName\":\"TUR\"},{\"Name\":\"TM\",\"DisplayName\":\"Turkmenistan\",\"TwoLetterISORegionName\":\"TM\",\"ThreeLetterISORegionName\":\"TKM\"},{\"Name\":\"AE\",\"DisplayName\":\"U.A.E.\",\"TwoLetterISORegionName\":\"AE\",\"ThreeLetterISORegionName\":\"ARE\"},{\"Name\":\"UA\",\"DisplayName\":\"Ukraine\",\"TwoLetterISORegionName\":\"UA\",\"ThreeLetterISORegionName\":\"UKR\"},{\"Name\":\"GB\",\"DisplayName\":\"United Kingdom\",\"TwoLetterISORegionName\":\"GB\",\"ThreeLetterISORegionName\":\"GBR\"},{\"Name\":\"US\",\"DisplayName\":\"United States\",\"TwoLetterISORegionName\":\"US\",\"ThreeLetterISORegionName\":\"USA\"},{\"Name\":\"UY\",\"DisplayName\":\"Uruguay\",\"TwoLetterISORegionName\":\"UY\",\"ThreeLetterISORegionName\":\"URY\"},{\"Name\":\"UZ\",\"DisplayName\":\"Uzbekistan\",\"TwoLetterISORegionName\":\"UZ\",\"ThreeLetterISORegionName\":\"UZB\"},{\"Name\":\"VN\",\"DisplayName\":\"Vietnam\",\"TwoLetterISORegionName\":\"VN\",\"ThreeLetterISORegionName\":\"VNM\"},{\"Name\":\"YE\",\"DisplayName\":\"Yemen\",\"TwoLetterISORegionName\":\"YE\",\"ThreeLetterISORegionName\":\"YEM\"},{\"Name\":\"ZW\",\"DisplayName\":\"Zimbabwe\",\"TwoLetterISORegionName\":\"ZW\",\"ThreeLetterISORegionName\":\"ZWE\"}]"; - - return _jsonSerializer.DeserializeFromString<CountryInfo[]>(jsonCountries); - } + public Task<CountryInfo[]> GetCountries() + => _jsonSerializer.DeserializeFromStreamAsync<CountryInfo[]>( + _assembly.GetManifestResourceStream("Emby.Server.Implementations.Localization.countries.json")); /// <summary> /// Gets the parental ratings. /// </summary> /// <returns>IEnumerable{ParentalRating}.</returns> - public ParentalRating[] GetParentalRatings() - { - return GetParentalRatingsDictionary().Values.ToArray(); - } + public IEnumerable<ParentalRating> GetParentalRatings() + => GetParentalRatingsDictionary().Values; /// <summary> /// Gets the parental ratings dictionary. @@ -288,14 +268,7 @@ namespace Emby.Server.Implementations.Localization countryCode = "us"; } - var ratings = GetRatings(countryCode); - - if (ratings == null) - { - ratings = GetRatings("us"); - } - - return ratings; + return GetRatings(countryCode) ?? GetRatings("us"); } /// <summary> @@ -314,37 +287,39 @@ namespace Emby.Server.Implementations.Localization /// </summary> /// <param name="file">The file.</param> /// <returns>Dictionary{System.StringParentalRating}.</returns> - private void LoadRatings(string file) + private async Task LoadRatings(string file) { - var dict = _fileSystem.ReadAllLines(file).Select(i => + Dictionary<string, ParentalRating> dict = new Dictionary<string, ParentalRating>(StringComparer.OrdinalIgnoreCase); + + using (var str = File.OpenRead(file)) + using (var reader = new StreamReader(str)) { - if (!string.IsNullOrWhiteSpace(i)) + string line; + while ((line = await reader.ReadLineAsync()) != null) { - var parts = i.Split(','); + if (string.IsNullOrWhiteSpace(line)) + { + continue; + } - if (parts.Length == 2) + string[] parts = line.Split(','); + if (parts.Length == 2 + && int.TryParse(parts[1], NumberStyles.Integer, UsCulture, out var value)) { - if (int.TryParse(parts[1], NumberStyles.Integer, UsCulture, out var value)) - { - return new ParentalRating { Name = parts[0], Value = value }; - } + dict.Add(parts[0], (new ParentalRating { Name = parts[0], Value = value })); } +#if DEBUG + _logger.LogWarning("Misformed line in {Path}", file); +#endif } + } - return null; - - }) - .Where(i => i != null) - .ToDictionary(i => i.Name, StringComparer.OrdinalIgnoreCase); - - var countryCode = _fileSystem.GetFileNameWithoutExtension(file) - .Split('-') - .Last(); + var countryCode = Path.GetFileNameWithoutExtension(file).Split('-')[1]; _allParentalRatings[countryCode] = dict; } - private readonly string[] _unratedValues = { "n/a", "unrated", "not rated" }; + private static readonly string[] _unratedValues = { "n/a", "unrated", "not rated" }; /// <summary> /// Gets the rating level. @@ -435,7 +410,7 @@ namespace Emby.Server.Implementations.Localization return phrase; } - const string DefaultCulture = "en-US"; + private const string DefaultCulture = "en-US"; private readonly ConcurrentDictionary<string, Dictionary<string, string>> _dictionaries = new ConcurrentDictionary<string, Dictionary<string, string>>(StringComparer.OrdinalIgnoreCase); @@ -450,10 +425,11 @@ namespace Emby.Server.Implementations.Localization const string prefix = "Core"; var key = prefix + culture; - return _dictionaries.GetOrAdd(key, k => GetDictionary(prefix, culture, DefaultCulture + ".json")); + return _dictionaries.GetOrAdd(key, + f => GetDictionary(prefix, culture, DefaultCulture + ".json").GetAwaiter().GetResult()); } - private Dictionary<string, string> GetDictionary(string prefix, string culture, string baseFilename) + private async Task<Dictionary<string, string>> GetDictionary(string prefix, string culture, string baseFilename) { if (string.IsNullOrEmpty(culture)) { @@ -464,24 +440,21 @@ namespace Emby.Server.Implementations.Localization var namespaceName = GetType().Namespace + "." + prefix; - CopyInto(dictionary, namespaceName + "." + baseFilename); - CopyInto(dictionary, namespaceName + "." + GetResourceFilename(culture)); + await CopyInto(dictionary, namespaceName + "." + baseFilename); + await CopyInto(dictionary, namespaceName + "." + GetResourceFilename(culture)); return dictionary; } - private void CopyInto(IDictionary<string, string> dictionary, string resourcePath) + private async Task CopyInto(IDictionary<string, string> dictionary, string resourcePath) { - using (var stream = _assemblyInfo.GetManifestResourceStream(GetType(), resourcePath)) + using (var stream = _assembly.GetManifestResourceStream(resourcePath)) { - if (stream != null) - { - var dict = _jsonSerializer.DeserializeFromStream<Dictionary<string, string>>(stream); + var dict = await _jsonSerializer.DeserializeFromStreamAsync<Dictionary<string, string>>(stream); - foreach (var key in dict.Keys) - { - dictionary[key] = dict[key]; - } + foreach (var key in dict.Keys) + { + dictionary[key] = dict[key]; } } } @@ -492,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"; @@ -552,11 +525,4 @@ namespace Emby.Server.Implementations.Localization new LocalizationOption("Vietnamese", "vi") }; } - - public interface ITextLocalizer - { - string RemoveDiacritics(string text); - - string NormalizeFormKD(string text); - } } diff --git a/Emby.Server.Implementations/Localization/Ratings/br.txt b/Emby.Server.Implementations/Localization/Ratings/br.csv index e5edaf62c..e5edaf62c 100644 --- a/Emby.Server.Implementations/Localization/Ratings/br.txt +++ b/Emby.Server.Implementations/Localization/Ratings/br.csv diff --git a/Emby.Server.Implementations/Localization/Ratings/ca.txt b/Emby.Server.Implementations/Localization/Ratings/ca.csv index 5aef0580f..5aef0580f 100644 --- a/Emby.Server.Implementations/Localization/Ratings/ca.txt +++ b/Emby.Server.Implementations/Localization/Ratings/ca.csv diff --git a/Emby.Server.Implementations/Localization/Ratings/co.txt b/Emby.Server.Implementations/Localization/Ratings/co.csv index 9684fa052..9684fa052 100644 --- a/Emby.Server.Implementations/Localization/Ratings/co.txt +++ b/Emby.Server.Implementations/Localization/Ratings/co.csv diff --git a/Emby.Server.Implementations/Localization/Ratings/dk.txt b/Emby.Server.Implementations/Localization/Ratings/dk.csv index 5364ae1f2..5364ae1f2 100644 --- a/Emby.Server.Implementations/Localization/Ratings/dk.txt +++ b/Emby.Server.Implementations/Localization/Ratings/dk.csv diff --git a/Emby.Server.Implementations/Localization/Ratings/es.txt b/Emby.Server.Implementations/Localization/Ratings/es.csv index 887d91ba6..887d91ba6 100644 --- a/Emby.Server.Implementations/Localization/Ratings/es.txt +++ b/Emby.Server.Implementations/Localization/Ratings/es.csv diff --git a/Emby.Server.Implementations/Localization/Ratings/fr.txt b/Emby.Server.Implementations/Localization/Ratings/fr.csv index f586a3fa9..f586a3fa9 100644 --- a/Emby.Server.Implementations/Localization/Ratings/fr.txt +++ b/Emby.Server.Implementations/Localization/Ratings/fr.csv diff --git a/Emby.Server.Implementations/Localization/Ratings/gb.txt b/Emby.Server.Implementations/Localization/Ratings/gb.csv index c1f7d0452..c1f7d0452 100644 --- a/Emby.Server.Implementations/Localization/Ratings/gb.txt +++ b/Emby.Server.Implementations/Localization/Ratings/gb.csv diff --git a/Emby.Server.Implementations/Localization/Ratings/ie.txt b/Emby.Server.Implementations/Localization/Ratings/ie.csv index e42be5cd4..e42be5cd4 100644 --- a/Emby.Server.Implementations/Localization/Ratings/ie.txt +++ b/Emby.Server.Implementations/Localization/Ratings/ie.csv diff --git a/Emby.Server.Implementations/Localization/Ratings/jp.txt b/Emby.Server.Implementations/Localization/Ratings/jp.csv index a8fc2d143..a8fc2d143 100644 --- a/Emby.Server.Implementations/Localization/Ratings/jp.txt +++ b/Emby.Server.Implementations/Localization/Ratings/jp.csv diff --git a/Emby.Server.Implementations/Localization/Ratings/kz.txt b/Emby.Server.Implementations/Localization/Ratings/kz.csv index 4441c5650..4441c5650 100644 --- a/Emby.Server.Implementations/Localization/Ratings/kz.txt +++ b/Emby.Server.Implementations/Localization/Ratings/kz.csv diff --git a/Emby.Server.Implementations/Localization/Ratings/mx.txt b/Emby.Server.Implementations/Localization/Ratings/mx.csv index 785a8ba22..785a8ba22 100644 --- a/Emby.Server.Implementations/Localization/Ratings/mx.txt +++ b/Emby.Server.Implementations/Localization/Ratings/mx.csv diff --git a/Emby.Server.Implementations/Localization/Ratings/nl.txt b/Emby.Server.Implementations/Localization/Ratings/nl.csv index 8c005092e..8c005092e 100644 --- a/Emby.Server.Implementations/Localization/Ratings/nl.txt +++ b/Emby.Server.Implementations/Localization/Ratings/nl.csv diff --git a/Emby.Server.Implementations/Localization/Ratings/nz.txt b/Emby.Server.Implementations/Localization/Ratings/nz.csv index bba99b764..bba99b764 100644 --- a/Emby.Server.Implementations/Localization/Ratings/nz.txt +++ b/Emby.Server.Implementations/Localization/Ratings/nz.csv diff --git a/Emby.Server.Implementations/Localization/Ratings/ro.txt b/Emby.Server.Implementations/Localization/Ratings/ro.csv index 4089b282f..4089b282f 100644 --- a/Emby.Server.Implementations/Localization/Ratings/ro.txt +++ b/Emby.Server.Implementations/Localization/Ratings/ro.csv diff --git a/Emby.Server.Implementations/Localization/Ratings/uk.txt b/Emby.Server.Implementations/Localization/Ratings/uk.csv index 6c8005b3f..6c8005b3f 100644 --- a/Emby.Server.Implementations/Localization/Ratings/uk.txt +++ b/Emby.Server.Implementations/Localization/Ratings/uk.csv diff --git a/Emby.Server.Implementations/Localization/Ratings/us.txt b/Emby.Server.Implementations/Localization/Ratings/us.csv index 34c897fe3..34c897fe3 100644 --- a/Emby.Server.Implementations/Localization/Ratings/us.txt +++ b/Emby.Server.Implementations/Localization/Ratings/us.csv diff --git a/Emby.Server.Implementations/Localization/TextLocalizer.cs b/Emby.Server.Implementations/Localization/TextLocalizer.cs deleted file mode 100644 index 96591e5e6..000000000 --- a/Emby.Server.Implementations/Localization/TextLocalizer.cs +++ /dev/null @@ -1,63 +0,0 @@ -using System; -using System.Globalization; -using System.Linq; -using System.Text; -using System.Text.RegularExpressions; - -namespace Emby.Server.Implementations.Localization -{ - public class TextLocalizer : ITextLocalizer - { - public string RemoveDiacritics(string text) - { - if (text == null) - { - throw new ArgumentNullException(nameof(text)); - } - - var chars = Normalize(text, NormalizationForm.FormD) - .Where(ch => CharUnicodeInfo.GetUnicodeCategory(ch) != UnicodeCategory.NonSpacingMark); - - return Normalize(string.Concat(chars), NormalizationForm.FormC); - } - - private static string Normalize(string text, NormalizationForm form, bool stripStringOnFailure = true) - { - if (stripStringOnFailure) - { - try - { - return text.Normalize(form); - } - catch (ArgumentException) - { - // will throw if input contains invalid unicode chars - // https://mnaoumov.wordpress.com/2014/06/14/stripping-invalid-characters-from-utf-16-strings/ - text = StripInvalidUnicodeCharacters(text); - return Normalize(text, form, false); - } - } - - try - { - return text.Normalize(form); - } - catch (ArgumentException) - { - // if it still fails, return the original text - return text; - } - } - - private static string StripInvalidUnicodeCharacters(string str) - { - var invalidCharactersRegex = new Regex("([\ud800-\udbff](?![\udc00-\udfff]))|((?<![\ud800-\udbff])[\udc00-\udfff])"); - return invalidCharactersRegex.Replace(str, ""); - } - - public string NormalizeFormKD(string text) - { - return text.Normalize(NormalizationForm.FormKD); - } - } -} 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/MediaEncoder/EncodingManager.cs b/Emby.Server.Implementations/MediaEncoder/EncodingManager.cs index 0575ff553..e68046f6d 100644 --- a/Emby.Server.Implementations/MediaEncoder/EncodingManager.cs +++ b/Emby.Server.Implementations/MediaEncoder/EncodingManager.cs @@ -141,12 +141,12 @@ namespace Emby.Server.Implementations.MediaEncoder var inputPath = MediaEncoderHelpers.GetInputArgument(_fileSystem, video.Path, protocol, null, Array.Empty<string>()); - _fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(path)); + Directory.CreateDirectory(Path.GetDirectoryName(path)); var container = video.Container; var tempFile = await _encoder.ExtractVideoImage(inputPath, container, protocol, video.GetDefaultVideoStream(), video.Video3DFormat, time, cancellationToken).ConfigureAwait(false); - _fileSystem.CopyFile(tempFile, path, true); + File.Copy(tempFile, path, true); try { 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/Playlists/PlaylistManager.cs b/Emby.Server.Implementations/Playlists/PlaylistManager.cs index 17f445708..29836e0bf 100644 --- a/Emby.Server.Implementations/Playlists/PlaylistManager.cs +++ b/Emby.Server.Implementations/Playlists/PlaylistManager.cs @@ -119,7 +119,7 @@ namespace Emby.Server.Implementations.Playlists try { - _fileSystem.CreateDirectory(path); + Directory.CreateDirectory(path); var playlist = new Playlist { @@ -164,7 +164,7 @@ namespace Emby.Server.Implementations.Playlists private string GetTargetPath(string path) { - while (_fileSystem.DirectoryExists(path)) + while (Directory.Exists(path)) { path += "1"; } @@ -340,7 +340,8 @@ namespace Emby.Server.Implementations.Playlists playlist.PlaylistEntries.Add(entry); } - _fileSystem.WriteAllText(playlistPath, new WplContent().ToText(playlist)); + string text = new WplContent().ToText(playlist); + File.WriteAllText(playlistPath, text); } if (string.Equals(".zpl", extension, StringComparison.OrdinalIgnoreCase)) { @@ -373,7 +374,8 @@ namespace Emby.Server.Implementations.Playlists playlist.PlaylistEntries.Add(entry); } - _fileSystem.WriteAllText(playlistPath, new ZplContent().ToText(playlist)); + string text = new ZplContent().ToText(playlist); + File.WriteAllText(playlistPath, text); } if (string.Equals(".m3u", extension, StringComparison.OrdinalIgnoreCase)) { @@ -401,7 +403,8 @@ namespace Emby.Server.Implementations.Playlists playlist.PlaylistEntries.Add(entry); } - _fileSystem.WriteAllText(playlistPath, new M3uContent().ToText(playlist)); + string text = new M3uContent().ToText(playlist); + File.WriteAllText(playlistPath, text); } if (string.Equals(".m3u8", extension, StringComparison.OrdinalIgnoreCase)) { @@ -429,7 +432,8 @@ namespace Emby.Server.Implementations.Playlists playlist.PlaylistEntries.Add(entry); } - _fileSystem.WriteAllText(playlistPath, new M3u8Content().ToText(playlist)); + string text = new M3u8Content().ToText(playlist); + File.WriteAllText(playlistPath, text); } if (string.Equals(".pls", extension, StringComparison.OrdinalIgnoreCase)) { @@ -449,13 +453,14 @@ namespace Emby.Server.Implementations.Playlists playlist.PlaylistEntries.Add(entry); } - _fileSystem.WriteAllText(playlistPath, new PlsContent().ToText(playlist)); + string text = new PlsContent().ToText(playlist); + File.WriteAllText(playlistPath, text); } } private string NormalizeItemPath(string playlistPath, string itemPath) { - return MakeRelativePath(_fileSystem.GetDirectoryName(playlistPath), itemPath); + return MakeRelativePath(Path.GetDirectoryName(playlistPath), itemPath); } private static string MakeRelativePath(string folderPath, string fileAbsolutePath) diff --git a/Emby.Server.Implementations/ResourceFileManager.cs b/Emby.Server.Implementations/ResourceFileManager.cs index 6acc7e1d1..890d848f4 100644 --- a/Emby.Server.Implementations/ResourceFileManager.cs +++ b/Emby.Server.Implementations/ResourceFileManager.cs @@ -37,16 +37,16 @@ namespace Emby.Server.Implementations public string ReadAllText(string basePath, string virtualPath) { - return _fileSystem.ReadAllText(GetResourcePath(basePath, virtualPath)); + return File.ReadAllText(GetResourcePath(basePath, virtualPath)); } private string GetResourcePath(string basePath, string virtualPath) { - var fullPath = Path.Combine(basePath, virtualPath.Replace('/', _fileSystem.DirectorySeparatorChar)); + var fullPath = Path.Combine(basePath, virtualPath.Replace('/', Path.DirectorySeparatorChar)); try { - fullPath = _fileSystem.GetFullPath(fullPath); + fullPath = Path.GetFullPath(fullPath); } catch (Exception ex) { diff --git a/Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs b/Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs index 93a9a0d81..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; @@ -129,21 +128,16 @@ namespace Emby.Server.Implementations.ScheduledTasks { if (_lastExecutionResult == null && !_readFromFile) { - try + if (File.Exists(path)) { - _lastExecutionResult = JsonSerializer.DeserializeFromFile<TaskResult>(path); - } - catch (DirectoryNotFoundException) - { - // File doesn't exist. No biggie - } - catch (FileNotFoundException) - { - // File doesn't exist. No biggie - } - catch (Exception ex) - { - Logger.LogError(ex, "Error deserializing {path}", path); + try + { + _lastExecutionResult = JsonSerializer.DeserializeFromFile<TaskResult>(path); + } + catch (Exception ex) + { + Logger.LogError(ex, "Error deserializing {File}", path); + } } _readFromFile = true; } @@ -156,7 +150,7 @@ namespace Emby.Server.Implementations.ScheduledTasks _lastExecutionResult = value; var path = GetHistoryFilePath(); - _fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(path)); + Directory.CreateDirectory(Path.GetDirectoryName(path)); lock (_lastExecutionResultSyncLock) { @@ -532,28 +526,15 @@ namespace Emby.Server.Implementations.ScheduledTasks private TaskTriggerInfo[] LoadTriggerSettings() { - try + string path = GetConfigurationFilePath(); + TaskTriggerInfo[] list = null; + if (File.Exists(path)) { - var list = JsonSerializer.DeserializeFromFile<IEnumerable<TaskTriggerInfo>>(GetConfigurationFilePath()); - - if (list != null) - { - return list.ToArray(); - } - } - catch (FileNotFoundException) - { - // File doesn't exist. No biggie. Return defaults. - } - catch (DirectoryNotFoundException) - { - // File doesn't exist. No biggie. Return defaults. + list = JsonSerializer.DeserializeFromFile<TaskTriggerInfo[]>(path); } - catch - { - } - return GetDefaultTriggers(); + // Return defaults if file doesn't exist. + return list ?? GetDefaultTriggers(); } private TaskTriggerInfo[] GetDefaultTriggers() @@ -583,7 +564,7 @@ namespace Emby.Server.Implementations.ScheduledTasks { var path = GetConfigurationFilePath(); - _fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(path)); + Directory.CreateDirectory(Path.GetDirectoryName(path)); JsonSerializer.SerializeToFile(triggers, path); } diff --git a/Emby.Server.Implementations/ScheduledTasks/TaskManager.cs b/Emby.Server.Implementations/ScheduledTasks/TaskManager.cs index d74c8fe8c..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 = _fileSystem.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 0ae7ae96c..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> @@ -101,17 +99,20 @@ namespace Emby.Server.Implementations.ScheduledTasks List<string> previouslyFailedImages; - try - { - previouslyFailedImages = _fileSystem.ReadAllText(failHistoryPath) - .Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries) - .ToList(); - } - catch (FileNotFoundException) + if (File.Exists(failHistoryPath)) { - previouslyFailedImages = new List<string>(); + try + { + previouslyFailedImages = File.ReadAllText(failHistoryPath) + .Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries) + .ToList(); + } + catch (IOException) + { + previouslyFailedImages = new List<string>(); + } } - catch (IOException) + else { previouslyFailedImages = new List<string>(); } @@ -136,11 +137,12 @@ namespace Emby.Server.Implementations.ScheduledTasks { previouslyFailedImages.Add(key); - var parentPath = _fileSystem.GetDirectoryName(failHistoryPath); + var parentPath = Path.GetDirectoryName(failHistoryPath); - _fileSystem.CreateDirectory(parentPath); + Directory.CreateDirectory(parentPath); - _fileSystem.WriteAllText(failHistoryPath, string.Join("|", previouslyFailedImages.ToArray())); + string text = string.Join("|", previouslyFailedImages); + File.WriteAllText(failHistoryPath, text); } numComplete++; @@ -157,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 2590f455c..6ec83b5c0 100644 --- a/Emby.Server.Implementations/ScheduledTasks/Tasks/DeleteCacheFileTask.cs +++ b/Emby.Server.Implementations/ScheduledTasks/Tasks/DeleteCacheFileTask.cs @@ -128,7 +128,7 @@ namespace Emby.Server.Implementations.ScheduledTasks.Tasks { try { - _fileSystem.DeleteDirectory(directory, false); + Directory.Delete(directory, false); } catch (UnauthorizedAccessException ex) { @@ -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/Serialization/XmlSerializer.cs b/Emby.Server.Implementations/Serialization/XmlSerializer.cs index f7428eff7..6400ec16e 100644 --- a/Emby.Server.Implementations/Serialization/XmlSerializer.cs +++ b/Emby.Server.Implementations/Serialization/XmlSerializer.cs @@ -107,7 +107,7 @@ namespace Emby.Server.Implementations.Serialization public object DeserializeFromFile(Type type, string file) { _logger.LogDebug("Deserializing file {0}", file); - using (var stream = _fileSystem.OpenRead(file)) + using (var stream = File.OpenRead(file)) { return DeserializeFromStream(type, stream); } 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 44377a897..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) @@ -555,7 +551,7 @@ namespace Emby.Server.Implementations.Updates var packageChecksum = string.IsNullOrWhiteSpace(package.checksum) ? Guid.Empty : new Guid(package.checksum); if (!packageChecksum.Equals(Guid.Empty)) // support for legacy uploads for now { - using (var stream = _fileSystem.OpenRead(tempFile)) + using (var stream = File.OpenRead(tempFile)) { var check = Guid.Parse(BitConverter.ToString(_cryptographyProvider.ComputeMD5(stream)).Replace("-", string.Empty)); if (check != packageChecksum) @@ -570,12 +566,12 @@ namespace Emby.Server.Implementations.Updates // Success - move it to the real target try { - _fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(target)); - _fileSystem.CopyFile(tempFile, target, true); + Directory.CreateDirectory(Path.GetDirectoryName(target)); + File.Copy(tempFile, target, true); //If it is an archive - write out a version file so we know what it is if (isArchive) { - _fileSystem.WriteAllText(target + ".ver", package.versionStr); + File.WriteAllText(target + ".ver", package.versionStr); } } catch (IOException ex) @@ -611,7 +607,7 @@ namespace Emby.Server.Implementations.Updates _logger.LogInformation("Deleting plugin file {0}", path); // Make this case-insensitive to account for possible incorrect assembly naming - var file = _fileSystem.GetFilePaths(_fileSystem.GetDirectoryName(path)) + var file = _fileSystem.GetFilePaths(Path.GetDirectoryName(path)) .FirstOrDefault(i => string.Equals(i, path, StringComparison.OrdinalIgnoreCase)); if (!string.IsNullOrWhiteSpace(file)) 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/Properties/AssemblyInfo.cs b/Jellyfin.Drawing.Skia/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..ea1c457f6 --- /dev/null +++ b/Jellyfin.Drawing.Skia/Properties/AssemblyInfo.cs @@ -0,0 +1,21 @@ +using System.Reflection; +using System.Resources; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("Jellyfin.Drawing.Skia")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("Jellyfin Project")] +[assembly: AssemblyProduct("Jellyfin: The Free Software Media System")] +[assembly: AssemblyCopyright("Copyright © 2019 Jellyfin Contributors. Code released under the GNU General Public License Version 2")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] +[assembly: NeutralResourcesLanguage("en")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] diff --git a/Jellyfin.Drawing.Skia/SkiaEncoder.cs b/Jellyfin.Drawing.Skia/SkiaEncoder.cs index a06477d3e..f1b886ec6 100644 --- a/Jellyfin.Drawing.Skia/SkiaEncoder.cs +++ b/Jellyfin.Drawing.Skia/SkiaEncoder.cs @@ -219,8 +219,8 @@ namespace Jellyfin.Drawing.Skia var tempPath = Path.Combine(_appPaths.TempDirectory, Guid.NewGuid() + Path.GetExtension(path) ?? string.Empty); - fileSystem.CreateDirectory(fileSystem.GetDirectoryName(tempPath)); - fileSystem.CopyFile(path, tempPath, true); + Directory.CreateDirectory(Path.GetDirectoryName(tempPath)); + File.Copy(path, tempPath, true); return tempPath; } @@ -257,7 +257,7 @@ namespace Jellyfin.Drawing.Skia internal static SKBitmap Decode(string path, bool forceCleanBitmap, IFileSystem fileSystem, ImageOrientation? orientation, out SKEncodedOrigin origin) { - if (!fileSystem.FileExists(path)) + if (!File.Exists(path)) { throw new FileNotFoundException("File not found", path); } @@ -532,7 +532,7 @@ namespace Jellyfin.Drawing.Skia // If all we're doing is resizing then we can stop now if (!hasBackgroundColor && !hasForegroundColor && blur == 0 && !hasIndicator) { - _fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(outputPath)); + Directory.CreateDirectory(Path.GetDirectoryName(outputPath)); using (var outputStream = new SKFileWStream(outputPath)) using (var pixmap = new SKPixmap(new SKImageInfo(width, height), resizedBitmap.GetPixels())) { @@ -584,7 +584,7 @@ namespace Jellyfin.Drawing.Skia DrawIndicator(canvas, width, height, options); } - _fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(outputPath)); + Directory.CreateDirectory(Path.GetDirectoryName(outputPath)); using (var outputStream = new SKFileWStream(outputPath)) { using (var pixmap = new SKPixmap(new SKImageInfo(width, height), saveBitmap.GetPixels())) 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 4dfe83441..7826fde35 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(); @@ -99,7 +114,7 @@ namespace Jellyfin.Server new NullImageEncoder(), new NetworkManager(_loggerFactory, environmentInfo))) { - appHost.Init(); + await appHost.Init(); appHost.ImageProcessor.ImageEncoder = GetImageEncoder(fileSystem, appPaths, appHost.LocalizationManager); @@ -129,9 +144,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 { @@ -167,9 +182,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 { @@ -183,12 +198,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 { @@ -204,10 +244,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 { @@ -267,7 +307,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) { @@ -311,11 +351,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)) { @@ -324,9 +364,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 cfd37667a..88654a42c 100644 --- a/MediaBrowser.Api/ApiEntryPoint.cs +++ b/MediaBrowser.Api/ApiEntryPoint.cs @@ -463,7 +463,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> @@ -473,9 +473,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)) { @@ -493,7 +493,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>(); @@ -506,13 +506,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> @@ -521,7 +526,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(); @@ -578,7 +583,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)) @@ -589,12 +594,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) { @@ -624,7 +629,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) { @@ -647,12 +652,11 @@ namespace MediaBrowser.Api /// <param name="outputFilePath">The output file path.</param> private void DeleteHlsPartialStreamFiles(string outputFilePath) { - var directory = _fileSystem.GetDirectoryName(outputFilePath); + var directory = Path.GetDirectoryName(outputFilePath); 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/EnvironmentService.cs b/MediaBrowser.Api/EnvironmentService.cs index 0fc20749f..bdd7a8f8f 100644 --- a/MediaBrowser.Api/EnvironmentService.cs +++ b/MediaBrowser.Api/EnvironmentService.cs @@ -137,14 +137,14 @@ namespace MediaBrowser.Api { if (request.IsFile.Value) { - if (!_fileSystem.FileExists(request.Path)) + if (!File.Exists(request.Path)) { throw new FileNotFoundException("File not found", request.Path); } } else { - if (!_fileSystem.DirectoryExists(request.Path)) + if (!Directory.Exists(request.Path)) { throw new FileNotFoundException("File not found", request.Path); } @@ -153,7 +153,7 @@ namespace MediaBrowser.Api else { - if (!_fileSystem.FileExists(request.Path) && !_fileSystem.DirectoryExists(request.Path)) + if (!File.Exists(request.Path) && !Directory.Exists(request.Path)) { throw new FileNotFoundException("Path not found", request.Path); } @@ -169,7 +169,7 @@ namespace MediaBrowser.Api { var file = Path.Combine(path, Guid.NewGuid().ToString()); - _fileSystem.WriteAllText(file, string.Empty); + File.WriteAllText(file, string.Empty); _fileSystem.DeleteFile(file); } @@ -303,7 +303,7 @@ namespace MediaBrowser.Api public object Get(GetParentPath request) { - var parent = _fileSystem.GetDirectoryName(request.Path); + var parent = Path.GetDirectoryName(request.Path); if (string.IsNullOrEmpty(parent)) { 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 61efae46d..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(); @@ -158,7 +158,7 @@ namespace MediaBrowser.Api.Images private string GetThemeName(string path, string rootImagePath) { - var parentName = _fileSystem.GetDirectoryName(path); + var parentName = Path.GetDirectoryName(path); if (string.Equals(parentName, rootImagePath, StringComparison.OrdinalIgnoreCase)) { @@ -185,7 +185,7 @@ namespace MediaBrowser.Api.Images var paths = BaseItem.SupportedImageExtensions.Select(i => Path.Combine(_appPaths.GeneralPath, request.Name, filename + i)).ToList(); - var path = paths.FirstOrDefault(_fileSystem.FileExists) ?? paths.FirstOrDefault(); + var path = paths.FirstOrDefault(File.Exists) ?? paths.FirstOrDefault(); return _resultFactory.GetStaticFileResult(Request, path); } @@ -199,11 +199,11 @@ namespace MediaBrowser.Api.Images { var themeFolder = Path.Combine(_appPaths.RatingsPath, request.Theme); - if (_fileSystem.DirectoryExists(themeFolder)) + if (Directory.Exists(themeFolder)) { var path = BaseItem.SupportedImageExtensions .Select(i => Path.Combine(themeFolder, request.Name + i)) - .FirstOrDefault(_fileSystem.FileExists); + .FirstOrDefault(File.Exists); if (!string.IsNullOrEmpty(path)) { @@ -213,14 +213,14 @@ namespace MediaBrowser.Api.Images var allFolder = Path.Combine(_appPaths.RatingsPath, "all"); - if (_fileSystem.DirectoryExists(allFolder)) + if (Directory.Exists(allFolder)) { // Avoid implicitly captured closure var currentRequest = request; var path = BaseItem.SupportedImageExtensions .Select(i => Path.Combine(allFolder, currentRequest.Name + i)) - .FirstOrDefault(_fileSystem.FileExists); + .FirstOrDefault(File.Exists); if (!string.IsNullOrEmpty(path)) { @@ -240,10 +240,10 @@ namespace MediaBrowser.Api.Images { var themeFolder = Path.Combine(_appPaths.MediaInfoImagesPath, request.Theme); - if (_fileSystem.DirectoryExists(themeFolder)) + if (Directory.Exists(themeFolder)) { var path = BaseItem.SupportedImageExtensions.Select(i => Path.Combine(themeFolder, request.Name + i)) - .FirstOrDefault(_fileSystem.FileExists); + .FirstOrDefault(File.Exists); if (!string.IsNullOrEmpty(path)) { @@ -253,13 +253,13 @@ namespace MediaBrowser.Api.Images var allFolder = Path.Combine(_appPaths.MediaInfoImagesPath, "all"); - if (_fileSystem.DirectoryExists(allFolder)) + if (Directory.Exists(allFolder)) { // Avoid implicitly captured closure var currentRequest = request; var path = BaseItem.SupportedImageExtensions.Select(i => Path.Combine(allFolder, currentRequest.Name + i)) - .FirstOrDefault(_fileSystem.FileExists); + .FirstOrDefault(File.Exists); if (!string.IsNullOrEmpty(path)) { 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/Images/RemoteImageService.cs b/MediaBrowser.Api/Images/RemoteImageService.cs index 24c8ed835..24d4751c5 100644 --- a/MediaBrowser.Api/Images/RemoteImageService.cs +++ b/MediaBrowser.Api/Images/RemoteImageService.cs @@ -220,9 +220,9 @@ namespace MediaBrowser.Api.Images try { - contentPath = _fileSystem.ReadAllText(pointerCachePath); + contentPath = File.ReadAllText(pointerCachePath); - if (_fileSystem.FileExists(contentPath)) + if (File.Exists(contentPath)) { return await ResultFactory.GetStaticFileResult(Request, contentPath).ConfigureAwait(false); } @@ -239,7 +239,7 @@ namespace MediaBrowser.Api.Images await DownloadImage(request.ImageUrl, urlHash, pointerCachePath).ConfigureAwait(false); // Read the pointer file again - contentPath = _fileSystem.ReadAllText(pointerCachePath); + contentPath = File.ReadAllText(pointerCachePath); return await ResultFactory.GetStaticFileResult(Request, contentPath).ConfigureAwait(false); } @@ -264,7 +264,7 @@ namespace MediaBrowser.Api.Images var fullCachePath = GetFullCachePath(urlHash + "." + ext); - _fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(fullCachePath)); + Directory.CreateDirectory(Path.GetDirectoryName(fullCachePath)); using (var stream = result.Content) { using (var filestream = _fileSystem.GetFileStream(fullCachePath, FileOpenMode.Create, FileAccessMode.Write, FileShareMode.Read, true)) @@ -273,8 +273,8 @@ namespace MediaBrowser.Api.Images } } - _fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(pointerCachePath)); - _fileSystem.WriteAllText(pointerCachePath, fullCachePath); + Directory.CreateDirectory(Path.GetDirectoryName(pointerCachePath)); + File.WriteAllText(pointerCachePath, fullCachePath); } } diff --git a/MediaBrowser.Api/ItemLookupService.cs b/MediaBrowser.Api/ItemLookupService.cs index 10d882e08..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); @@ -265,9 +252,9 @@ namespace MediaBrowser.Api try { - contentPath = _fileSystem.ReadAllText(pointerCachePath); + contentPath = File.ReadAllText(pointerCachePath); - if (_fileSystem.FileExists(contentPath)) + if (File.Exists(contentPath)) { return await ResultFactory.GetStaticFileResult(Request, contentPath).ConfigureAwait(false); } @@ -284,7 +271,7 @@ namespace MediaBrowser.Api await DownloadImage(request.ProviderName, request.ImageUrl, urlHash, pointerCachePath).ConfigureAwait(false); // Read the pointer file again - contentPath = _fileSystem.ReadAllText(pointerCachePath); + contentPath = File.ReadAllText(pointerCachePath); return await ResultFactory.GetStaticFileResult(Request, contentPath).ConfigureAwait(false); } @@ -305,7 +292,7 @@ namespace MediaBrowser.Api var fullCachePath = GetFullCachePath(urlHash + "." + ext); - _fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(fullCachePath)); + Directory.CreateDirectory(Path.GetDirectoryName(fullCachePath)); using (var stream = result.Content) { using (var filestream = _fileSystem.GetFileStream(fullCachePath, FileOpenMode.Create, FileAccessMode.Write, FileShareMode.Read, true)) @@ -314,8 +301,8 @@ namespace MediaBrowser.Api } } - _fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(pointerCachePath)); - _fileSystem.WriteAllText(pointerCachePath, fullCachePath); + Directory.CreateDirectory(Path.GetDirectoryName(pointerCachePath)); + File.WriteAllText(pointerCachePath, fullCachePath); } /// <summary> diff --git a/MediaBrowser.Api/ItemUpdateService.cs b/MediaBrowser.Api/ItemUpdateService.cs index c386b25b8..825732888 100644 --- a/MediaBrowser.Api/ItemUpdateService.cs +++ b/MediaBrowser.Api/ItemUpdateService.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using System.Linq; using System.Threading; +using System.Threading.Tasks; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Audio; @@ -60,15 +61,15 @@ namespace MediaBrowser.Api _fileSystem = fileSystem; } - public object Get(GetMetadataEditorInfo request) + public async Task<object> Get(GetMetadataEditorInfo request) { var item = _libraryManager.GetItemById(request.ItemId); var info = new MetadataEditorInfo { - ParentalRatingOptions = _localizationManager.GetParentalRatings(), + ParentalRatingOptions = _localizationManager.GetParentalRatings().ToArray(), ExternalIdInfos = _providerManager.GetExternalIdInfos(item).ToArray(), - Countries = _localizationManager.GetCountries(), + Countries = await _localizationManager.GetCountries(), Cultures = _localizationManager.GetCultures() }; @@ -154,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/Library/LibraryStructureService.cs b/MediaBrowser.Api/Library/LibraryStructureService.cs index 3be6b29dd..d6bcf7878 100644 --- a/MediaBrowser.Api/Library/LibraryStructureService.cs +++ b/MediaBrowser.Api/Library/LibraryStructureService.cs @@ -255,12 +255,12 @@ namespace MediaBrowser.Api.Library var currentPath = Path.Combine(rootFolderPath, request.Name); var newPath = Path.Combine(rootFolderPath, request.NewName); - if (!_fileSystem.DirectoryExists(currentPath)) + if (!Directory.Exists(currentPath)) { throw new FileNotFoundException("The media collection does not exist"); } - if (!string.Equals(currentPath, newPath, StringComparison.OrdinalIgnoreCase) && _fileSystem.DirectoryExists(newPath)) + if (!string.Equals(currentPath, newPath, StringComparison.OrdinalIgnoreCase) && Directory.Exists(newPath)) { throw new ArgumentException("Media library already exists at " + newPath + "."); } @@ -273,11 +273,11 @@ namespace MediaBrowser.Api.Library if (string.Equals(currentPath, newPath, StringComparison.OrdinalIgnoreCase)) { var tempPath = Path.Combine(rootFolderPath, Guid.NewGuid().ToString("N")); - _fileSystem.MoveDirectory(currentPath, tempPath); + Directory.Move(currentPath, tempPath); currentPath = tempPath; } - _fileSystem.MoveDirectory(currentPath, newPath); + Directory.Move(currentPath, newPath); } finally { 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 bb525adc7..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; @@ -192,7 +192,7 @@ namespace MediaBrowser.Api.Playback CancellationTokenSource cancellationTokenSource, string workingDirectory = null) { - FileSystem.CreateDirectory(FileSystem.GetDirectoryName(outputPath)); + Directory.CreateDirectory(Path.GetDirectoryName(outputPath)); await AcquireResources(state, cancellationTokenSource).ConfigureAwait(false); @@ -258,7 +258,7 @@ namespace MediaBrowser.Api.Playback } var logFilePath = Path.Combine(ServerConfigurationManager.ApplicationPaths.LogDirectoryPath, logFilePrefix + "-" + Guid.NewGuid() + ".txt"); - FileSystem.CreateDirectory(FileSystem.GetDirectoryName(logFilePath)); + 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. state.LogFileStream = FileSystem.GetFileStream(logFilePath, FileOpenMode.Create, FileAccessMode.Write, FileShareMode.Read, true); @@ -290,7 +290,7 @@ namespace MediaBrowser.Api.Playback new JobLogger(Logger).StartStreamingLog(state, process.StandardError.BaseStream, state.LogFileStream); // Wait for the file to exist before proceeeding - while (!FileSystem.FileExists(state.WaitForPath ?? outputPath) && !transcodingJob.HasExited) + while (!File.Exists(state.WaitForPath ?? outputPath) && !transcodingJob.HasExited) { await Task.Delay(100, cancellationTokenSource.Token).ConfigureAwait(false); } diff --git a/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs b/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs index 1e90d03b0..08a2183f8 100644 --- a/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs +++ b/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs @@ -83,13 +83,13 @@ namespace MediaBrowser.Api.Playback.Hls TranscodingJob job = null; var playlist = state.OutputFilePath; - if (!FileSystem.FileExists(playlist)) + if (!File.Exists(playlist)) { var transcodingLock = ApiEntryPoint.Instance.GetTranscodingLock(playlist); await transcodingLock.WaitAsync(cancellationTokenSource.Token).ConfigureAwait(false); try { - if (!FileSystem.FileExists(playlist)) + if (!File.Exists(playlist)) { // If the playlist doesn't already exist, startup ffmpeg try @@ -264,7 +264,7 @@ namespace MediaBrowser.Api.Playback.Hls var useGenericSegmenter = true; if (useGenericSegmenter) { - var outputTsArg = Path.Combine(FileSystem.GetDirectoryName(outputPath), Path.GetFileNameWithoutExtension(outputPath)) + "%d" + GetSegmentFileExtension(state.Request); + var outputTsArg = Path.Combine(Path.GetDirectoryName(outputPath), Path.GetFileNameWithoutExtension(outputPath)) + "%d" + GetSegmentFileExtension(state.Request); var timeDeltaParam = string.Empty; diff --git a/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs b/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs index b3099e17e..30696ec97 100644 --- a/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs +++ b/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs @@ -164,7 +164,7 @@ namespace MediaBrowser.Api.Playback.Hls TranscodingJob job = null; - if (FileSystem.FileExists(segmentPath)) + if (File.Exists(segmentPath)) { job = ApiEntryPoint.Instance.OnTranscodeBeginRequest(playlistPath, TranscodingJobType); return await GetSegmentResult(state, playlistPath, segmentPath, segmentExtension, requestedIndex, job, cancellationToken).ConfigureAwait(false); @@ -177,7 +177,7 @@ namespace MediaBrowser.Api.Playback.Hls try { - if (FileSystem.FileExists(segmentPath)) + if (File.Exists(segmentPath)) { job = ApiEntryPoint.Instance.OnTranscodeBeginRequest(playlistPath, TranscodingJobType); transcodingLock.Release(); @@ -381,7 +381,7 @@ namespace MediaBrowser.Api.Playback.Hls private static FileSystemMetadata GetLastTranscodingFile(string playlist, string segmentExtension, IFileSystem fileSystem) { - var folder = fileSystem.GetDirectoryName(playlist); + var folder = Path.GetDirectoryName(playlist); var filePrefix = Path.GetFileNameWithoutExtension(playlist) ?? string.Empty; @@ -418,7 +418,7 @@ namespace MediaBrowser.Api.Playback.Hls private string GetSegmentPath(StreamState state, string playlist, int index) { - var folder = FileSystem.GetDirectoryName(playlist); + var folder = Path.GetDirectoryName(playlist); var filename = Path.GetFileNameWithoutExtension(playlist); @@ -433,7 +433,7 @@ namespace MediaBrowser.Api.Playback.Hls TranscodingJob transcodingJob, CancellationToken cancellationToken) { - var segmentFileExists = FileSystem.FileExists(segmentPath); + var segmentFileExists = File.Exists(segmentPath); // If all transcoding has completed, just return immediately if (transcodingJob != null && transcodingJob.HasExited && segmentFileExists) @@ -458,14 +458,14 @@ namespace MediaBrowser.Api.Playback.Hls { try { - var text = FileSystem.ReadAllText(playlistPath, Encoding.UTF8); + var text = File.ReadAllText(playlistPath, Encoding.UTF8); // If it appears in the playlist, it's done if (text.IndexOf(segmentFilename, StringComparison.OrdinalIgnoreCase) != -1) { if (!segmentFileExists) { - segmentFileExists = FileSystem.FileExists(segmentPath); + segmentFileExists = File.Exists(segmentPath); } if (segmentFileExists) { @@ -932,7 +932,7 @@ namespace MediaBrowser.Api.Playback.Hls var mapArgs = state.IsOutputVideo ? EncodingHelper.GetMapArgs(state) : string.Empty; - var outputTsArg = Path.Combine(FileSystem.GetDirectoryName(outputPath), Path.GetFileNameWithoutExtension(outputPath)) + "%d" + GetSegmentFileExtension(state.Request); + var outputTsArg = Path.Combine(Path.GetDirectoryName(outputPath), Path.GetFileNameWithoutExtension(outputPath)) + "%d" + GetSegmentFileExtension(state.Request); var timeDeltaParam = string.Empty; diff --git a/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs b/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs index bb21fe5ae..621d1ff88 100644 --- a/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs +++ b/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Globalization; +using System.IO; using System.Threading; using System.Threading.Tasks; using MediaBrowser.Common.Net; @@ -153,7 +154,7 @@ namespace MediaBrowser.Api.Playback.Progressive } var outputPath = state.OutputFilePath; - var outputPathExists = FileSystem.FileExists(outputPath); + var outputPathExists = File.Exists(outputPath); var transcodingJob = ApiEntryPoint.Instance.GetTranscodingJob(outputPath, TranscodingJobType.Progressive); var isTranscodeCached = outputPathExists && transcodingJob != null; @@ -377,7 +378,7 @@ namespace MediaBrowser.Api.Playback.Progressive { TranscodingJob job; - if (!FileSystem.FileExists(outputPath)) + if (!File.Exists(outputPath)) { job = await StartFfMpeg(state, outputPath, cancellationTokenSource).ConfigureAwait(false); } diff --git a/MediaBrowser.Api/PluginService.cs b/MediaBrowser.Api/PluginService.cs index 94be45474..af61887b2 100644 --- a/MediaBrowser.Api/PluginService.cs +++ b/MediaBrowser.Api/PluginService.cs @@ -153,7 +153,11 @@ namespace MediaBrowser.Api private readonly INetworkManager _network; private readonly IDeviceManager _deviceManager; - public PluginService(IJsonSerializer jsonSerializer, IApplicationHost appHost, IInstallationManager installationManager, INetworkManager network, IDeviceManager deviceManager) + public PluginService(IJsonSerializer jsonSerializer, + IApplicationHost appHost, + IInstallationManager installationManager, + INetworkManager network, + IDeviceManager deviceManager) : base() { if (jsonSerializer == null) @@ -173,7 +177,7 @@ namespace MediaBrowser.Api /// </summary> /// <param name="request">The request.</param> /// <returns>System.Object.</returns> - public async Task<object> Get(GetRegistrationStatus request) + public object Get(GetRegistrationStatus request) { var record = new MBRegistrationRecord { @@ -187,26 +191,12 @@ namespace MediaBrowser.Api return ToOptimizedResult(record); } - //TODO this function is only kept for compatibility and should be removed once paid plugins break - public async Task<object> Get(GetRegistration request) - { - var info = new RegistrationInfo - { - ExpirationDate = DateTime.Now.AddYears(100), - IsRegistered = true, - IsTrial = false, - Name = request.Name - }; - - return ToOptimizedResult(info); - } - /// <summary> /// Gets the specified request. /// </summary> /// <param name="request">The request.</param> /// <returns>System.Object.</returns> - public async Task<object> Get(GetPlugins request) + public object Get(GetPlugins request) { var result = _appHost.Plugins.OrderBy(p => p.Name).Select(p => p.GetPluginInfo()).ToArray(); return ToOptimizedResult(result); @@ -230,7 +220,7 @@ namespace MediaBrowser.Api /// </summary> /// <param name="request">The request.</param> /// <returns>System.Object.</returns> - public async Task<object> Get(GetPluginSecurityInfo request) + public object Get(GetPluginSecurityInfo request) { var result = new PluginSecurityInfo { 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 5f137d804..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,20 +101,21 @@ 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(); user.Name = request.Name; - _userManager.UpdateUser(user); - var result = new UpdateStartupUserResult(); + _userManager.UpdateUser(user); - return result; + if (!string.IsNullOrEmpty(request.Password)) { + await _userManager.ChangePassword(user, request.Password).ConfigureAwait(false); + } } } @@ -129,11 +129,6 @@ namespace MediaBrowser.Api public class StartupUser { public string Name { get; set; } - public string ConnectUserName { get; set; } - } - - public class UpdateStartupUserResult - { - public UserLinkResult UserLinkResult { get; set; } + public string Password { 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 76f91e373..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); @@ -267,13 +267,13 @@ namespace MediaBrowser.Api.UserLibrary var session = GetSession(_sessionContext); - var dto = await UpdatePlayedStatus(user, request.Id, true, datePlayed).ConfigureAwait(false); + var dto = UpdatePlayedStatus(user, request.Id, true, datePlayed); foreach (var additionalUserInfo in session.AdditionalUsers) { var additionalUser = _userManager.GetUserById(additionalUserInfo.UserId); - await UpdatePlayedStatus(additionalUser, request.Id, true, datePlayed).ConfigureAwait(false); + UpdatePlayedStatus(additionalUser, request.Id, true, datePlayed); } return dto; @@ -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,22 +401,22 @@ 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); var session = GetSession(_sessionContext); - var dto = await UpdatePlayedStatus(user, request.Id, false, null).ConfigureAwait(false); + var dto = UpdatePlayedStatus(user, request.Id, false, null); foreach (var additionalUserInfo in session.AdditionalUsers) { var additionalUser = _userManager.GetUserById(additionalUserInfo.UserId); - await UpdatePlayedStatus(additionalUser, request.Id, false, null).ConfigureAwait(false); + UpdatePlayedStatus(additionalUser, request.Id, false, null); } return dto; @@ -432,7 +430,7 @@ namespace MediaBrowser.Api.UserLibrary /// <param name="wasPlayed">if set to <c>true</c> [was played].</param> /// <param name="datePlayed">The date played.</param> /// <returns>Task.</returns> - private async Task<UserItemDataDto> UpdatePlayedStatus(User user, string itemId, bool wasPlayed, DateTime? datePlayed) + private UserItemDataDto UpdatePlayedStatus(User user, string itemId, bool wasPlayed, DateTime? datePlayed) { var item = _libraryManager.GetItemById(itemId); 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.Common/IApplicationHost.cs b/MediaBrowser.Common/IApplicationHost.cs index 385127c54..59e3c1767 100644 --- a/MediaBrowser.Common/IApplicationHost.cs +++ b/MediaBrowser.Common/IApplicationHost.cs @@ -89,7 +89,7 @@ namespace MediaBrowser.Common /// <typeparam name="T"></typeparam> /// <param name="manageLiftime">if set to <c>true</c> [manage liftime].</param> /// <returns>IEnumerable{``0}.</returns> - IEnumerable<T> GetExports<T>(bool manageLiftime = true); + IEnumerable<T> GetExports<T>(bool manageLifetime = true); /// <summary> /// Updates the application. @@ -131,7 +131,7 @@ namespace MediaBrowser.Common /// <summary> /// Inits this instance. /// </summary> - void Init(); + Task Init(); /// <summary> /// Creates the instance. 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/Drawing/ImageHelper.cs b/MediaBrowser.Controller/Drawing/ImageHelper.cs index f88a63223..432cf8042 100644 --- a/MediaBrowser.Controller/Drawing/ImageHelper.cs +++ b/MediaBrowser.Controller/Drawing/ImageHelper.cs @@ -63,7 +63,8 @@ namespace MediaBrowser.Controller.Drawing case ImageType.Logo: return 2.58; case ImageType.Primary: - return item.GetDefaultPrimaryImageAspectRatio(); + double defaultPrimaryImageAspectRatio = item.GetDefaultPrimaryImageAspectRatio(); + return defaultPrimaryImageAspectRatio > 0 ? defaultPrimaryImageAspectRatio : 2.0 / 3; default: return 1; } diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs index 846fd9eec..72c4e3573 100644 --- a/MediaBrowser.Controller/Entities/BaseItem.cs +++ b/MediaBrowser.Controller/Entities/BaseItem.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Globalization; +using System.IO; using System.Linq; using System.Text; using System.Threading; @@ -228,7 +229,7 @@ namespace MediaBrowser.Controller.Entities return Path; } - return FileSystem.GetDirectoryName(Path); + return System.IO.Path.GetDirectoryName(Path); } } @@ -614,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 { @@ -660,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) { @@ -1518,7 +1519,7 @@ namespace MediaBrowser.Controller.Entities public virtual double GetDefaultPrimaryImageAspectRatio() { - return 2.0 / 3; + return 0; } public virtual string CreatePresentationUniqueKey() @@ -2208,7 +2209,7 @@ namespace MediaBrowser.Controller.Entities { var allFiles = ImageInfos .Where(i => i.IsLocalFile) - .Select(i => FileSystem.GetDirectoryName(i.Path)) + .Select(i => System.IO.Path.GetDirectoryName(i.Path)) .Distinct(StringComparer.OrdinalIgnoreCase) .SelectMany(i => directoryService.GetFilePaths(i)) .ToList(); @@ -2343,7 +2344,7 @@ namespace MediaBrowser.Controller.Entities var newImagePaths = images.Select(i => i.FullName).ToList(); var deleted = existingImages - .Where(i => i.IsLocalFile && !newImagePaths.Contains(i.Path, StringComparer.OrdinalIgnoreCase) && !FileSystem.FileExists(i.Path)) + .Where(i => i.IsLocalFile && !newImagePaths.Contains(i.Path, StringComparer.OrdinalIgnoreCase) && !File.Exists(i.Path)) .ToList(); if (deleted.Count > 0) @@ -2396,7 +2397,7 @@ namespace MediaBrowser.Controller.Entities var extensions = new List<string> { ".nfo", ".xml", ".srt", ".vtt", ".sub", ".idx", ".txt", ".edl", ".bif", ".smi", ".ttml" }; extensions.AddRange(SupportedImageExtensions); - return FileSystem.GetFiles(FileSystem.GetDirectoryName(Path), extensions.ToArray(), false, false) + return FileSystem.GetFiles(System.IO.Path.GetDirectoryName(Path), extensions.ToArray(), false, false) .Where(i => System.IO.Path.GetFileNameWithoutExtension(i.FullName).StartsWith(filename, StringComparison.OrdinalIgnoreCase)) .ToList(); } @@ -2508,7 +2509,7 @@ namespace MediaBrowser.Controller.Entities if (string.IsNullOrEmpty(Name) && !string.IsNullOrEmpty(Path)) { - Name = FileSystem.GetFileNameWithoutExtension(Path); + Name = System.IO.Path.GetFileNameWithoutExtension(Path); hasChanges = true; } 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 82a4531ff..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 = FileSystem.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/Season.cs b/MediaBrowser.Controller/Entities/TV/Season.cs index b40009e0c..5d7c260d1 100644 --- a/MediaBrowser.Controller/Entities/TV/Season.cs +++ b/MediaBrowser.Controller/Entities/TV/Season.cs @@ -97,7 +97,7 @@ namespace MediaBrowser.Controller.Entities.TV return series.Path; } - return FileSystem.GetDirectoryName(Path); + return System.IO.Path.GetDirectoryName(Path); } } 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 10fe096a4..0d5f508dd 100644 --- a/MediaBrowser.Controller/Entities/User.cs +++ b/MediaBrowser.Controller/Entities/User.cs @@ -1,10 +1,10 @@ using System; +using System.IO; using System.Threading; 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; @@ -32,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 { @@ -167,18 +162,18 @@ namespace MediaBrowser.Controller.Entities var oldConfigurationDirectory = ConfigurationDirectoryPath; // Exceptions will be thrown if these paths already exist - if (FileSystem.DirectoryExists(newConfigDirectory)) + if (Directory.Exists(newConfigDirectory)) { - FileSystem.DeleteDirectory(newConfigDirectory, true); + Directory.Delete(newConfigDirectory, true); } - if (FileSystem.DirectoryExists(oldConfigurationDirectory)) + if (Directory.Exists(oldConfigurationDirectory)) { - FileSystem.MoveDirectory(oldConfigurationDirectory, newConfigDirectory); + Directory.Move(oldConfigurationDirectory, newConfigDirectory); } else { - FileSystem.CreateDirectory(newConfigDirectory); + Directory.CreateDirectory(newConfigDirectory); } } 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 dd4440c3b..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) @@ -345,7 +345,7 @@ namespace MediaBrowser.Controller.Entities { if (IsStacked) { - return FileSystem.GetDirectoryName(Path); + return System.IO.Path.GetDirectoryName(Path); } if (!IsPlaceHolder) diff --git a/MediaBrowser.Controller/Extensions/StringExtensions.cs b/MediaBrowser.Controller/Extensions/StringExtensions.cs index 73f529fc0..b1aaf6534 100644 --- a/MediaBrowser.Controller/Extensions/StringExtensions.cs +++ b/MediaBrowser.Controller/Extensions/StringExtensions.cs @@ -1,4 +1,8 @@ -using MediaBrowser.Model.Globalization; +using System; +using System.Globalization; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; namespace MediaBrowser.Controller.Extensions { @@ -7,11 +11,45 @@ namespace MediaBrowser.Controller.Extensions /// </summary> public static class StringExtensions { - public static ILocalizationManager LocalizationManager { get; set; } - public static string RemoveDiacritics(this string text) { - return LocalizationManager.RemoveDiacritics(text); + if (text == null) + { + throw new ArgumentNullException(nameof(text)); + } + + var chars = Normalize(text, NormalizationForm.FormD) + .Where(ch => CharUnicodeInfo.GetUnicodeCategory(ch) != UnicodeCategory.NonSpacingMark); + + return Normalize(string.Concat(chars), NormalizationForm.FormC); + } + + private static string Normalize(string text, NormalizationForm form, bool stripStringOnFailure = true) + { + if (stripStringOnFailure) + { + try + { + return text.Normalize(form); + } + catch (ArgumentException) + { + // will throw if input contains invalid unicode chars + // https://mnaoumov.wordpress.com/2014/06/14/stripping-invalid-characters-from-utf-16-strings/ + text = Regex.Replace(text, "([\ud800-\udbff](?![\udc00-\udfff]))|((?<![\ud800-\udbff])[\udc00-\udfff])", ""); + return Normalize(text, form, false); + } + } + + try + { + return text.Normalize(form); + } + catch (ArgumentException) + { + // if it still fails, return the original text + return text; + } } } } 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/ItemResolveArgs.cs b/MediaBrowser.Controller/Library/ItemResolveArgs.cs index 7bb8325f8..0222b926e 100644 --- a/MediaBrowser.Controller/Library/ItemResolveArgs.cs +++ b/MediaBrowser.Controller/Library/ItemResolveArgs.cs @@ -85,7 +85,7 @@ namespace MediaBrowser.Controller.Library return false; } - var parentDir = BaseItem.FileSystem.GetDirectoryName(Path) ?? string.Empty; + var parentDir = System.IO.Path.GetDirectoryName(Path) ?? string.Empty; return parentDir.Length > _appPaths.RootFolderPath.Length && parentDir.StartsWith(_appPaths.RootFolderPath, StringComparison.OrdinalIgnoreCase); 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 968e3dbcb..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> @@ -434,7 +434,7 @@ namespace MediaBrowser.Controller.MediaEncoding if (string.Equals(Path.GetExtension(subtitlePath), ".sub", StringComparison.OrdinalIgnoreCase)) { var idxFile = Path.ChangeExtension(subtitlePath, ".idx"); - if (_fileSystem.FileExists(idxFile)) + if (File.Exists(idxFile)) { subtitlePath = idxFile; } @@ -542,7 +542,7 @@ namespace MediaBrowser.Controller.MediaEncoding // var fallbackFontPath = Path.Combine(_appPaths.ProgramDataPath, "fonts", "DroidSansFallback.ttf"); // string fallbackFontParam = string.Empty; - // if (!_fileSystem.FileExists(fallbackFontPath)) + // if (!File.Exists(fallbackFontPath)) // { // _fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(fallbackFontPath)); // using (var stream = _assemblyInfo.GetManifestResourceStream(GetType(), GetType().Namespace + ".DroidSansFallback.ttf")) @@ -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/Playlists/Playlist.cs b/MediaBrowser.Controller/Playlists/Playlist.cs index 969643660..e83260725 100644 --- a/MediaBrowser.Controller/Playlists/Playlist.cs +++ b/MediaBrowser.Controller/Playlists/Playlist.cs @@ -50,7 +50,7 @@ namespace MediaBrowser.Controller.Playlists if (IsPlaylistFile(path)) { - return FileSystem.GetDirectoryName(path); + return System.IO.Path.GetDirectoryName(path); } return path; 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.Controller/Subtitles/ISubtitleManager.cs b/MediaBrowser.Controller/Subtitles/ISubtitleManager.cs index 2ee58bbe6..0872335c5 100644 --- a/MediaBrowser.Controller/Subtitles/ISubtitleManager.cs +++ b/MediaBrowser.Controller/Subtitles/ISubtitleManager.cs @@ -16,11 +16,6 @@ namespace MediaBrowser.Controller.Subtitles event EventHandler<SubtitleDownloadFailureEventArgs> SubtitleDownloadFailure; /// <summary> - /// Occurs when [subtitles downloaded]. - /// </summary> - event EventHandler<SubtitleDownloadEventArgs> SubtitlesDownloaded; - - /// <summary> /// Adds the parts. /// </summary> /// <param name="subtitleProviders">The subtitle providers.</param> diff --git a/MediaBrowser.LocalMetadata/Images/EpisodeLocalImageProvider.cs b/MediaBrowser.LocalMetadata/Images/EpisodeLocalImageProvider.cs index 894f46129..443f3fbb5 100644 --- a/MediaBrowser.LocalMetadata/Images/EpisodeLocalImageProvider.cs +++ b/MediaBrowser.LocalMetadata/Images/EpisodeLocalImageProvider.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.IO; using System.Linq; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.TV; @@ -29,11 +30,11 @@ namespace MediaBrowser.LocalMetadata.Images public List<LocalImageInfo> GetImages(BaseItem item, IDirectoryService directoryService) { - var parentPath = _fileSystem.GetDirectoryName(item.Path); + var parentPath = Path.GetDirectoryName(item.Path); var parentPathFiles = directoryService.GetFiles(parentPath); - var nameWithoutExtension = _fileSystem.GetFileNameWithoutExtension(item.Path); + var nameWithoutExtension = Path.GetFileNameWithoutExtension(item.Path); return GetFilesFromParentFolder(nameWithoutExtension, parentPathFiles); } 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/BaseItemXmlParser.cs b/MediaBrowser.LocalMetadata/Parsers/BaseItemXmlParser.cs index e40a55e56..38458e34c 100644 --- a/MediaBrowser.LocalMetadata/Parsers/BaseItemXmlParser.cs +++ b/MediaBrowser.LocalMetadata/Parsers/BaseItemXmlParser.cs @@ -102,7 +102,7 @@ namespace MediaBrowser.LocalMetadata.Parsers { item.ResetPeople(); - using (var fileStream = FileSystem.OpenRead(metadataFile)) + using (var fileStream = File.OpenRead(metadataFile)) { using (var streamReader = new StreamReader(fileStream, encoding)) { 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 537bd073c..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(FileSystem.GetDirectoryName(info.Path), "game.xml")); - } - } -} diff --git a/MediaBrowser.LocalMetadata/Savers/BaseXmlSaver.cs b/MediaBrowser.LocalMetadata/Savers/BaseXmlSaver.cs index 2eac35f28..438b84252 100644 --- a/MediaBrowser.LocalMetadata/Savers/BaseXmlSaver.cs +++ b/MediaBrowser.LocalMetadata/Savers/BaseXmlSaver.cs @@ -94,7 +94,7 @@ namespace MediaBrowser.LocalMetadata.Savers private void SaveToFile(Stream stream, string path) { - FileSystem.CreateDirectory(FileSystem.GetDirectoryName(path)); + Directory.CreateDirectory(Path.GetDirectoryName(path)); // On Windows, savint the file will fail if the file is hidden or readonly FileSystem.SetAttributes(path, false, false); @@ -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/Configuration/EncodingConfigurationFactory.cs b/MediaBrowser.MediaEncoding/Configuration/EncodingConfigurationFactory.cs index 1af4146bc..bb806ee55 100644 --- a/MediaBrowser.MediaEncoding/Configuration/EncodingConfigurationFactory.cs +++ b/MediaBrowser.MediaEncoding/Configuration/EncodingConfigurationFactory.cs @@ -46,7 +46,7 @@ namespace MediaBrowser.MediaEncoding.Configuration && !string.Equals(oldEncodingConfig.TranscodingTempPath ?? string.Empty, newPath)) { // Validate - if (!_fileSystem.DirectoryExists(newPath)) + if (!Directory.Exists(newPath)) { throw new FileNotFoundException(string.Format("{0} does not exist.", newPath)); } 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 ed4c445cd..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); - FileSystem.CreateDirectory(FileSystem.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"); - FileSystem.CreateDirectory(FileSystem.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 (!FileSystem.FileExists(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 d9c178431..d922f1068 100644 --- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs @@ -214,7 +214,7 @@ namespace MediaBrowser.MediaEncoding.Encoder throw new ArgumentNullException(nameof(path)); } - if (!FileSystem.FileExists(path) && !FileSystem.DirectoryExists(path)) + if (!File.Exists(path) && !Directory.Exists(path)) { throw new ResourceNotFoundException(); } @@ -288,12 +288,12 @@ namespace MediaBrowser.MediaEncoding.Encoder if (!string.IsNullOrWhiteSpace(appPath)) { - if (FileSystem.DirectoryExists(appPath)) + if (Directory.Exists(appPath)) { return GetPathsFromDirectory(appPath); } - if (FileSystem.FileExists(appPath)) + if (File.Exists(appPath)) { return new Tuple<string, string>(appPath, GetProbePathFromEncoderPath(appPath)); } @@ -336,7 +336,7 @@ namespace MediaBrowser.MediaEncoding.Encoder var ffmpegPath = files.FirstOrDefault(i => string.Equals(Path.GetFileNameWithoutExtension(i), "ffmpeg", StringComparison.OrdinalIgnoreCase) && !excludeExtensions.Contains(Path.GetExtension(i) ?? string.Empty)); var ffprobePath = files.FirstOrDefault(i => string.Equals(Path.GetFileNameWithoutExtension(i), "ffprobe", StringComparison.OrdinalIgnoreCase) && !excludeExtensions.Contains(Path.GetExtension(i) ?? string.Empty)); - if (string.IsNullOrWhiteSpace(ffmpegPath) || !FileSystem.FileExists(ffmpegPath)) + if (string.IsNullOrWhiteSpace(ffmpegPath) || !File.Exists(ffmpegPath)) { files = FileSystem.GetFilePaths(path, true); @@ -353,7 +353,7 @@ namespace MediaBrowser.MediaEncoding.Encoder private string GetProbePathFromEncoderPath(string appPath) { - return FileSystem.GetFilePaths(FileSystem.GetDirectoryName(appPath)) + return FileSystem.GetFilePaths(Path.GetDirectoryName(appPath)) .FirstOrDefault(i => string.Equals(Path.GetFileNameWithoutExtension(i), "ffprobe", StringComparison.OrdinalIgnoreCase)); } @@ -608,7 +608,7 @@ namespace MediaBrowser.MediaEncoding.Encoder } var tempExtractPath = Path.Combine(ConfigurationManager.ApplicationPaths.TempDirectory, Guid.NewGuid() + ".jpg"); - FileSystem.CreateDirectory(FileSystem.GetDirectoryName(tempExtractPath)); + Directory.CreateDirectory(Path.GetDirectoryName(tempExtractPath)); // apply some filters to thumbnail extracted below (below) crop any black lines that we made and get the correct ar then scale to width 600. // This filter chain may have adverse effects on recorded tv thumbnails if ar changes during presentation ex. commercials @ diff ar @@ -770,7 +770,7 @@ namespace MediaBrowser.MediaEncoding.Encoder vf += string.Format(",scale=min(iw\\,{0}):trunc(ow/dar/2)*2", maxWidthParam); } - FileSystem.CreateDirectory(targetDirectory); + Directory.CreateDirectory(targetDirectory); var outputPath = Path.Combine(targetDirectory, filenamePrefix + "%05d.jpg"); var args = string.Format("-i {0} -threads 0 -v quiet -vf \"{2}\" -f image2 \"{1}\"", inputArgument, outputPath, vf); @@ -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/OpenSubtitleDownloader.cs b/MediaBrowser.MediaEncoding/Subtitles/OpenSubtitleDownloader.cs index a1d925881..6a5162b8d 100644 --- a/MediaBrowser.MediaEncoding/Subtitles/OpenSubtitleDownloader.cs +++ b/MediaBrowser.MediaEncoding/Subtitles/OpenSubtitleDownloader.cs @@ -269,7 +269,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles var subLanguageId = NormalizeLanguage(request.Language); string hash; - using (var fileStream = _fileSystem.OpenRead(request.MediaPath)) + using (var fileStream = File.OpenRead(request.MediaPath)) { hash = Utilities.ComputeHash(fileStream); } 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.MediaEncoding/Subtitles/SubtitleEncoder.cs b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs index 2f9eb98ea..d978359c7 100644 --- a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs +++ b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs @@ -210,7 +210,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles } } - return _fileSystem.OpenRead(path); + return File.OpenRead(path); } private async Task<SubtitleInfo> GetReadableFile( @@ -386,7 +386,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles try { - if (!_fileSystem.FileExists(outputPath)) + if (!File.Exists(outputPath)) { await ConvertTextSubtitleToSrtInternal(inputPath, language, inputProtocol, outputPath, cancellationToken).ConfigureAwait(false); } @@ -422,7 +422,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles throw new ArgumentNullException(nameof(outputPath)); } - _fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(outputPath)); + Directory.CreateDirectory(Path.GetDirectoryName(outputPath)); var encodingParam = await GetSubtitleFileCharacterSet(inputPath, language, inputProtocol, cancellationToken).ConfigureAwait(false); @@ -481,7 +481,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles { failed = true; - if (_fileSystem.FileExists(outputPath)) + if (File.Exists(outputPath)) { try { @@ -494,7 +494,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles } } } - else if (!_fileSystem.FileExists(outputPath)) + else if (!File.Exists(outputPath)) { failed = true; } @@ -537,7 +537,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles try { - if (!_fileSystem.FileExists(outputPath)) + if (!File.Exists(outputPath)) { await ExtractTextSubtitleInternal(_mediaEncoder.GetInputArgument(inputFiles, protocol), subtitleStreamIndex, outputCodec, outputPath, cancellationToken).ConfigureAwait(false); } @@ -565,7 +565,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles throw new ArgumentNullException(nameof(outputPath)); } - _fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(outputPath)); + Directory.CreateDirectory(Path.GetDirectoryName(outputPath)); var processArgs = string.Format("-i {0} -map 0:{1} -an -vn -c:s {2} \"{3}\"", inputPath, subtitleStreamIndex, outputCodec, outputPath); @@ -634,7 +634,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles _logger.LogError(ex, "Error deleting extracted subtitle {Path}", outputPath); } } - else if (!_fileSystem.FileExists(outputPath)) + else if (!File.Exists(outputPath)) { failed = true; } @@ -672,7 +672,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles string text; Encoding encoding; - using (var fileStream = _fileSystem.OpenRead(file)) + using (var fileStream = File.OpenRead(file)) using (var reader = new StreamReader(fileStream, true)) { encoding = reader.CurrentEncoding; @@ -747,7 +747,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles } if (protocol == MediaProtocol.File) { - return _fileSystem.ReadAllBytes(path); + return File.ReadAllBytes(path); } throw new ArgumentOutOfRangeException(nameof(protocol)); 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/Globalization/ILocalizationManager.cs b/MediaBrowser.Model/Globalization/ILocalizationManager.cs index 05efb6681..a9ce60a2a 100644 --- a/MediaBrowser.Model/Globalization/ILocalizationManager.cs +++ b/MediaBrowser.Model/Globalization/ILocalizationManager.cs @@ -1,4 +1,6 @@ +using System.Collections.Generic; using System.Globalization; +using System.Threading.Tasks; using MediaBrowser.Model.Entities; namespace MediaBrowser.Model.Globalization @@ -17,12 +19,12 @@ namespace MediaBrowser.Model.Globalization /// Gets the countries. /// </summary> /// <returns>IEnumerable{CountryInfo}.</returns> - CountryInfo[] GetCountries(); + Task<CountryInfo[]> GetCountries(); /// <summary> /// Gets the parental ratings. /// </summary> /// <returns>IEnumerable{ParentalRating}.</returns> - ParentalRating[] GetParentalRatings(); + IEnumerable<ParentalRating> GetParentalRatings(); /// <summary> /// Gets the rating level. /// </summary> @@ -51,8 +53,6 @@ namespace MediaBrowser.Model.Globalization /// <returns>IEnumerable{LocalizatonOption}.</returns> LocalizationOption[] GetLocalizationOptions(); - string RemoveDiacritics(string text); - string NormalizeFormKD(string text); bool HasUnicodeCategory(string value, UnicodeCategory category); diff --git a/MediaBrowser.Model/IO/IFileSystem.cs b/MediaBrowser.Model/IO/IFileSystem.cs index b8a315ccc..6c9b2bd88 100644 --- a/MediaBrowser.Model/IO/IFileSystem.cs +++ b/MediaBrowser.Model/IO/IFileSystem.cs @@ -36,32 +36,32 @@ namespace MediaBrowser.Model.IO string MakeAbsolutePath(string folderPath, string filePath); /// <summary> - /// Returns a <see cref="FileSystemMetadata"/> object for the specified file or directory path. + /// Returns a <see cref="FileSystemMetadata" /> object for the specified file or directory path. /// </summary> /// <param name="path">A path to a file or directory.</param> - /// <returns>A <see cref="FileSystemMetadata"/> object.</returns> - /// <remarks>If the specified path points to a directory, the returned <see cref="FileSystemMetadata"/> object's - /// <see cref="FileSystemMetadata.IsDirectory"/> property will be set to true and all other properties will reflect the properties of the directory.</remarks> + /// <returns>A <see cref="FileSystemMetadata" /> object.</returns> + /// <remarks>If the specified path points to a directory, the returned <see cref="FileSystemMetadata" /> object's + /// <see cref="FileSystemMetadata.IsDirectory" /> property will be set to true and all other properties will reflect the properties of the directory.</remarks> FileSystemMetadata GetFileSystemInfo(string path); /// <summary> - /// Returns a <see cref="FileSystemMetadata"/> object for the specified file path. + /// Returns a <see cref="FileSystemMetadata" /> object for the specified file path. /// </summary> /// <param name="path">A path to a file.</param> - /// <returns>A <see cref="FileSystemMetadata"/> object.</returns> - /// <remarks><para>If the specified path points to a directory, the returned <see cref="FileSystemMetadata"/> object's - /// <see cref="FileSystemMetadata.IsDirectory"/> property and the <see cref="FileSystemMetadata.Exists"/> property will both be set to false.</para> - /// <para>For automatic handling of files <b>and</b> directories, use <see cref="GetFileSystemInfo"/>.</para></remarks> + /// <returns>A <see cref="FileSystemMetadata" /> object.</returns> + /// <remarks><para>If the specified path points to a directory, the returned <see cref="FileSystemMetadata" /> object's + /// <see cref="FileSystemMetadata.IsDirectory" /> property and the <see cref="FileSystemMetadata.Exists" /> property will both be set to false.</para> + /// <para>For automatic handling of files <b>and</b> directories, use <see cref="M:IFileSystem.GetFileSystemInfo(System.String)" />.</para></remarks> FileSystemMetadata GetFileInfo(string path); /// <summary> - /// Returns a <see cref="FileSystemMetadata"/> object for the specified directory path. + /// Returns a <see cref="FileSystemMetadata" /> object for the specified directory path. /// </summary> /// <param name="path">A path to a directory.</param> - /// <returns>A <see cref="FileSystemMetadata"/> object.</returns> - /// <remarks><para>If the specified path points to a file, the returned <see cref="FileSystemMetadata"/> object's - /// <see cref="FileSystemMetadata.IsDirectory"/> property will be set to true and the <see cref="FileSystemMetadata.Exists"/> property will be set to false.</para> - /// <para>For automatic handling of files <b>and</b> directories, use <see cref="GetFileSystemInfo"/>.</para></remarks> + /// <returns>A <see cref="FileSystemMetadata" /> object.</returns> + /// <remarks><para>If the specified path points to a file, the returned <see cref="FileSystemMetadata" /> object's + /// <see cref="FileSystemMetadata.IsDirectory" /> property will be set to true and the <see cref="FileSystemMetadata.Exists" /> property will be set to false.</para> + /// <para>For automatic handling of files <b>and</b> directories, use <see cref="M:IFileSystem.GetFileSystemInfo(System.String)" />.</para></remarks> FileSystemMetadata GetDirectoryInfo(string path); /// <summary> @@ -110,14 +110,8 @@ namespace MediaBrowser.Model.IO /// <returns>FileStream.</returns> Stream GetFileStream(string path, FileOpenMode mode, FileAccessMode access, FileShareMode share, bool isAsync = false); - Stream GetFileStream(string path, FileOpenMode mode, FileAccessMode access, FileShareMode share, FileOpenOptions fileOpenOptions); - - /// <summary> - /// Opens the read. - /// </summary> - /// <param name="path">The path.</param> - /// <returns>Stream.</returns> - Stream OpenRead(string path); + Stream GetFileStream(string path, FileOpenMode mode, FileAccessMode access, FileShareMode share, + FileOpenOptions fileOpenOptions); string DefaultDirectory { get; } @@ -152,8 +146,6 @@ namespace MediaBrowser.Model.IO /// <returns>System.String.</returns> string NormalizePath(string path); - string GetDirectoryName(string path); - /// <summary> /// Gets the file name without extension. /// </summary> @@ -162,13 +154,6 @@ namespace MediaBrowser.Model.IO string GetFileNameWithoutExtension(FileSystemMetadata info); /// <summary> - /// Gets the file name without extension. - /// </summary> - /// <param name="path">The path.</param> - /// <returns>System.String.</returns> - string GetFileNameWithoutExtension(string path); - - /// <summary> /// Determines whether [is path file] [the specified path]. /// </summary> /// <param name="path">The path.</param> @@ -182,13 +167,6 @@ namespace MediaBrowser.Model.IO void DeleteFile(string path); /// <summary> - /// Deletes the directory. - /// </summary> - /// <param name="path">The path.</param> - /// <param name="recursive">if set to <c>true</c> [recursive].</param> - void DeleteDirectory(string path, bool recursive); - - /// <summary> /// Gets the directories. /// </summary> /// <param name="path">The path.</param> @@ -212,86 +190,6 @@ namespace MediaBrowser.Model.IO IEnumerable<FileSystemMetadata> GetFileSystemEntries(string path, bool recursive = false); /// <summary> - /// Creates the directory. - /// </summary> - /// <param name="path">The path.</param> - void CreateDirectory(string path); - - /// <summary> - /// Copies the file. - /// </summary> - /// <param name="source">The source.</param> - /// <param name="target">The target.</param> - /// <param name="overwrite">if set to <c>true</c> [overwrite].</param> - void CopyFile(string source, string target, bool overwrite); - - /// <summary> - /// Moves the file. - /// </summary> - /// <param name="source">The source.</param> - /// <param name="target">The target.</param> - void MoveFile(string source, string target); - - /// <summary> - /// Moves the directory. - /// </summary> - /// <param name="source">The source.</param> - /// <param name="target">The target.</param> - void MoveDirectory(string source, string target); - - /// <summary> - /// Directories the exists. - /// </summary> - /// <param name="path">The path.</param> - /// <returns><c>true</c> if XXXX, <c>false</c> otherwise.</returns> - bool DirectoryExists(string path); - - /// <summary> - /// Files the exists. - /// </summary> - /// <param name="path">The path.</param> - /// <returns><c>true</c> if XXXX, <c>false</c> otherwise.</returns> - bool FileExists(string path); - - /// <summary> - /// Reads all text. - /// </summary> - /// <param name="path">The path.</param> - /// <returns>System.String.</returns> - string ReadAllText(string path); - - byte[] ReadAllBytes(string path); - - void WriteAllBytes(string path, byte[] bytes); - - /// <summary> - /// Writes all text. - /// </summary> - /// <param name="path">The path.</param> - /// <param name="text">The text.</param> - void WriteAllText(string path, string text); - - /// <summary> - /// Writes all text. - /// </summary> - /// <param name="path">The path.</param> - /// <param name="text">The text.</param> - /// <param name="encoding">The encoding.</param> - void WriteAllText(string path, string text, Encoding encoding); - - /// <summary> - /// Reads all text. - /// </summary> - /// <param name="path">The path.</param> - /// <param name="encoding">The encoding.</param> - /// <returns>System.String.</returns> - string ReadAllText(string path, Encoding encoding); - - string[] ReadAllLines(string path); - - void WriteAllLines(string path, IEnumerable<string> lines); - - /// <summary> /// Gets the directory paths. /// </summary> /// <param name="path">The path.</param> @@ -306,6 +204,7 @@ namespace MediaBrowser.Model.IO /// <param name="recursive">if set to <c>true</c> [recursive].</param> /// <returns>IEnumerable<System.String>.</returns> IEnumerable<string> GetFilePaths(string path, bool recursive = false); + IEnumerable<string> GetFilePaths(string path, string[] extensions, bool enableCaseSensitiveExtensions, bool recursive); /// <summary> @@ -319,15 +218,10 @@ namespace MediaBrowser.Model.IO void SetHidden(string path, bool isHidden); void SetReadOnly(string path, bool readOnly); void SetAttributes(string path, bool isHidden, bool readOnly); - - char DirectorySeparatorChar { get; } - - string GetFullPath(string path); - List<FileSystemMetadata> GetDrives(); - void SetExecutable(string path); } + //TODO Investigate if can be replaced by the one from System.IO ? public enum FileOpenMode { 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/BoxSets/MovieDbBoxSetProvider.cs b/MediaBrowser.Providers/BoxSets/MovieDbBoxSetProvider.cs index e06d93520..4e41694c4 100644 --- a/MediaBrowser.Providers/BoxSets/MovieDbBoxSetProvider.cs +++ b/MediaBrowser.Providers/BoxSets/MovieDbBoxSetProvider.cs @@ -156,7 +156,7 @@ namespace MediaBrowser.Providers.BoxSets var dataFilePath = GetDataFilePath(_config.ApplicationPaths, tmdbId, preferredMetadataLanguage); - _fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(dataFilePath)); + Directory.CreateDirectory(Path.GetDirectoryName(dataFilePath)); _json.SerializeToFile(mainResult, dataFilePath); } 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 d0d00ef12..ab906809f 100644 --- a/MediaBrowser.Providers/Manager/ImageSaver.cs +++ b/MediaBrowser.Providers/Manager/ImageSaver.cs @@ -233,14 +233,14 @@ namespace MediaBrowser.Providers.Manager { _logger.LogDebug("Saving image to {0}", path); - var parentFolder = _fileSystem.GetDirectoryName(path); + var parentFolder = Path.GetDirectoryName(path); try { _libraryMonitor.ReportFileSystemChangeBeginning(path); _libraryMonitor.ReportFileSystemChangeBeginning(parentFolder); - _fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(path)); + Directory.CreateDirectory(Path.GetDirectoryName(path)); _fileSystem.SetAttributes(path, false, false); @@ -411,7 +411,7 @@ namespace MediaBrowser.Providers.Manager filename = item is MusicAlbum ? "cdart" : "disc"; break; case ImageType.Primary: - filename = saveLocally && item is Episode ? _fileSystem.GetFileNameWithoutExtension(item.Path) : folderName; + filename = saveLocally && item is Episode ? Path.GetFileNameWithoutExtension(item.Path) : folderName; break; case ImageType.Backdrop: filename = GetBackdropSaveFilename(item.GetImages(type), "backdrop", "backdrop", imageIndex); @@ -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; @@ -437,7 +437,7 @@ namespace MediaBrowser.Providers.Manager { if (type == ImageType.Primary && item is Episode) { - path = Path.Combine(_fileSystem.GetDirectoryName(item.Path), "metadata", filename + extension); + path = Path.Combine(Path.GetDirectoryName(item.Path), "metadata", filename + extension); } else if (item.IsInMixedFolder) @@ -471,7 +471,7 @@ namespace MediaBrowser.Providers.Manager return zeroIndexFilename; } - var filenames = images.Select(i => _fileSystem.GetFileNameWithoutExtension(i.Path)).ToList(); + var filenames = images.Select(i => Path.GetFileNameWithoutExtension(i.Path)).ToList(); var current = 1; while (filenames.Contains(numberedIndexPrefix + current.ToString(UsCulture), StringComparer.OrdinalIgnoreCase)) @@ -569,9 +569,9 @@ namespace MediaBrowser.Providers.Manager if (item is Episode) { - var seasonFolder = _fileSystem.GetDirectoryName(item.Path); + var seasonFolder = Path.GetDirectoryName(item.Path); - var imageFilename = _fileSystem.GetFileNameWithoutExtension(item.Path) + "-thumb" + extension; + var imageFilename = Path.GetFileNameWithoutExtension(item.Path) + "-thumb" + extension; return new[] { Path.Combine(seasonFolder, imageFilename) }; } @@ -617,9 +617,9 @@ namespace MediaBrowser.Providers.Manager { imageFilename = "poster"; } - var folder = _fileSystem.GetDirectoryName(item.Path); + var folder = Path.GetDirectoryName(item.Path); - return Path.Combine(folder, _fileSystem.GetFileNameWithoutExtension(item.Path) + "-" + imageFilename + extension); + return Path.Combine(folder, Path.GetFileNameWithoutExtension(item.Path) + "-" + imageFilename + extension); } } } diff --git a/MediaBrowser.Providers/Manager/ItemImageProvider.cs b/MediaBrowser.Providers/Manager/ItemImageProvider.cs index c2e53ae6c..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); } @@ -387,7 +387,7 @@ namespace MediaBrowser.Providers.Manager var existing = item.GetImageInfo(type, 0); if (existing != null) { - if (existing.IsLocalFile && !_fileSystem.FileExists(existing.Path)) + if (existing.IsLocalFile && !File.Exists(existing.Path)) { item.RemoveImage(existing); changed = true; diff --git a/MediaBrowser.Providers/Manager/MetadataService.cs b/MediaBrowser.Providers/Manager/MetadataService.cs index 1972ad290..77028e526 100644 --- a/MediaBrowser.Providers/Manager/MetadataService.cs +++ b/MediaBrowser.Providers/Manager/MetadataService.cs @@ -566,8 +566,7 @@ namespace MediaBrowser.Providers.Manager var providersWithChanges = providers .Where(i => { - var hasFileChangeMonitor = i as IHasItemChangeMonitor; - if (hasFileChangeMonitor != null) + if (i is IHasItemChangeMonitor hasFileChangeMonitor) { return HasChanged(item, hasFileChangeMonitor, options.DirectoryService); } diff --git a/MediaBrowser.Providers/Manager/ProviderManager.cs b/MediaBrowser.Providers/Manager/ProviderManager.cs index 65364ad67..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>(), @@ -703,7 +701,7 @@ namespace MediaBrowser.Providers.Manager // Manual edit occurred // Even if save local is off, save locally anyway if the metadata file already exists - if (fileSaver == null || !_fileSystem.FileExists(fileSaver.GetSavePath(item))) + if (fileSaver == null || !File.Exists(fileSaver.GetSavePath(item))) { return false; } diff --git a/MediaBrowser.Providers/MediaInfo/AudioImageProvider.cs b/MediaBrowser.Providers/MediaInfo/AudioImageProvider.cs index 0b902ccec..61a8a122b 100644 --- a/MediaBrowser.Providers/MediaInfo/AudioImageProvider.cs +++ b/MediaBrowser.Providers/MediaInfo/AudioImageProvider.cs @@ -58,9 +58,9 @@ namespace MediaBrowser.Providers.MediaInfo { var path = GetAudioImagePath(item); - if (!_fileSystem.FileExists(path)) + if (!File.Exists(path)) { - _fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(path)); + Directory.CreateDirectory(Path.GetDirectoryName(path)); var imageStream = imageStreams.FirstOrDefault(i => (i.Comment ?? string.Empty).IndexOf("front", StringComparison.OrdinalIgnoreCase) != -1) ?? imageStreams.FirstOrDefault(i => (i.Comment ?? string.Empty).IndexOf("cover", StringComparison.OrdinalIgnoreCase) != -1) ?? @@ -70,7 +70,7 @@ namespace MediaBrowser.Providers.MediaInfo var tempFile = await _mediaEncoder.ExtractAudioImage(item.Path, imageStreamIndex, cancellationToken).ConfigureAwait(false); - _fileSystem.CopyFile(tempFile, path, true); + File.Copy(tempFile, path, true); try { diff --git a/MediaBrowser.Providers/MediaInfo/FFProbeProvider.cs b/MediaBrowser.Providers/MediaInfo/FFProbeProvider.cs index 5e9824ed1..4e11fcbb2 100644 --- a/MediaBrowser.Providers/MediaInfo/FFProbeProvider.cs +++ b/MediaBrowser.Providers/MediaInfo/FFProbeProvider.cs @@ -1,4 +1,5 @@ using System; +using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; @@ -73,17 +74,12 @@ namespace MediaBrowser.Providers.MediaInfo } } - if (item.SupportsLocalMetadata) + if (item.SupportsLocalMetadata && video != null && !video.IsPlaceHolder + && !video.SubtitleFiles.SequenceEqual( + _subtitleResolver.GetExternalSubtitleFiles(video, directoryService, false), StringComparer.Ordinal)) { - if (video != null && !video.IsPlaceHolder) - { - if (!video.SubtitleFiles - .SequenceEqual(_subtitleResolver.GetExternalSubtitleFiles(video, directoryService, false), StringComparer.Ordinal)) - { - _logger.LogDebug("Refreshing {0} due to external subtitles change.", item.Path); - return true; - } - } + _logger.LogDebug("Refreshing {0} due to external subtitles change.", item.Path); + return true; } return false; @@ -196,7 +192,7 @@ namespace MediaBrowser.Providers.MediaInfo private void FetchShortcutInfo(BaseItem item) { - item.ShortcutPath = _fileSystem.ReadAllLines(item.Path) + item.ShortcutPath = File.ReadAllLines(item.Path) .Select(NormalizeStrmLine) .FirstOrDefault(i => !string.IsNullOrWhiteSpace(i) && !i.StartsWith("#", StringComparison.OrdinalIgnoreCase)); } diff --git a/MediaBrowser.Providers/MediaInfo/SubtitleResolver.cs b/MediaBrowser.Providers/MediaInfo/SubtitleResolver.cs index 2ce10b656..cd026b39b 100644 --- a/MediaBrowser.Providers/MediaInfo/SubtitleResolver.cs +++ b/MediaBrowser.Providers/MediaInfo/SubtitleResolver.cs @@ -98,7 +98,7 @@ namespace MediaBrowser.Providers.MediaInfo int startIndex, string[] files) { - var videoFileNameWithoutExtension = _fileSystem.GetFileNameWithoutExtension(videoPath); + var videoFileNameWithoutExtension = Path.GetFileNameWithoutExtension(videoPath); videoFileNameWithoutExtension = NormalizeFilenameForSubtitleComparison(videoFileNameWithoutExtension); foreach (var fullName in files) @@ -110,7 +110,7 @@ namespace MediaBrowser.Providers.MediaInfo continue; } - var fileNameWithoutExtension = _fileSystem.GetFileNameWithoutExtension(fullName); + var fileNameWithoutExtension = Path.GetFileNameWithoutExtension(fullName); fileNameWithoutExtension = NormalizeFilenameForSubtitleComparison(fileNameWithoutExtension); if (!string.Equals(videoFileNameWithoutExtension, fileNameWithoutExtension, StringComparison.OrdinalIgnoreCase) && @@ -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/FanartMovieImageProvider.cs b/MediaBrowser.Providers/Movies/FanartMovieImageProvider.cs index 63d99db9b..4a94bcb1a 100644 --- a/MediaBrowser.Providers/Movies/FanartMovieImageProvider.cs +++ b/MediaBrowser.Providers/Movies/FanartMovieImageProvider.cs @@ -254,7 +254,7 @@ namespace MediaBrowser.Providers.Movies var path = GetFanartJsonPath(id); - _fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(path)); + Directory.CreateDirectory(Path.GetDirectoryName(path)); try { diff --git a/MediaBrowser.Providers/Movies/GenericMovieDbInfo.cs b/MediaBrowser.Providers/Movies/GenericMovieDbInfo.cs index 10d3e5e9d..4300b84a9 100644 --- a/MediaBrowser.Providers/Movies/GenericMovieDbInfo.cs +++ b/MediaBrowser.Providers/Movies/GenericMovieDbInfo.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Globalization; +using System.IO; using System.Linq; using System.Net; using System.Threading; @@ -91,7 +92,7 @@ namespace MediaBrowser.Providers.Movies tmdbId = movieInfo.id.ToString(_usCulture); dataFilePath = MovieDbProvider.Current.GetDataFilePath(tmdbId, language); - _fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(dataFilePath)); + Directory.CreateDirectory(Path.GetDirectoryName(dataFilePath)); _jsonSerializer.SerializeToFile(movieInfo, dataFilePath); } } diff --git a/MediaBrowser.Providers/Movies/MovieDbProvider.cs b/MediaBrowser.Providers/Movies/MovieDbProvider.cs index f03a8c2c2..3ff63a4bf 100644 --- a/MediaBrowser.Providers/Movies/MovieDbProvider.cs +++ b/MediaBrowser.Providers/Movies/MovieDbProvider.cs @@ -198,7 +198,7 @@ namespace MediaBrowser.Providers.Movies var dataFilePath = GetDataFilePath(id, preferredMetadataLanguage); - _fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(dataFilePath)); + Directory.CreateDirectory(Path.GetDirectoryName(dataFilePath)); _jsonSerializer.SerializeToFile(mainResult, dataFilePath); } @@ -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/Music/AudioDbAlbumProvider.cs b/MediaBrowser.Providers/Music/AudioDbAlbumProvider.cs index 3c4855806..7ccf7cffa 100644 --- a/MediaBrowser.Providers/Music/AudioDbAlbumProvider.cs +++ b/MediaBrowser.Providers/Music/AudioDbAlbumProvider.cs @@ -153,7 +153,7 @@ namespace MediaBrowser.Providers.Music var path = GetAlbumInfoPath(_config.ApplicationPaths, musicBrainzReleaseGroupId); - _fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(path)); + Directory.CreateDirectory(Path.GetDirectoryName(path)); using (var httpResponse = await _httpClient.SendAsync(new HttpRequestOptions { diff --git a/MediaBrowser.Providers/Music/AudioDbArtistProvider.cs b/MediaBrowser.Providers/Music/AudioDbArtistProvider.cs index 03eefc2eb..2540a6047 100644 --- a/MediaBrowser.Providers/Music/AudioDbArtistProvider.cs +++ b/MediaBrowser.Providers/Music/AudioDbArtistProvider.cs @@ -151,7 +151,7 @@ namespace MediaBrowser.Providers.Music { using (var response = httpResponse.Content) { - _fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(path)); + Directory.CreateDirectory(Path.GetDirectoryName(path)); using (var xmlFileStream = _fileSystem.GetFileStream(path, FileOpenMode.Create, FileAccessMode.Write, FileShareMode.Read, true)) { diff --git a/MediaBrowser.Providers/Music/FanArtArtistProvider.cs b/MediaBrowser.Providers/Music/FanArtArtistProvider.cs index a7456bdc0..2efeb6985 100644 --- a/MediaBrowser.Providers/Music/FanArtArtistProvider.cs +++ b/MediaBrowser.Providers/Music/FanArtArtistProvider.cs @@ -233,7 +233,7 @@ namespace MediaBrowser.Providers.Music var jsonPath = GetArtistJsonPath(_config.ApplicationPaths, musicBrainzId); - _fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(jsonPath)); + Directory.CreateDirectory(Path.GetDirectoryName(jsonPath)); try { diff --git a/MediaBrowser.Providers/Omdb/OmdbProvider.cs b/MediaBrowser.Providers/Omdb/OmdbProvider.cs index c52907745..19dce34d6 100644 --- a/MediaBrowser.Providers/Omdb/OmdbProvider.cs +++ b/MediaBrowser.Providers/Omdb/OmdbProvider.cs @@ -294,7 +294,7 @@ namespace MediaBrowser.Providers.Omdb using (var stream = response.Content) { var rootObject = await _jsonSerializer.DeserializeFromStreamAsync<RootObject>(stream).ConfigureAwait(false); - _fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(path)); + Directory.CreateDirectory(Path.GetDirectoryName(path)); _jsonSerializer.SerializeToFile(rootObject, path); } } @@ -331,7 +331,7 @@ namespace MediaBrowser.Providers.Omdb using (var stream = response.Content) { var rootObject = await _jsonSerializer.DeserializeFromStreamAsync<SeasonRootObject>(stream).ConfigureAwait(false); - _fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(path)); + Directory.CreateDirectory(Path.GetDirectoryName(path)); _jsonSerializer.SerializeToFile(rootObject, path); } } diff --git a/MediaBrowser.Providers/People/MovieDbPersonProvider.cs b/MediaBrowser.Providers/People/MovieDbPersonProvider.cs index dc6ce842e..6d9d66f80 100644 --- a/MediaBrowser.Providers/People/MovieDbPersonProvider.cs +++ b/MediaBrowser.Providers/People/MovieDbPersonProvider.cs @@ -229,7 +229,7 @@ namespace MediaBrowser.Providers.People { using (var json = response.Content) { - _fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(dataFilePath)); + Directory.CreateDirectory(Path.GetDirectoryName(dataFilePath)); using (var fs = _fileSystem.GetFileStream(dataFilePath, FileOpenMode.Create, FileAccessMode.Write, FileShareMode.Read, true)) { diff --git a/MediaBrowser.Providers/Playlists/PlaylistItemsProvider.cs b/MediaBrowser.Providers/Playlists/PlaylistItemsProvider.cs index 7a57adb33..dacb63f84 100644 --- a/MediaBrowser.Providers/Playlists/PlaylistItemsProvider.cs +++ b/MediaBrowser.Providers/Playlists/PlaylistItemsProvider.cs @@ -45,7 +45,7 @@ namespace MediaBrowser.Providers.Playlists return Task.FromResult(ItemUpdateType.None); } - using (var stream = _fileSystem.OpenRead(path)) + using (var stream = File.OpenRead(path)) { var items = GetItems(stream, extension).ToArray(); diff --git a/MediaBrowser.Providers/Studios/StudiosImageProvider.cs b/MediaBrowser.Providers/Studios/StudiosImageProvider.cs index 481f0d01f..4b41589f1 100644 --- a/MediaBrowser.Providers/Studios/StudiosImageProvider.cs +++ b/MediaBrowser.Providers/Studios/StudiosImageProvider.cs @@ -151,11 +151,11 @@ namespace MediaBrowser.Providers.Studios }).ConfigureAwait(false); - fileSystem.CreateDirectory(fileSystem.GetDirectoryName(file)); + Directory.CreateDirectory(Path.GetDirectoryName(file)); try { - fileSystem.CopyFile(temp, file, true); + File.Copy(temp, file, true); } catch { diff --git a/MediaBrowser.Providers/Subtitles/SubtitleManager.cs b/MediaBrowser.Providers/Subtitles/SubtitleManager.cs index 468ba730a..7fc6909f5 100644 --- a/MediaBrowser.Providers/Subtitles/SubtitleManager.cs +++ b/MediaBrowser.Providers/Subtitles/SubtitleManager.cs @@ -30,9 +30,7 @@ namespace MediaBrowser.Providers.Subtitles private readonly IFileSystem _fileSystem; private readonly ILibraryMonitor _monitor; private readonly IMediaSourceManager _mediaSourceManager; - private readonly IServerConfigurationManager _config; - public event EventHandler<SubtitleDownloadEventArgs> SubtitlesDownloaded; public event EventHandler<SubtitleDownloadFailureEventArgs> SubtitleDownloadFailure; private ILocalizationManager _localization; @@ -42,14 +40,12 @@ namespace MediaBrowser.Providers.Subtitles IFileSystem fileSystem, ILibraryMonitor monitor, IMediaSourceManager mediaSourceManager, - IServerConfigurationManager config, ILocalizationManager localizationManager) { _logger = loggerFactory.CreateLogger(nameof(SubtitleManager)); _fileSystem = fileSystem; _monitor = monitor; _mediaSourceManager = mediaSourceManager; - _config = config; _localization = localizationManager; } @@ -134,11 +130,6 @@ namespace MediaBrowser.Providers.Subtitles return results.SelectMany(i => i).ToArray(); } - private SubtitleOptions GetOptions() - { - return _config.GetConfiguration<SubtitleOptions>("subtitles"); - } - public Task DownloadSubtitles(Video video, string subtitleId, CancellationToken cancellationToken) { var libraryOptions = BaseItem.LibraryManager.GetLibraryOptions(video); @@ -168,14 +159,14 @@ namespace MediaBrowser.Providers.Subtitles memoryStream.Position = 0; var savePaths = new List<string>(); - var saveFileName = _fileSystem.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) { @@ -217,7 +208,7 @@ namespace MediaBrowser.Providers.Subtitles try { - _fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(savePath)); + Directory.CreateDirectory(Path.GetDirectoryName(savePath)); using (var fs = _fileSystem.GetFileStream(savePath, FileOpenMode.Create, FileAccessMode.Write, FileShareMode.Read, true)) { @@ -305,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/FanArt/FanartSeriesProvider.cs b/MediaBrowser.Providers/TV/FanArt/FanartSeriesProvider.cs index 7f3bc323e..172a7d2b8 100644 --- a/MediaBrowser.Providers/TV/FanArt/FanartSeriesProvider.cs +++ b/MediaBrowser.Providers/TV/FanArt/FanartSeriesProvider.cs @@ -298,7 +298,7 @@ namespace MediaBrowser.Providers.TV var path = GetFanartJsonPath(tvdbId); - _fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(path)); + Directory.CreateDirectory(Path.GetDirectoryName(path)); try { diff --git a/MediaBrowser.Providers/TV/MissingEpisodeProvider.cs b/MediaBrowser.Providers/TV/MissingEpisodeProvider.cs index 8da6d4523..4ac012399 100644 --- a/MediaBrowser.Providers/TV/MissingEpisodeProvider.cs +++ b/MediaBrowser.Providers/TV/MissingEpisodeProvider.cs @@ -58,7 +58,7 @@ namespace MediaBrowser.Providers.TV } // Check this in order to avoid logging an exception due to directory not existing - if (!_fileSystem.DirectoryExists(seriesDataPath)) + if (!Directory.Exists(seriesDataPath)) { return false; } diff --git a/MediaBrowser.Providers/TV/TheMovieDb/MovieDbProviderBase.cs b/MediaBrowser.Providers/TV/TheMovieDb/MovieDbProviderBase.cs index 3df3cf8b8..9f1102946 100644 --- a/MediaBrowser.Providers/TV/TheMovieDb/MovieDbProviderBase.cs +++ b/MediaBrowser.Providers/TV/TheMovieDb/MovieDbProviderBase.cs @@ -101,7 +101,7 @@ namespace MediaBrowser.Providers.TV var dataFilePath = GetDataFilePath(id, seasonNumber, episodeNumber, preferredMetadataLanguage); - _fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(dataFilePath)); + Directory.CreateDirectory(Path.GetDirectoryName(dataFilePath)); _jsonSerializer.SerializeToFile(mainResult, dataFilePath); } diff --git a/MediaBrowser.Providers/TV/TheMovieDb/MovieDbSeasonProvider.cs b/MediaBrowser.Providers/TV/TheMovieDb/MovieDbSeasonProvider.cs index 8d13cc726..790b38074 100644 --- a/MediaBrowser.Providers/TV/TheMovieDb/MovieDbSeasonProvider.cs +++ b/MediaBrowser.Providers/TV/TheMovieDb/MovieDbSeasonProvider.cs @@ -188,7 +188,7 @@ namespace MediaBrowser.Providers.TV var dataFilePath = GetDataFilePath(id, seasonNumber, preferredMetadataLanguage); - _fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(dataFilePath)); + Directory.CreateDirectory(Path.GetDirectoryName(dataFilePath)); _jsonSerializer.SerializeToFile(mainResult, dataFilePath); } diff --git a/MediaBrowser.Providers/TV/TheMovieDb/MovieDbSeriesProvider.cs b/MediaBrowser.Providers/TV/TheMovieDb/MovieDbSeriesProvider.cs index c20cbc419..76031a7cd 100644 --- a/MediaBrowser.Providers/TV/TheMovieDb/MovieDbSeriesProvider.cs +++ b/MediaBrowser.Providers/TV/TheMovieDb/MovieDbSeriesProvider.cs @@ -187,7 +187,7 @@ namespace MediaBrowser.Providers.TV tmdbId = seriesInfo.id.ToString(_usCulture); string dataFilePath = GetDataFilePath(tmdbId, language); - _fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(dataFilePath)); + Directory.CreateDirectory(Path.GetDirectoryName(dataFilePath)); _jsonSerializer.SerializeToFile(seriesInfo, dataFilePath); await EnsureSeriesInfo(tmdbId, language, cancellationToken).ConfigureAwait(false); @@ -351,7 +351,7 @@ namespace MediaBrowser.Providers.TV var dataFilePath = GetDataFilePath(id, preferredMetadataLanguage); - _fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(dataFilePath)); + Directory.CreateDirectory(Path.GetDirectoryName(dataFilePath)); _jsonSerializer.SerializeToFile(mainResult, dataFilePath); } diff --git a/MediaBrowser.Providers/TV/TheTVDB/TvdbEpisodeProvider.cs b/MediaBrowser.Providers/TV/TheTVDB/TvdbEpisodeProvider.cs index c4edb43ff..25fc214b5 100644 --- a/MediaBrowser.Providers/TV/TheTVDB/TvdbEpisodeProvider.cs +++ b/MediaBrowser.Providers/TV/TheTVDB/TvdbEpisodeProvider.cs @@ -197,7 +197,7 @@ namespace MediaBrowser.Providers.TV if (searchInfo.IndexNumber.HasValue) { - var files = GetEpisodeXmlFiles(searchInfo.SeriesDisplayOrder, searchInfo.ParentIndexNumber, searchInfo.IndexNumber, searchInfo.IndexNumberEnd, _fileSystem.GetDirectoryName(xmlFile)); + var files = GetEpisodeXmlFiles(searchInfo.SeriesDisplayOrder, searchInfo.ParentIndexNumber, searchInfo.IndexNumber, searchInfo.IndexNumberEnd, Path.GetDirectoryName(xmlFile)); list = files.Select(GetXmlReader).ToList(); } @@ -296,7 +296,7 @@ namespace MediaBrowser.Providers.TV private XmlReader GetXmlReader(FileSystemMetadata xmlFile) { - return GetXmlReader(_fileSystem.ReadAllText(xmlFile.FullName, Encoding.UTF8)); + return GetXmlReader(File.ReadAllText(xmlFile.FullName, Encoding.UTF8)); } private XmlReader GetXmlReader(string xml) diff --git a/MediaBrowser.Providers/TV/TheTVDB/TvdbPrescanTask.cs b/MediaBrowser.Providers/TV/TheTVDB/TvdbPrescanTask.cs index c4a132d45..6f7cb72d3 100644 --- a/MediaBrowser.Providers/TV/TheTVDB/TvdbPrescanTask.cs +++ b/MediaBrowser.Providers/TV/TheTVDB/TvdbPrescanTask.cs @@ -82,7 +82,7 @@ namespace MediaBrowser.Providers.TV { var path = TvdbSeriesProvider.GetSeriesDataPath(_config.CommonApplicationPaths); - _fileSystem.CreateDirectory(path); + Directory.CreateDirectory(path); var timestampFile = Path.Combine(path, "time.txt"); @@ -95,7 +95,7 @@ namespace MediaBrowser.Providers.TV } // Find out the last time we queried tvdb for updates - var lastUpdateTime = timestampFileInfo.Exists ? _fileSystem.ReadAllText(timestampFile, Encoding.UTF8) : string.Empty; + var lastUpdateTime = timestampFileInfo.Exists ? File.ReadAllText(timestampFile, Encoding.UTF8) : string.Empty; string newUpdateTime; @@ -171,7 +171,7 @@ namespace MediaBrowser.Providers.TV await UpdateSeries(listToUpdate, path, nullableUpdateValue, progress, cancellationToken).ConfigureAwait(false); } - _fileSystem.WriteAllText(timestampFile, newUpdateTime, Encoding.UTF8); + File.WriteAllText(timestampFile, newUpdateTime, Encoding.UTF8); progress.Report(100); } @@ -390,7 +390,7 @@ namespace MediaBrowser.Providers.TV seriesDataPath = Path.Combine(seriesDataPath, id); - _fileSystem.CreateDirectory(seriesDataPath); + Directory.CreateDirectory(seriesDataPath); return TvdbSeriesProvider.Current.DownloadSeriesZip(id, MetadataProviders.Tvdb.ToString(), null, null, seriesDataPath, lastTvDbUpdateTime, preferredMetadataLanguage, cancellationToken); } diff --git a/MediaBrowser.Providers/TV/TheTVDB/TvdbSeriesProvider.cs b/MediaBrowser.Providers/TV/TheTVDB/TvdbSeriesProvider.cs index b6df64396..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) @@ -263,7 +263,7 @@ namespace MediaBrowser.Providers.TV if (!string.Equals(downloadLangaugeXmlFile, saveAsLanguageXmlFile, StringComparison.OrdinalIgnoreCase)) { - _fileSystem.CopyFile(downloadLangaugeXmlFile, saveAsLanguageXmlFile, true); + File.Copy(downloadLangaugeXmlFile, saveAsLanguageXmlFile, true); } await ExtractEpisodes(seriesDataPath, downloadLangaugeXmlFile, lastTvDbUpdateTime).ConfigureAwait(false); @@ -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) @@ -1526,7 +1526,7 @@ namespace MediaBrowser.Providers.TV var file = Path.Combine(seriesDataPath, string.Format("episode-{0}-{1}.xml", seasonNumber, episodeNumber)); // Only save the file if not already there, or if the episode has changed - if (hasEpisodeChanged || !_fileSystem.FileExists(file)) + if (hasEpisodeChanged || !File.Exists(file)) { using (var fileStream = _fileSystem.GetFileStream(file, FileOpenMode.Create, FileAccessMode.Write, FileShareMode.None, true)) { @@ -1546,7 +1546,7 @@ namespace MediaBrowser.Providers.TV file = Path.Combine(seriesDataPath, string.Format("episode-abs-{0}.xml", absoluteNumber)); // Only save the file if not already there, or if the episode has changed - if (hasEpisodeChanged || !_fileSystem.FileExists(file)) + if (hasEpisodeChanged || !File.Exists(file)) { using (var fileStream = _fileSystem.GetFileStream(file, FileOpenMode.Create, FileAccessMode.Write, FileShareMode.None, true)) { @@ -1567,7 +1567,7 @@ namespace MediaBrowser.Providers.TV file = Path.Combine(seriesDataPath, string.Format("episode-dvd-{0}-{1}.xml", dvdSeasonNumber, dvdEpisodeNumber)); // Only save the file if not already there, or if the episode has changed - if (hasEpisodeChanged || !_fileSystem.FileExists(file)) + if (hasEpisodeChanged || !File.Exists(file)) { using (var fileStream = _fileSystem.GetFileStream(file, FileOpenMode.Create, FileAccessMode.Write, FileShareMode.None, true)) { @@ -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.WebDashboard/Api/DashboardService.cs b/MediaBrowser.WebDashboard/Api/DashboardService.cs index 5405934ce..531978e1d 100644 --- a/MediaBrowser.WebDashboard/Api/DashboardService.cs +++ b/MediaBrowser.WebDashboard/Api/DashboardService.cs @@ -390,7 +390,7 @@ namespace MediaBrowser.WebDashboard.Api { try { - _fileSystem.DeleteDirectory(targetPath, true); + Directory.Delete(targetPath, true); } catch (IOException) { @@ -433,15 +433,15 @@ namespace MediaBrowser.WebDashboard.Api private void CopyDirectory(string source, string destination) { - _fileSystem.CreateDirectory(destination); + Directory.CreateDirectory(destination); //Now Create all of the directories foreach (var dirPath in _fileSystem.GetDirectories(source, true)) - _fileSystem.CreateDirectory(dirPath.FullName.Replace(source, destination)); + Directory.CreateDirectory(dirPath.FullName.Replace(source, destination)); //Copy all the files & Replaces any files with the same name foreach (var newPath in _fileSystem.GetFiles(source, true)) - _fileSystem.CopyFile(newPath.FullName, newPath.FullName.Replace(source, destination), true); + File.Copy(newPath.FullName, newPath.FullName.Replace(source, destination), true); } } diff --git a/MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs b/MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs index 513296745..f20dbbb6e 100644 --- a/MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs +++ b/MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs @@ -108,7 +108,7 @@ namespace MediaBrowser.XbmcMetadata.Parsers { if (!SupportsUrlAfterClosingXmlTag) { - using (var fileStream = FileSystem.OpenRead(metadataFile)) + using (var fileStream = File.OpenRead(metadataFile)) { using (var streamReader = new StreamReader(fileStream, Encoding.UTF8)) { @@ -140,7 +140,7 @@ namespace MediaBrowser.XbmcMetadata.Parsers return; } - using (var fileStream = FileSystem.OpenRead(metadataFile)) + using (var fileStream = File.OpenRead(metadataFile)) { using (var streamReader = new StreamReader(fileStream, Encoding.UTF8)) { diff --git a/MediaBrowser.XbmcMetadata/Parsers/EpisodeNfoParser.cs b/MediaBrowser.XbmcMetadata/Parsers/EpisodeNfoParser.cs index c76f8345a..a8cb6ac40 100644 --- a/MediaBrowser.XbmcMetadata/Parsers/EpisodeNfoParser.cs +++ b/MediaBrowser.XbmcMetadata/Parsers/EpisodeNfoParser.cs @@ -28,7 +28,7 @@ namespace MediaBrowser.XbmcMetadata.Parsers protected override void Fetch(MetadataResult<Episode> item, string metadataFile, XmlReaderSettings settings, CancellationToken cancellationToken) { - using (var fileStream = FileSystem.OpenRead(metadataFile)) + using (var fileStream = File.OpenRead(metadataFile)) { using (var streamReader = new StreamReader(fileStream, Encoding.UTF8)) { diff --git a/MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs b/MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs index 1efffff3d..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", @@ -193,7 +192,7 @@ namespace MediaBrowser.XbmcMetadata.Savers private void SaveToFile(Stream stream, string path) { - FileSystem.CreateDirectory(FileSystem.GetDirectoryName(path)); + Directory.CreateDirectory(Path.GetDirectoryName(path)); // On Windows, savint the file will fail if the file is hidden or readonly FileSystem.SetAttributes(path, false, false); @@ -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)) @@ -974,7 +967,7 @@ namespace MediaBrowser.XbmcMetadata.Savers settings.IgnoreProcessingInstructions = true; settings.IgnoreComments = true; - using (var fileStream = fileSystem.OpenRead(path)) + using (var fileStream = File.OpenRead(path)) { using (var streamReader = new StreamReader(fileStream, Encoding.UTF8)) { @@ -1021,7 +1014,7 @@ namespace MediaBrowser.XbmcMetadata.Savers private string GetTagForProviderKey(string providerKey) { - return providerKey.ToLower() + "id"; + return providerKey.ToLowerInvariant() + "id"; } } } diff --git a/MediaBrowser.XbmcMetadata/Savers/SeasonNfoSaver.cs b/MediaBrowser.XbmcMetadata/Savers/SeasonNfoSaver.cs index 102fba70b..5246bec02 100644 --- a/MediaBrowser.XbmcMetadata/Savers/SeasonNfoSaver.cs +++ b/MediaBrowser.XbmcMetadata/Savers/SeasonNfoSaver.cs @@ -36,7 +36,7 @@ namespace MediaBrowser.XbmcMetadata.Savers return false; } - return updateType >= MinimumUpdateType || (updateType >= ItemUpdateType.MetadataImport && FileSystem.FileExists(GetSavePath(item))); + return updateType >= MinimumUpdateType || (updateType >= ItemUpdateType.MetadataImport && File.Exists(GetSavePath(item))); } protected override void WriteCustomElements(BaseItem item, XmlWriter writer) 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() |
