diff options
172 files changed, 1756 insertions, 1235 deletions
diff --git a/.ci/azure-pipelines-abi.yml b/.ci/azure-pipelines-abi.yml index 8d0737b66..e58a2bdc7 100644 --- a/.ci/azure-pipelines-abi.yml +++ b/.ci/azure-pipelines-abi.yml @@ -7,7 +7,7 @@ parameters: default: "ubuntu-latest" - name: DotNetSdkVersion type: string - default: 5.0.103 + default: 5.0.302 jobs: - job: CompatibilityCheck diff --git a/.ci/azure-pipelines-main.yml b/.ci/azure-pipelines-main.yml index 4bc72f9eb..d2c087c14 100644 --- a/.ci/azure-pipelines-main.yml +++ b/.ci/azure-pipelines-main.yml @@ -1,7 +1,7 @@ parameters: LinuxImage: 'ubuntu-latest' RestoreBuildProjects: 'Jellyfin.Server/Jellyfin.Server.csproj' - DotNetSdkVersion: 5.0.103 + DotNetSdkVersion: 5.0.302 jobs: - job: Build diff --git a/.ci/azure-pipelines-test.yml b/.ci/azure-pipelines-test.yml index 7838b3b02..7ec4cdad1 100644 --- a/.ci/azure-pipelines-test.yml +++ b/.ci/azure-pipelines-test.yml @@ -10,7 +10,7 @@ parameters: default: "tests/**/*Tests.csproj" - name: DotNetSdkVersion type: string - default: 5.0.103 + default: 5.0.302 jobs: - job: Test diff --git a/.ci/azure-pipelines.yml b/.ci/azure-pipelines.yml index c028b6e3e..4e8b6557b 100644 --- a/.ci/azure-pipelines.yml +++ b/.ci/azure-pipelines.yml @@ -6,7 +6,7 @@ variables: - name: RestoreBuildProjects value: 'Jellyfin.Server/Jellyfin.Server.csproj' - name: DotNetSdkVersion - value: 5.0.103 + value: 5.0.302 pr: autoCancel: true diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index b44961bf8..c2d2aff34 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -212,3 +212,4 @@ - [Tim Hobbs](https://github.com/timhobbs) - [SvenVandenbrande](https://github.com/SvenVandenbrande) - [olsh](https://github.com/olsh) + - [gnuyent](https://github.com/gnuyent) diff --git a/Directory.Build.props b/Directory.Build.props new file mode 100644 index 000000000..b899999ef --- /dev/null +++ b/Directory.Build.props @@ -0,0 +1,14 @@ +<Project> + <!-- Sets defaults for all projects in the repo --> + + <PropertyGroup> + <Nullable>enable</Nullable> + <TreatWarningsAsErrors>true</TreatWarningsAsErrors> + <CodeAnalysisRuleSet>$(MSBuildThisFileDirectory)/jellyfin.ruleset</CodeAnalysisRuleSet> + </PropertyGroup> + + <PropertyGroup Condition=" '$(Configuration)' == 'Debug' "> + <AnalysisMode>AllEnabledByDefault</AnalysisMode> + </PropertyGroup> + +</Project> diff --git a/Dockerfile b/Dockerfile index 4e2d06b82..0859fdc4c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -8,15 +8,7 @@ RUN apk add curl git zlib zlib-dev autoconf g++ make libpng-dev gifsicle alpine- && npm ci --no-audit --unsafe-perm \ && mv dist /dist -FROM mcr.microsoft.com/dotnet/sdk:${DOTNET_VERSION} as builder -WORKDIR /repo -COPY . . -ENV DOTNET_CLI_TELEMETRY_OPTOUT=1 -# because of changes in docker and systemd we need to not build in parallel at the moment -# see https://success.docker.com/article/how-to-reserve-resource-temporarily-unavailable-errors-due-to-tasksmax-setting -RUN dotnet publish Jellyfin.Server --disable-parallel --configuration Release --output="/jellyfin" --self-contained --runtime linux-x64 "-p:DebugSymbols=false;DebugType=none" - -FROM debian:buster-slim +FROM debian:buster-slim as app # https://askubuntu.com/questions/972516/debian-frontend-environment-variable ARG DEBIAN_FRONTEND="noninteractive" @@ -25,9 +17,6 @@ ARG APT_KEY_DONT_WARN_ON_DANGEROUS_USAGE=DontWarn # https://github.com/NVIDIA/nvidia-docker/wiki/Installation-(Native-GPU-Support) ENV NVIDIA_DRIVER_CAPABILITIES="compute,video,utility" -COPY --from=builder /jellyfin /jellyfin -COPY --from=web-builder /dist /jellyfin/jellyfin-web - # https://github.com/intel/compute-runtime/releases ARG GMMLIB_VERSION=20.3.2 ARG IGC_VERSION=1.0.5435 @@ -73,6 +62,19 @@ ENV LC_ALL en_US.UTF-8 ENV LANG en_US.UTF-8 ENV LANGUAGE en_US:en +FROM mcr.microsoft.com/dotnet/sdk:${DOTNET_VERSION} as builder +WORKDIR /repo +COPY . . +ENV DOTNET_CLI_TELEMETRY_OPTOUT=1 +# because of changes in docker and systemd we need to not build in parallel at the moment +# see https://success.docker.com/article/how-to-reserve-resource-temporarily-unavailable-errors-due-to-tasksmax-setting +RUN dotnet publish Jellyfin.Server --disable-parallel --configuration Release --output="/jellyfin" --self-contained --runtime linux-x64 "-p:DebugSymbols=false;DebugType=none" + +FROM app + +COPY --from=builder /jellyfin /jellyfin +COPY --from=web-builder /dist /jellyfin/jellyfin-web + EXPOSE 8096 VOLUME /cache /config /media ENTRYPOINT ["./jellyfin/jellyfin", \ diff --git a/Dockerfile.arm b/Dockerfile.arm index 25a0de7db..cc0c79c94 100644 --- a/Dockerfile.arm +++ b/Dockerfile.arm @@ -13,19 +13,8 @@ RUN apk add curl git zlib zlib-dev autoconf g++ make libpng-dev gifsicle alpine- && npm ci --no-audit --unsafe-perm \ && mv dist /dist - -FROM mcr.microsoft.com/dotnet/sdk:${DOTNET_VERSION} as builder -WORKDIR /repo -COPY . . -ENV DOTNET_CLI_TELEMETRY_OPTOUT=1 -# Discard objs - may cause failures if exists -RUN find . -type d -name obj | xargs -r rm -r -# Build -RUN dotnet publish Jellyfin.Server --configuration Release --output="/jellyfin" --self-contained --runtime linux-arm "-p:DebugSymbols=false;DebugType=none" - - FROM multiarch/qemu-user-static:x86_64-arm as qemu -FROM arm32v7/debian:buster-slim +FROM arm32v7/debian:buster-slim as app # https://askubuntu.com/questions/972516/debian-frontend-environment-variable ARG DEBIAN_FRONTEND="noninteractive" @@ -61,14 +50,25 @@ RUN apt-get update \ && chmod 777 /cache /config /media \ && sed -i -e 's/# en_US.UTF-8 UTF-8/en_US.UTF-8 UTF-8/' /etc/locale.gen && locale-gen -COPY --from=builder /jellyfin /jellyfin -COPY --from=web-builder /dist /jellyfin/jellyfin-web - ENV DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=1 ENV LC_ALL en_US.UTF-8 ENV LANG en_US.UTF-8 ENV LANGUAGE en_US:en +FROM mcr.microsoft.com/dotnet/sdk:${DOTNET_VERSION} as builder +WORKDIR /repo +COPY . . +ENV DOTNET_CLI_TELEMETRY_OPTOUT=1 +# Discard objs - may cause failures if exists +RUN find . -type d -name obj | xargs -r rm -r +# Build +RUN dotnet publish Jellyfin.Server --configuration Release --output="/jellyfin" --self-contained --runtime linux-arm "-p:DebugSymbols=false;DebugType=none" + +FROM app + +COPY --from=builder /jellyfin /jellyfin +COPY --from=web-builder /dist /jellyfin/jellyfin-web + EXPOSE 8096 VOLUME /cache /config /media ENTRYPOINT ["./jellyfin/jellyfin", \ diff --git a/Dockerfile.arm64 b/Dockerfile.arm64 index c9f19c5a3..64367a32d 100644 --- a/Dockerfile.arm64 +++ b/Dockerfile.arm64 @@ -13,18 +13,8 @@ RUN apk add curl git zlib zlib-dev autoconf g++ make libpng-dev gifsicle alpine- && npm ci --no-audit --unsafe-perm \ && mv dist /dist - -FROM mcr.microsoft.com/dotnet/sdk:${DOTNET_VERSION} as builder -WORKDIR /repo -COPY . . -ENV DOTNET_CLI_TELEMETRY_OPTOUT=1 -# Discard objs - may cause failures if exists -RUN find . -type d -name obj | xargs -r rm -r -# Build -RUN dotnet publish Jellyfin.Server --configuration Release --output="/jellyfin" --self-contained --runtime linux-arm64 "-p:DebugSymbols=false;DebugType=none" - FROM multiarch/qemu-user-static:x86_64-aarch64 as qemu -FROM arm64v8/debian:buster-slim +FROM arm64v8/debian:buster-slim as app # https://askubuntu.com/questions/972516/debian-frontend-environment-variable ARG DEBIAN_FRONTEND="noninteractive" @@ -50,14 +40,25 @@ RUN apt-get update && apt-get install --no-install-recommends --no-install-sugge && chmod 777 /cache /config /media \ && sed -i -e 's/# en_US.UTF-8 UTF-8/en_US.UTF-8 UTF-8/' /etc/locale.gen && locale-gen -COPY --from=builder /jellyfin /jellyfin -COPY --from=web-builder /dist /jellyfin/jellyfin-web - ENV DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=1 ENV LC_ALL en_US.UTF-8 ENV LANG en_US.UTF-8 ENV LANGUAGE en_US:en +FROM mcr.microsoft.com/dotnet/sdk:${DOTNET_VERSION} as builder +WORKDIR /repo +COPY . . +ENV DOTNET_CLI_TELEMETRY_OPTOUT=1 +# Discard objs - may cause failures if exists +RUN find . -type d -name obj | xargs -r rm -r +# Build +RUN dotnet publish Jellyfin.Server --configuration Release --output="/jellyfin" --self-contained --runtime linux-arm64 "-p:DebugSymbols=false;DebugType=none" + +FROM app + +COPY --from=builder /jellyfin /jellyfin +COPY --from=web-builder /dist /jellyfin/jellyfin-web + EXPOSE 8096 VOLUME /cache /config /media ENTRYPOINT ["./jellyfin/jellyfin", \ diff --git a/DvdLib/DvdLib.csproj b/DvdLib/DvdLib.csproj index 7bbd9acf8..b8301e2f2 100644 --- a/DvdLib/DvdLib.csproj +++ b/DvdLib/DvdLib.csproj @@ -13,7 +13,8 @@ <TargetFramework>net5.0</TargetFramework> <GenerateAssemblyInfo>false</GenerateAssemblyInfo> <GenerateDocumentationFile>true</GenerateDocumentationFile> - <TreatWarningsAsErrors>true</TreatWarningsAsErrors> + <AnalysisMode>AllDisabledByDefault</AnalysisMode> + <Nullable>disable</Nullable> </PropertyGroup> </Project> diff --git a/Emby.Dlna/Configuration/DlnaOptions.cs b/Emby.Dlna/Configuration/DlnaOptions.cs index 5ceeb5530..91fac4bef 100644 --- a/Emby.Dlna/Configuration/DlnaOptions.cs +++ b/Emby.Dlna/Configuration/DlnaOptions.cs @@ -1,5 +1,3 @@ -#nullable disable - #pragma warning disable CS1591 namespace Emby.Dlna.Configuration @@ -74,7 +72,7 @@ namespace Emby.Dlna.Configuration /// <summary> /// Gets or sets the default user account that the dlna server uses. /// </summary> - public string DefaultUserId { get; set; } + public string? DefaultUserId { get; set; } /// <summary> /// Gets or sets a value indicating whether playTo device profiles should be created. diff --git a/Emby.Dlna/ContentDirectory/ContentDirectoryService.cs b/Emby.Dlna/ContentDirectory/ContentDirectoryService.cs index 7b8c50440..9020dea99 100644 --- a/Emby.Dlna/ContentDirectory/ContentDirectoryService.cs +++ b/Emby.Dlna/ContentDirectory/ContentDirectoryService.cs @@ -1,5 +1,3 @@ -#nullable disable - #pragma warning disable CS1591 using System; @@ -140,7 +138,7 @@ namespace Emby.Dlna.ContentDirectory /// </summary> /// <param name="profile">The <see cref="DeviceProfile"/>.</param> /// <returns>The <see cref="User"/>.</returns> - private User GetUser(DeviceProfile profile) + private User? GetUser(DeviceProfile profile) { if (!string.IsNullOrEmpty(profile.UserId)) { diff --git a/Emby.Dlna/ContentDirectory/ControlHandler.cs b/Emby.Dlna/ContentDirectory/ControlHandler.cs index 27c5b2268..ac336e5dc 100644 --- a/Emby.Dlna/ContentDirectory/ControlHandler.cs +++ b/Emby.Dlna/ContentDirectory/ControlHandler.cs @@ -288,21 +288,14 @@ namespace Emby.Dlna.ContentDirectory /// <returns>The xml feature list.</returns> private static string WriteFeatureListXml() { - // TODO: clean this up - var builder = new StringBuilder(); - - builder.Append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>"); - builder.Append("<Features xmlns=\"urn:schemas-upnp-org:av:avs\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"urn:schemas-upnp-org:av:avs http://www.upnp.org/schemas/av/avs.xsd\">"); - - builder.Append("<Feature name=\"samsung.com_BASICVIEW\" version=\"1\">"); - builder.Append("<container id=\"I\" type=\"object.item.imageItem\"/>"); - builder.Append("<container id=\"A\" type=\"object.item.audioItem\"/>"); - builder.Append("<container id=\"V\" type=\"object.item.videoItem\"/>"); - builder.Append("</Feature>"); - - builder.Append("</Features>"); - - return builder.ToString(); + return "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" + + "<Features xmlns=\"urn:schemas-upnp-org:av:avs\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"urn:schemas-upnp-org:av:avs http://www.upnp.org/schemas/av/avs.xsd\">" + + "<Feature name=\"samsung.com_BASICVIEW\" version=\"1\">" + + "<container id=\"I\" type=\"object.item.imageItem\"/>" + + "<container id=\"A\" type=\"object.item.audioItem\"/>" + + "<container id=\"V\" type=\"object.item.videoItem\"/>" + + "</Feature>" + + "</Features>"; } /// <summary> diff --git a/Emby.Dlna/ControlResponse.cs b/Emby.Dlna/ControlResponse.cs index a7f2d4a73..8b0958842 100644 --- a/Emby.Dlna/ControlResponse.cs +++ b/Emby.Dlna/ControlResponse.cs @@ -1,5 +1,3 @@ -#nullable disable - #pragma warning disable CS1591 using System.Collections.Generic; @@ -8,9 +6,11 @@ namespace Emby.Dlna { public class ControlResponse { - public ControlResponse() + public ControlResponse(string xml, bool isSuccessful) { Headers = new Dictionary<string, string>(); + Xml = xml; + IsSuccessful = isSuccessful; } public IDictionary<string, string> Headers { get; } diff --git a/Emby.Dlna/Emby.Dlna.csproj b/Emby.Dlna/Emby.Dlna.csproj index a40578e40..970c16d2e 100644 --- a/Emby.Dlna/Emby.Dlna.csproj +++ b/Emby.Dlna/Emby.Dlna.csproj @@ -20,8 +20,7 @@ <TargetFramework>net5.0</TargetFramework> <GenerateAssemblyInfo>false</GenerateAssemblyInfo> <GenerateDocumentationFile>true</GenerateDocumentationFile> - <TreatWarningsAsErrors>true</TreatWarningsAsErrors> - <Nullable>enable</Nullable> + <AnalysisMode>AllDisabledByDefault</AnalysisMode> </PropertyGroup> <!-- Code Analyzers--> @@ -31,10 +30,6 @@ <PackageReference Include="SmartAnalyzers.MultithreadingAnalyzer" Version="1.1.31" PrivateAssets="All" /> </ItemGroup> - <PropertyGroup Condition=" '$(Configuration)' == 'Debug' "> - <CodeAnalysisRuleSet>../jellyfin.ruleset</CodeAnalysisRuleSet> - </PropertyGroup> - <ItemGroup> <EmbeddedResource Include="Images\logo120.jpg" /> <EmbeddedResource Include="Images\logo120.png" /> diff --git a/Emby.Dlna/EventSubscriptionResponse.cs b/Emby.Dlna/EventSubscriptionResponse.cs index 8c82dcbf6..635d2c47a 100644 --- a/Emby.Dlna/EventSubscriptionResponse.cs +++ b/Emby.Dlna/EventSubscriptionResponse.cs @@ -1,5 +1,3 @@ -#nullable disable - #pragma warning disable CS1591 using System.Collections.Generic; @@ -8,8 +6,10 @@ namespace Emby.Dlna { public class EventSubscriptionResponse { - public EventSubscriptionResponse() + public EventSubscriptionResponse(string content, string contentType) { + Content = content; + ContentType = contentType; Headers = new Dictionary<string, string>(); } diff --git a/Emby.Dlna/Eventing/DlnaEventManager.cs b/Emby.Dlna/Eventing/DlnaEventManager.cs index 2e672b886..3c9136090 100644 --- a/Emby.Dlna/Eventing/DlnaEventManager.cs +++ b/Emby.Dlna/Eventing/DlnaEventManager.cs @@ -51,11 +51,7 @@ namespace Emby.Dlna.Eventing return GetEventSubscriptionResponse(subscriptionId, requestedTimeoutString, timeoutSeconds); } - return new EventSubscriptionResponse - { - Content = string.Empty, - ContentType = "text/plain" - }; + return new EventSubscriptionResponse(string.Empty, "text/plain"); } public EventSubscriptionResponse CreateEventSubscription(string notificationType, string requestedTimeoutString, string callbackUrl) @@ -103,20 +99,12 @@ namespace Emby.Dlna.Eventing _subscriptions.TryRemove(subscriptionId, out _); - return new EventSubscriptionResponse - { - Content = string.Empty, - ContentType = "text/plain" - }; + return new EventSubscriptionResponse(string.Empty, "text/plain"); } private EventSubscriptionResponse GetEventSubscriptionResponse(string subscriptionId, string requestedTimeoutString, int timeoutSeconds) { - var response = new EventSubscriptionResponse - { - Content = string.Empty, - ContentType = "text/plain" - }; + var response = new EventSubscriptionResponse(string.Empty, "text/plain"); response.Headers["SID"] = subscriptionId; response.Headers["TIMEOUT"] = string.IsNullOrEmpty(requestedTimeoutString) ? ("SECOND-" + timeoutSeconds.ToString(_usCulture)) : requestedTimeoutString; diff --git a/Emby.Dlna/PlayTo/Device.cs b/Emby.Dlna/PlayTo/Device.cs index 6c580d15b..11fcd81cf 100644 --- a/Emby.Dlna/PlayTo/Device.cs +++ b/Emby.Dlna/PlayTo/Device.cs @@ -1260,10 +1260,7 @@ namespace Emby.Dlna.PlayTo return; } - PlaybackStart?.Invoke(this, new PlaybackStartEventArgs - { - MediaInfo = mediaInfo - }); + PlaybackStart?.Invoke(this, new PlaybackStartEventArgs(mediaInfo)); } private void OnPlaybackProgress(UBaseObject mediaInfo) @@ -1273,27 +1270,17 @@ namespace Emby.Dlna.PlayTo return; } - PlaybackProgress?.Invoke(this, new PlaybackProgressEventArgs - { - MediaInfo = mediaInfo - }); + PlaybackProgress?.Invoke(this, new PlaybackProgressEventArgs(mediaInfo)); } private void OnPlaybackStop(UBaseObject mediaInfo) { - PlaybackStopped?.Invoke(this, new PlaybackStoppedEventArgs - { - MediaInfo = mediaInfo - }); + PlaybackStopped?.Invoke(this, new PlaybackStoppedEventArgs(mediaInfo)); } private void OnMediaChanged(UBaseObject old, UBaseObject newMedia) { - MediaChanged?.Invoke(this, new MediaChangedEventArgs - { - OldMediaInfo = old, - NewMediaInfo = newMedia - }); + MediaChanged?.Invoke(this, new MediaChangedEventArgs(old, newMedia)); } /// <inheritdoc /> diff --git a/Emby.Dlna/PlayTo/MediaChangedEventArgs.cs b/Emby.Dlna/PlayTo/MediaChangedEventArgs.cs index 2bc4d8cc2..0f7a524d6 100644 --- a/Emby.Dlna/PlayTo/MediaChangedEventArgs.cs +++ b/Emby.Dlna/PlayTo/MediaChangedEventArgs.cs @@ -1,6 +1,4 @@ -#nullable disable - -#pragma warning disable CS1591 +#pragma warning disable CS1591 using System; @@ -8,6 +6,12 @@ namespace Emby.Dlna.PlayTo { public class MediaChangedEventArgs : EventArgs { + public MediaChangedEventArgs(UBaseObject oldMediaInfo, UBaseObject newMediaInfo) + { + OldMediaInfo = oldMediaInfo; + NewMediaInfo = newMediaInfo; + } + public UBaseObject OldMediaInfo { get; set; } public UBaseObject NewMediaInfo { get; set; } diff --git a/Emby.Dlna/PlayTo/PlaybackProgressEventArgs.cs b/Emby.Dlna/PlayTo/PlaybackProgressEventArgs.cs index c7d2b28df..c95d8b1e8 100644 --- a/Emby.Dlna/PlayTo/PlaybackProgressEventArgs.cs +++ b/Emby.Dlna/PlayTo/PlaybackProgressEventArgs.cs @@ -1,5 +1,3 @@ -#nullable disable - #pragma warning disable CS1591 using System; @@ -8,6 +6,11 @@ namespace Emby.Dlna.PlayTo { public class PlaybackProgressEventArgs : EventArgs { + public PlaybackProgressEventArgs(UBaseObject mediaInfo) + { + MediaInfo = mediaInfo; + } + public UBaseObject MediaInfo { get; set; } } } diff --git a/Emby.Dlna/PlayTo/PlaybackStartEventArgs.cs b/Emby.Dlna/PlayTo/PlaybackStartEventArgs.cs index f8a14f411..619c861ed 100644 --- a/Emby.Dlna/PlayTo/PlaybackStartEventArgs.cs +++ b/Emby.Dlna/PlayTo/PlaybackStartEventArgs.cs @@ -1,5 +1,3 @@ -#nullable disable - #pragma warning disable CS1591 using System; @@ -8,6 +6,11 @@ namespace Emby.Dlna.PlayTo { public class PlaybackStartEventArgs : EventArgs { + public PlaybackStartEventArgs(UBaseObject mediaInfo) + { + MediaInfo = mediaInfo; + } + public UBaseObject MediaInfo { get; set; } } } diff --git a/Emby.Dlna/PlayTo/PlaybackStoppedEventArgs.cs b/Emby.Dlna/PlayTo/PlaybackStoppedEventArgs.cs index 6661f92ac..d0ec25059 100644 --- a/Emby.Dlna/PlayTo/PlaybackStoppedEventArgs.cs +++ b/Emby.Dlna/PlayTo/PlaybackStoppedEventArgs.cs @@ -1,5 +1,3 @@ -#nullable disable - #pragma warning disable CS1591 using System; @@ -8,6 +6,11 @@ namespace Emby.Dlna.PlayTo { public class PlaybackStoppedEventArgs : EventArgs { + public PlaybackStoppedEventArgs(UBaseObject mediaInfo) + { + MediaInfo = mediaInfo; + } + public UBaseObject MediaInfo { get; set; } } } diff --git a/Emby.Dlna/Service/BaseControlHandler.cs b/Emby.Dlna/Service/BaseControlHandler.cs index b3ee860f4..581e4a286 100644 --- a/Emby.Dlna/Service/BaseControlHandler.cs +++ b/Emby.Dlna/Service/BaseControlHandler.cs @@ -95,11 +95,7 @@ namespace Emby.Dlna.Service var xml = builder.ToString().Replace("xmlns:m=", "xmlns:u=", StringComparison.Ordinal); - var controlResponse = new ControlResponse - { - Xml = xml, - IsSuccessful = true - }; + var controlResponse = new ControlResponse(xml, true); controlResponse.Headers.Add("EXT", string.Empty); diff --git a/Emby.Dlna/Service/ControlErrorHandler.cs b/Emby.Dlna/Service/ControlErrorHandler.cs index f2b5dd9ca..3e2cd6d2e 100644 --- a/Emby.Dlna/Service/ControlErrorHandler.cs +++ b/Emby.Dlna/Service/ControlErrorHandler.cs @@ -46,11 +46,7 @@ namespace Emby.Dlna.Service writer.WriteEndDocument(); } - return new ControlResponse - { - Xml = builder.ToString(), - IsSuccessful = false - }; + return new ControlResponse(builder.ToString(), false); } } } diff --git a/Emby.Drawing/Emby.Drawing.csproj b/Emby.Drawing/Emby.Drawing.csproj index 5c5afe1c6..baf350c6f 100644 --- a/Emby.Drawing/Emby.Drawing.csproj +++ b/Emby.Drawing/Emby.Drawing.csproj @@ -9,8 +9,7 @@ <TargetFramework>net5.0</TargetFramework> <GenerateAssemblyInfo>false</GenerateAssemblyInfo> <GenerateDocumentationFile>true</GenerateDocumentationFile> - <TreatWarningsAsErrors>true</TreatWarningsAsErrors> - <Nullable>enable</Nullable> + <AnalysisMode>AllDisabledByDefault</AnalysisMode> </PropertyGroup> <ItemGroup> @@ -30,8 +29,4 @@ <PackageReference Include="SmartAnalyzers.MultithreadingAnalyzer" Version="1.1.31" PrivateAssets="All" /> </ItemGroup> - <PropertyGroup Condition=" '$(Configuration)' == 'Debug' "> - <CodeAnalysisRuleSet>../jellyfin.ruleset</CodeAnalysisRuleSet> - </PropertyGroup> - </Project> diff --git a/Emby.Naming/AudioBook/AudioBookInfo.cs b/Emby.Naming/AudioBook/AudioBookInfo.cs index 15702ff2c..acd8905af 100644 --- a/Emby.Naming/AudioBook/AudioBookInfo.cs +++ b/Emby.Naming/AudioBook/AudioBookInfo.cs @@ -15,7 +15,7 @@ namespace Emby.Naming.AudioBook /// <param name="files">List of files composing the actual audiobook.</param> /// <param name="extras">List of extra files.</param> /// <param name="alternateVersions">Alternative version of files.</param> - public AudioBookInfo(string name, int? year, List<AudioBookFileInfo> files, List<AudioBookFileInfo> extras, List<AudioBookFileInfo> alternateVersions) + public AudioBookInfo(string name, int? year, IReadOnlyList<AudioBookFileInfo> files, IReadOnlyList<AudioBookFileInfo> extras, IReadOnlyList<AudioBookFileInfo> alternateVersions) { Name = name; Year = year; @@ -39,18 +39,18 @@ namespace Emby.Naming.AudioBook /// Gets or sets the files. /// </summary> /// <value>The files.</value> - public List<AudioBookFileInfo> Files { get; set; } + public IReadOnlyList<AudioBookFileInfo> Files { get; set; } /// <summary> /// Gets or sets the extras. /// </summary> /// <value>The extras.</value> - public List<AudioBookFileInfo> Extras { get; set; } + public IReadOnlyList<AudioBookFileInfo> Extras { get; set; } /// <summary> /// Gets or sets the alternate versions. /// </summary> /// <value>The alternate versions.</value> - public List<AudioBookFileInfo> AlternateVersions { get; set; } + public IReadOnlyList<AudioBookFileInfo> AlternateVersions { get; set; } } } diff --git a/Emby.Naming/AudioBook/AudioBookListResolver.cs b/Emby.Naming/AudioBook/AudioBookListResolver.cs index ca5322890..1e4a8d2ed 100644 --- a/Emby.Naming/AudioBook/AudioBookListResolver.cs +++ b/Emby.Naming/AudioBook/AudioBookListResolver.cs @@ -87,7 +87,7 @@ namespace Emby.Naming.AudioBook foreach (var audioFile in group) { var name = Path.GetFileNameWithoutExtension(audioFile.Path); - if (name.Equals("audiobook") || + if (name.Equals("audiobook", StringComparison.OrdinalIgnoreCase) || name.Contains(nameParserResult.Name, StringComparison.OrdinalIgnoreCase) || name.Contains(nameWithReplacedDots, StringComparison.OrdinalIgnoreCase)) { diff --git a/Emby.Naming/Common/NamingOptions.cs b/Emby.Naming/Common/NamingOptions.cs index 5f125eb4f..915ce42cc 100644 --- a/Emby.Naming/Common/NamingOptions.cs +++ b/Emby.Naming/Common/NamingOptions.cs @@ -284,7 +284,7 @@ namespace Emby.Naming.Common // Not a Kodi rule as well, but below rule also causes false positives for triple-digit episode names // [bar] Foo - 1 [baz] special case of below expression to prevent false positives with digits in the series name - new EpisodeExpression(@".*?(\[.*?\])+.*?(?<seriesname>[\w\s]+?)[\s_]*-[\s_]*(?<epnumber>[0-9]+).*$") + new EpisodeExpression(@".*[\\\/]?.*?(\[.*?\])+.*?(?<seriesname>[-\w\s]+?)[\s_]*-[\s_]*(?<epnumber>[0-9]+).*$") { IsNamed = true }, diff --git a/Emby.Naming/Emby.Naming.csproj b/Emby.Naming/Emby.Naming.csproj index 3224ff412..07d879e96 100644 --- a/Emby.Naming/Emby.Naming.csproj +++ b/Emby.Naming/Emby.Naming.csproj @@ -1,4 +1,4 @@ -<Project Sdk="Microsoft.NET.Sdk"> +<Project Sdk="Microsoft.NET.Sdk"> <!-- ProjectGuid is only included as a requirement for SonarQube analysis --> <PropertyGroup> @@ -9,12 +9,11 @@ <TargetFramework>net5.0</TargetFramework> <GenerateAssemblyInfo>false</GenerateAssemblyInfo> <GenerateDocumentationFile>true</GenerateDocumentationFile> - <TreatWarningsAsErrors>true</TreatWarningsAsErrors> <PublishRepositoryUrl>true</PublishRepositoryUrl> <EmbedUntrackedSources>true</EmbedUntrackedSources> <IncludeSymbols>true</IncludeSymbols> <SymbolPackageFormat>snupkg</SymbolPackageFormat> - <Nullable>enable</Nullable> + <AnalysisMode>AllDisabledByDefault</AnalysisMode> </PropertyGroup> <PropertyGroup Condition=" '$(Stability)'=='Unstable'"> @@ -50,8 +49,4 @@ <PackageReference Include="SmartAnalyzers.MultithreadingAnalyzer" Version="1.1.31" PrivateAssets="All" /> </ItemGroup> - <PropertyGroup Condition=" '$(Configuration)' == 'Debug' "> - <CodeAnalysisRuleSet>../jellyfin.ruleset</CodeAnalysisRuleSet> - </PropertyGroup> - </Project> diff --git a/Emby.Naming/Video/ExtraResolver.cs b/Emby.Naming/Video/ExtraResolver.cs index 1fade985b..a32af002c 100644 --- a/Emby.Naming/Video/ExtraResolver.cs +++ b/Emby.Naming/Video/ExtraResolver.cs @@ -1,6 +1,5 @@ using System; using System.IO; -using System.Linq; using System.Text.RegularExpressions; using Emby.Naming.Audio; using Emby.Naming.Common; diff --git a/Emby.Naming/Video/VideoListResolver.cs b/Emby.Naming/Video/VideoListResolver.cs index 7da2dcd7a..ed7d511a3 100644 --- a/Emby.Naming/Video/VideoListResolver.cs +++ b/Emby.Naming/Video/VideoListResolver.cs @@ -21,7 +21,7 @@ namespace Emby.Naming.Video /// <param name="namingOptions">The naming options.</param> /// <param name="supportMultiVersion">Indication we should consider multi-versions of content.</param> /// <returns>Returns enumerable of <see cref="VideoInfo"/> which groups files together when related.</returns> - public static IEnumerable<VideoInfo> Resolve(List<FileSystemMetadata> files, NamingOptions namingOptions, bool supportMultiVersion = true) + public static IEnumerable<VideoInfo> Resolve(IEnumerable<FileSystemMetadata> files, NamingOptions namingOptions, bool supportMultiVersion = true) { var videoInfos = files .Select(i => VideoResolver.Resolve(i.FullName, i.IsDirectory, namingOptions)) diff --git a/Emby.Notifications/Emby.Notifications.csproj b/Emby.Notifications/Emby.Notifications.csproj index 5a2aea642..5edcf2f29 100644 --- a/Emby.Notifications/Emby.Notifications.csproj +++ b/Emby.Notifications/Emby.Notifications.csproj @@ -9,10 +9,6 @@ <TargetFramework>net5.0</TargetFramework> <GenerateAssemblyInfo>false</GenerateAssemblyInfo> <GenerateDocumentationFile>true</GenerateDocumentationFile> - <TreatWarningsAsErrors>true</TreatWarningsAsErrors> - <Nullable>enable</Nullable> - <AnalysisMode>AllEnabledByDefault</AnalysisMode> - <CodeAnalysisRuleSet>../jellyfin.ruleset</CodeAnalysisRuleSet> </PropertyGroup> <ItemGroup> diff --git a/Emby.Photos/Emby.Photos.csproj b/Emby.Photos/Emby.Photos.csproj index 2b6618159..00b2f0f94 100644 --- a/Emby.Photos/Emby.Photos.csproj +++ b/Emby.Photos/Emby.Photos.csproj @@ -22,10 +22,6 @@ <TargetFramework>net5.0</TargetFramework> <GenerateAssemblyInfo>false</GenerateAssemblyInfo> <GenerateDocumentationFile>true</GenerateDocumentationFile> - <TreatWarningsAsErrors>true</TreatWarningsAsErrors> - <Nullable>enable</Nullable> - <AnalysisMode>AllEnabledByDefault</AnalysisMode> - <CodeAnalysisRuleSet>../jellyfin.ruleset</CodeAnalysisRuleSet> </PropertyGroup> <!-- Code Analyzers--> diff --git a/Emby.Server.Implementations/Collections/CollectionManager.cs b/Emby.Server.Implementations/Collections/CollectionManager.cs index 4fc33e2ea..08acd1767 100644 --- a/Emby.Server.Implementations/Collections/CollectionManager.cs +++ b/Emby.Server.Implementations/Collections/CollectionManager.cs @@ -82,12 +82,10 @@ namespace Emby.Server.Implementations.Collections internal async Task<Folder> EnsureLibraryFolder(string path, bool createIfNeeded) { - var existingFolders = FindFolders(path) - .ToList(); - - if (existingFolders.Count > 0) + var existingFolder = FindFolders(path).FirstOrDefault(); + if (existingFolder != null) { - return existingFolders[0]; + return existingFolder; } if (!createIfNeeded) diff --git a/Emby.Server.Implementations/Emby.Server.Implementations.csproj b/Emby.Server.Implementations/Emby.Server.Implementations.csproj index fe233df6c..4c9e05821 100644 --- a/Emby.Server.Implementations/Emby.Server.Implementations.csproj +++ b/Emby.Server.Implementations/Emby.Server.Implementations.csproj @@ -44,12 +44,13 @@ <TargetFramework>net5.0</TargetFramework> <GenerateAssemblyInfo>false</GenerateAssemblyInfo> <GenerateDocumentationFile>true</GenerateDocumentationFile> - <TreatWarningsAsErrors Condition=" '$(Configuration)' == 'Release'">true</TreatWarningsAsErrors> - <Nullable>enable</Nullable> <!-- https://github.com/microsoft/ApplicationInsights-dotnet/issues/2047 --> <NoWarn>AD0001</NoWarn> - <AnalysisMode Condition=" '$(Configuration)' == 'Debug' ">AllEnabledByDefault</AnalysisMode> - <CodeAnalysisRuleSet>../jellyfin.ruleset</CodeAnalysisRuleSet> + <TreatWarningsAsErrors>false</TreatWarningsAsErrors> + </PropertyGroup> + + <PropertyGroup Condition=" '$(Configuration)' == 'Release'"> + <TreatWarningsAsErrors>true</TreatWarningsAsErrors> </PropertyGroup> <!-- Code Analyzers--> diff --git a/Emby.Server.Implementations/HttpServer/Security/AuthorizationContext.cs b/Emby.Server.Implementations/HttpServer/Security/AuthorizationContext.cs index 488614609..b2625a68c 100644 --- a/Emby.Server.Implementations/HttpServer/Security/AuthorizationContext.cs +++ b/Emby.Server.Implementations/HttpServer/Security/AuthorizationContext.cs @@ -141,7 +141,7 @@ namespace Emby.Server.Implementations.HttpServer.Security } // Temporary. TODO - allow clients to specify that the token has been shared with a casting device - var allowTokenInfoUpdate = authInfo.Client == null || authInfo.Client.IndexOf("chromecast", StringComparison.OrdinalIgnoreCase) == -1; + var allowTokenInfoUpdate = authInfo.Client == null || !authInfo.Client.Contains("chromecast", StringComparison.OrdinalIgnoreCase); if (string.IsNullOrWhiteSpace(authInfo.Device)) { diff --git a/Emby.Server.Implementations/Localization/Core/ar.json b/Emby.Server.Implementations/Localization/Core/ar.json index 3d6e159b1..be629c8a4 100644 --- a/Emby.Server.Implementations/Localization/Core/ar.json +++ b/Emby.Server.Implementations/Localization/Core/ar.json @@ -118,5 +118,7 @@ "TaskCleanActivityLog": "حذف سجل الأنشطة", "Default": "الإعدادات الافتراضية", "Undefined": "غير معرف", - "Forced": "ملحقة" + "Forced": "ملحقة", + "TaskOptimizeDatabaseDescription": "يضغط قاعدة البيانات ويقتطع المساحة الحرة. تشغيل هذه المهمة بعد فحص المكتبة أو إجراء تغييرات أخرى تشير ضمنًا إلى أن تعديلات قاعدة البيانات قد تؤدي إلى تحسين الأداء.", + "TaskOptimizeDatabase": "تحسين قاعدة البيانات" } diff --git a/Emby.Server.Implementations/Localization/Core/bg-BG.json b/Emby.Server.Implementations/Localization/Core/bg-BG.json index bc25531d3..f55287d15 100644 --- a/Emby.Server.Implementations/Localization/Core/bg-BG.json +++ b/Emby.Server.Implementations/Localization/Core/bg-BG.json @@ -8,7 +8,7 @@ "CameraImageUploadedFrom": "Нова снимка от камера беше качена от {0}", "Channels": "Канали", "ChapterNameValue": "Глава {0}", - "Collections": "Поредици", + "Collections": "Колекции", "DeviceOfflineWithName": "{0} се разкачи", "DeviceOnlineWithName": "{0} е свързан", "FailedLoginAttemptWithUserName": "Неуспешен опит за влизане от {0}", @@ -29,13 +29,13 @@ "Inherit": "Наследяване", "ItemAddedWithName": "{0} е добавено към библиотеката", "ItemRemovedWithName": "{0} е премахнато от библиотеката", - "LabelIpAddressValue": "ИП адрес: {0}", - "LabelRunningTimeValue": "Стартирано от: {0}", + "LabelIpAddressValue": "IP адрес: {0}", + "LabelRunningTimeValue": "Продължителност: {0}", "Latest": "Последни", - "MessageApplicationUpdated": "Сървърът е обновен", - "MessageApplicationUpdatedTo": "Сървърът е обновен до {0}", - "MessageNamedServerConfigurationUpdatedWithValue": "Секцията {0} от сървърната конфигурация се актуализира", - "MessageServerConfigurationUpdated": "Конфигурацията на сървъра се актуализира", + "MessageApplicationUpdated": "Сървърът беше обновен", + "MessageApplicationUpdatedTo": "Сървърът беше обновен до {0}", + "MessageNamedServerConfigurationUpdatedWithValue": "Секцията {0} от сървърната конфигурация беше актуализирана", + "MessageServerConfigurationUpdated": "Конфигурацията на сървъра беше актуализирана", "MixedContent": "Смесено съдържание", "Movies": "Филми", "Music": "Музика", @@ -118,5 +118,7 @@ "Forced": "Принудително", "Default": "По подразбиране", "TaskCleanActivityLogDescription": "Изтрива записите в дневника с активност по стари от конфигурираната възраст.", - "TaskCleanActivityLog": "Изчисти дневника с активност" + "TaskCleanActivityLog": "Изчисти дневника с активност", + "TaskOptimizeDatabaseDescription": "Прави базата данни по-компактна и освобождава място. Пускането на тази задача след сканиране на библиотеката или правене на други промени, свързани с модификации на базата данни, може да подобри производителността.", + "TaskOptimizeDatabase": "Оптимизирай базата данни" } diff --git a/Emby.Server.Implementations/Localization/Core/da.json b/Emby.Server.Implementations/Localization/Core/da.json index 3453507d9..b2c484a31 100644 --- a/Emby.Server.Implementations/Localization/Core/da.json +++ b/Emby.Server.Implementations/Localization/Core/da.json @@ -118,5 +118,7 @@ "TaskCleanActivityLog": "Ryd Aktivitetslog", "Undefined": "Udefineret", "Forced": "Tvunget", - "Default": "Standard" + "Default": "Standard", + "TaskOptimizeDatabaseDescription": "Kompakter database og forkorter fri plads. Ved at køre denne proces efter at scanne biblioteket eller efter at ændre noget som kunne have indflydelse på databasen, kan forbedre ydeevne.", + "TaskOptimizeDatabase": "Optimér database" } diff --git a/Emby.Server.Implementations/Localization/Core/es.json b/Emby.Server.Implementations/Localization/Core/es.json index 91939843f..7d42182b0 100644 --- a/Emby.Server.Implementations/Localization/Core/es.json +++ b/Emby.Server.Implementations/Localization/Core/es.json @@ -70,7 +70,7 @@ "ScheduledTaskFailedWithName": "{0} falló", "ScheduledTaskStartedWithName": "{0} iniciada", "ServerNameNeedsToBeRestarted": "{0} necesita ser reiniciado", - "Shows": "Series de Televisión", + "Shows": "Series", "Songs": "Canciones", "StartupEmbyServerIsLoading": "Jellyfin Server se está cargando. Vuelve a intentarlo en breve.", "SubtitleDownloadFailureForItem": "Error al descargar subtítulos para {0}", diff --git a/Emby.Server.Implementations/Localization/Core/it.json b/Emby.Server.Implementations/Localization/Core/it.json index 8b753400e..0bde76e74 100644 --- a/Emby.Server.Implementations/Localization/Core/it.json +++ b/Emby.Server.Implementations/Localization/Core/it.json @@ -70,7 +70,7 @@ "ScheduledTaskFailedWithName": "{0} fallito", "ScheduledTaskStartedWithName": "{0} avviati", "ServerNameNeedsToBeRestarted": "{0} deve essere riavviato", - "Shows": "Programmi", + "Shows": "Serie TV", "Songs": "Canzoni", "StartupEmbyServerIsLoading": "Jellyfin server si sta avviando. Per favore riprova più tardi.", "SubtitleDownloadFailureForItem": "Impossibile scaricare i sottotitoli per {0}", diff --git a/Emby.Server.Implementations/Localization/Core/ja.json b/Emby.Server.Implementations/Localization/Core/ja.json index fa0ab8b92..0d90ad31c 100644 --- a/Emby.Server.Implementations/Localization/Core/ja.json +++ b/Emby.Server.Implementations/Localization/Core/ja.json @@ -117,5 +117,7 @@ "TaskCleanActivityLog": "アクティビティの履歴を消去", "Undefined": "未定義", "Forced": "強制", - "Default": "デフォルト" + "Default": "デフォルト", + "TaskOptimizeDatabaseDescription": "データベースをコンパクトにして、空き領域を切り詰めます。メディアライブラリのスキャン後でこのタスクを実行するとパフォーマンスが向上する可能性があります。", + "TaskOptimizeDatabase": "データベースの最適化" } diff --git a/Emby.Server.Implementations/Localization/Core/lv.json b/Emby.Server.Implementations/Localization/Core/lv.json index a46bdc3de..443a74a10 100644 --- a/Emby.Server.Implementations/Localization/Core/lv.json +++ b/Emby.Server.Implementations/Localization/Core/lv.json @@ -117,5 +117,7 @@ "TaskCleanActivityLogDescription": "Nodzēš darbību žurnāla ierakstus, kuri ir vecāki par doto vecumu.", "TaskCleanActivityLog": "Notīrīt Darbību Žurnālu", "Undefined": "Nenoteikts", - "Default": "Noklusējums" + "Default": "Noklusējums", + "TaskOptimizeDatabaseDescription": "Saspiež datubāzi un atbrīvo atmiņu. Uzdevum palaišana pēc bibliotēku skenēšanas vai citām, ar datubāzi saistītām, izmaiņām iespējams uzlabos ātrdarbību.", + "TaskOptimizeDatabase": "Optimizēt datubāzi" } diff --git a/Emby.Server.Implementations/Localization/Core/nb.json b/Emby.Server.Implementations/Localization/Core/nb.json index fbe1f7c4d..81c1eefe7 100644 --- a/Emby.Server.Implementations/Localization/Core/nb.json +++ b/Emby.Server.Implementations/Localization/Core/nb.json @@ -118,5 +118,6 @@ "Undefined": "Udefinert", "Forced": "Tvunget", "Default": "Standard", - "TaskCleanActivityLogDescription": "Sletter oppføringer i aktivitetsloggen som er eldre enn den konfigurerte alderen." + "TaskCleanActivityLogDescription": "Sletter oppføringer i aktivitetsloggen som er eldre enn den konfigurerte alderen.", + "TaskOptimizeDatabase": "Optimiser database" } diff --git a/Emby.Server.Implementations/Localization/Core/sl-SI.json b/Emby.Server.Implementations/Localization/Core/sl-SI.json index 1852dc89e..a6fcbd3e2 100644 --- a/Emby.Server.Implementations/Localization/Core/sl-SI.json +++ b/Emby.Server.Implementations/Localization/Core/sl-SI.json @@ -16,7 +16,7 @@ "Folders": "Mape", "Genres": "Zvrsti", "HeaderAlbumArtists": "Izvajalci albuma", - "HeaderContinueWatching": "Nadaljuj z ogledom", + "HeaderContinueWatching": "Nadaljuj ogled", "HeaderFavoriteAlbums": "Priljubljeni albumi", "HeaderFavoriteArtists": "Priljubljeni izvajalci", "HeaderFavoriteEpisodes": "Priljubljene epizode", @@ -90,7 +90,7 @@ "UserStartedPlayingItemWithValues": "{0} predvaja {1} na {2}", "UserStoppedPlayingItemWithValues": "{0} je nehal predvajati {1} na {2}", "ValueHasBeenAddedToLibrary": "{0} je bil dodan vaši knjižnici", - "ValueSpecialEpisodeName": "Posebna - {0}", + "ValueSpecialEpisodeName": "Bonus - {0}", "VersionNumber": "Različica {0}", "TaskDownloadMissingSubtitles": "Prenesi manjkajoče podnapise", "TaskRefreshChannelsDescription": "Osveži podatke spletnih kanalov.", diff --git a/Emby.Server.Implementations/Localization/Core/tr.json b/Emby.Server.Implementations/Localization/Core/tr.json index c6b904045..771c91d59 100644 --- a/Emby.Server.Implementations/Localization/Core/tr.json +++ b/Emby.Server.Implementations/Localization/Core/tr.json @@ -43,7 +43,7 @@ "NameInstallFailed": "{0} kurulumu başarısız", "NameSeasonNumber": "Sezon {0}", "NameSeasonUnknown": "Bilinmeyen Sezon", - "NewVersionIsAvailable": "Jellyfin Sunucusunun yeni bir versiyonu indirmek için hazır.", + "NewVersionIsAvailable": "Jellyfin Sunucusunun yeni bir sürümü indirmek için hazır.", "NotificationOptionApplicationUpdateAvailable": "Uygulama güncellemesi mevcut", "NotificationOptionApplicationUpdateInstalled": "Uygulama güncellemesi yüklendi", "NotificationOptionAudioPlayback": "Ses çalma başladı", @@ -75,7 +75,7 @@ "StartupEmbyServerIsLoading": "Jellyfin Sunucusu yükleniyor. Lütfen kısa süre sonra tekrar deneyin.", "SubtitleDownloadFailureForItem": "Subtitles failed to download for {0}", "SubtitleDownloadFailureFromForItem": "{1} için alt yazılar {0} 'dan indirilemedi", - "Sync": "Eşitle", + "Sync": "Eşzamanlama", "System": "Sistem", "TvShows": "Diziler", "User": "Kullanıcı", @@ -89,34 +89,36 @@ "UserPolicyUpdatedWithName": "Kullanıcı politikası {0} için güncellendi", "UserStartedPlayingItemWithValues": "{0}, {2} cihazında {1} izliyor", "UserStoppedPlayingItemWithValues": "{0}, {2} cihazında {1} izlemeyi bitirdi", - "ValueHasBeenAddedToLibrary": "Medya kitaplığınıza {0} eklendi", + "ValueHasBeenAddedToLibrary": "Medya kütüphanenize {0} eklendi", "ValueSpecialEpisodeName": "Özel - {0}", - "VersionNumber": "Versiyon {0}", + "VersionNumber": "Sürüm {0}", "TaskCleanCache": "Geçici dosya klasörünü temizle", "TasksChannelsCategory": "İnternet kanalları", "TasksApplicationCategory": "Uygulama", "TasksLibraryCategory": "Kütüphane", - "TasksMaintenanceCategory": "Onarım", + "TasksMaintenanceCategory": "Bakım", "TaskRefreshPeopleDescription": "Medya kütüphanenizdeki videoların oyuncu ve yönetmen bilgilerini günceller.", "TaskDownloadMissingSubtitlesDescription": "Metadata ayarlarını baz alarak eksik altyazıları internette arar.", "TaskDownloadMissingSubtitles": "Eksik altyazıları indir", "TaskRefreshChannelsDescription": "Internet kanal bilgilerini yenile.", "TaskRefreshChannels": "Kanalları Yenile", - "TaskCleanTranscodeDescription": "Bir günü dolmuş dönüştürme bilgisi içeren dosyaları siler.", + "TaskCleanTranscodeDescription": "Bir günden daha eski dönüştürme dosyalarını siler.", "TaskCleanTranscode": "Dönüşüm Dizinini Temizle", "TaskUpdatePluginsDescription": "Otomatik güncellenmeye ayarlanmış eklentilerin güncellemelerini indirir ve kurar.", "TaskUpdatePlugins": "Eklentileri Güncelle", "TaskRefreshPeople": "Kullanıcıları Yenile", - "TaskCleanLogsDescription": "{0} günden eski log dosyalarını siler.", - "TaskCleanLogs": "Log Dizinini Temizle", - "TaskRefreshLibraryDescription": "Medya kütüphanenize eklenen yeni dosyaları arar ve bilgileri yeniler.", + "TaskCleanLogsDescription": "{0} günden eski günlük dosyalarını siler.", + "TaskCleanLogs": "Günlük Dizinini Temizle", + "TaskRefreshLibraryDescription": "Medya kütüphanenize eklenen yeni dosyaları arar ve ortam bilgilerini yeniler.", "TaskRefreshLibrary": "Medya Kütüphanesini Tara", "TaskRefreshChapterImagesDescription": "Sahnelere ayrılmış videolar için küçük resimler oluştur.", "TaskRefreshChapterImages": "Bölüm Resimlerini Çıkar", "TaskCleanCacheDescription": "Sistem tarafından artık ihtiyaç duyulmayan önbellek dosyalarını siler.", - "TaskCleanActivityLog": "İşlem Günlüğünü Temizle", - "TaskCleanActivityLogDescription": "Belirtilen sureden daha eski etkinlik log kayıtları silindi.", + "TaskCleanActivityLog": "Etkinlik Günlüğünü Temizle", + "TaskCleanActivityLogDescription": "Yapılandırılan tarihten daha eski olan etkinlik günlüğü girişlerini siler.", "Undefined": "Bilinmeyen", "Default": "Varsayılan", - "Forced": "Zorla" + "Forced": "Zorla", + "TaskOptimizeDatabaseDescription": "Veritabanını sıkıştırır ve boş alanı keser. Kitaplığı taradıktan sonra veya veritabanında değişiklik anlamına gelen diğer işlemleri yaptıktan sonra bu görevi çalıştırmak performansı artırabilir.", + "TaskOptimizeDatabase": "Veritabanını optimize et" } diff --git a/Emby.Server.Implementations/Localization/LocalizationManager.cs b/Emby.Server.Implementations/Localization/LocalizationManager.cs index a9e3bfdb0..9808e47de 100644 --- a/Emby.Server.Implementations/Localization/LocalizationManager.cs +++ b/Emby.Server.Implementations/Localization/LocalizationManager.cs @@ -23,6 +23,9 @@ namespace Emby.Server.Implementations.Localization public class LocalizationManager : ILocalizationManager { private const string DefaultCulture = "en-US"; + private const string RatingsPath = "Emby.Server.Implementations.Localization.Ratings."; + private const string CulturesPath = "Emby.Server.Implementations.Localization.iso6392.txt"; + private const string CountriesPath = "Emby.Server.Implementations.Localization.countries.json"; private static readonly Assembly _assembly = typeof(LocalizationManager).Assembly; private static readonly string[] _unratedValues = { "n/a", "unrated", "not rated" }; @@ -58,43 +61,39 @@ namespace Emby.Server.Implementations.Localization /// <returns><see cref="Task" />.</returns> public async Task LoadAll() { - const string RatingsResource = "Emby.Server.Implementations.Localization.Ratings."; - // Extract from the assembly foreach (var resource in _assembly.GetManifestResourceNames()) { - if (!resource.StartsWith(RatingsResource, StringComparison.Ordinal)) + if (!resource.StartsWith(RatingsPath, StringComparison.Ordinal)) { continue; } - string countryCode = resource.Substring(RatingsResource.Length, 2); + string countryCode = resource.Substring(RatingsPath.Length, 2); var dict = new Dictionary<string, ParentalRating>(StringComparer.OrdinalIgnoreCase); - using (var str = _assembly.GetManifestResourceStream(resource)) - using (var reader = new StreamReader(str)) + await using var str = _assembly.GetManifestResourceStream(resource); + using var reader = new StreamReader(str); + await foreach (var line in reader.ReadAllLinesAsync().ConfigureAwait(false)) { - await foreach (var line in reader.ReadAllLinesAsync().ConfigureAwait(false)) + if (string.IsNullOrWhiteSpace(line)) { - if (string.IsNullOrWhiteSpace(line)) - { - continue; - } - - string[] parts = line.Split(','); - if (parts.Length == 2 - && int.TryParse(parts[1], NumberStyles.Integer, CultureInfo.InvariantCulture, out var value)) - { - var name = parts[0]; - dict.Add(name, new ParentalRating(name, value)); - } + continue; + } + + string[] parts = line.Split(','); + if (parts.Length == 2 + && int.TryParse(parts[1], NumberStyles.Integer, CultureInfo.InvariantCulture, out var value)) + { + var name = parts[0]; + dict.Add(name, new ParentalRating(name, value)); + } #if DEBUG - else - { - _logger.LogWarning("Malformed line in ratings file for country {CountryCode}", countryCode); - } -#endif + else + { + _logger.LogWarning("Malformed line in ratings file for country {CountryCode}", countryCode); } +#endif } _allParentalRatings[countryCode] = dict; @@ -114,52 +113,48 @@ namespace Emby.Server.Implementations.Localization { List<CultureDto> list = new List<CultureDto>(); - const string ResourcePath = "Emby.Server.Implementations.Localization.iso6392.txt"; - - using (var stream = _assembly.GetManifestResourceStream(ResourcePath)) - using (var reader = new StreamReader(stream)) + await using var stream = _assembly.GetManifestResourceStream(CulturesPath); + using var reader = new StreamReader(stream); + await foreach (var line in reader.ReadAllLinesAsync().ConfigureAwait(false)) { - await foreach (var line in reader.ReadAllLinesAsync().ConfigureAwait(false)) + if (string.IsNullOrWhiteSpace(line)) { - if (string.IsNullOrWhiteSpace(line)) + continue; + } + + var parts = line.Split('|'); + + if (parts.Length == 5) + { + string name = parts[3]; + if (string.IsNullOrWhiteSpace(name)) { continue; } - var parts = line.Split('|'); + string twoCharName = parts[2]; + if (string.IsNullOrWhiteSpace(twoCharName)) + { + continue; + } - if (parts.Length == 5) + string[] threeletterNames; + if (string.IsNullOrWhiteSpace(parts[1])) + { + threeletterNames = new[] { parts[0] }; + } + else { - string name = parts[3]; - if (string.IsNullOrWhiteSpace(name)) - { - continue; - } - - string twoCharName = parts[2]; - if (string.IsNullOrWhiteSpace(twoCharName)) - { - continue; - } - - string[] threeletterNames; - if (string.IsNullOrWhiteSpace(parts[1])) - { - threeletterNames = new[] { parts[0] }; - } - else - { - threeletterNames = new[] { parts[0], parts[1] }; - } - - list.Add(new CultureDto - { - DisplayName = name, - Name = name, - ThreeLetterISOLanguageNames = threeletterNames, - TwoLetterISOLanguageName = twoCharName - }); + threeletterNames = new[] { parts[0], parts[1] }; } + + list.Add(new CultureDto + { + DisplayName = name, + Name = name, + ThreeLetterISOLanguageNames = threeletterNames, + TwoLetterISOLanguageName = twoCharName + }); } } @@ -188,7 +183,7 @@ namespace Emby.Server.Implementations.Localization /// <inheritdoc /> public IEnumerable<CountryInfo> GetCountries() { - using StreamReader reader = new StreamReader(_assembly.GetManifestResourceStream("Emby.Server.Implementations.Localization.countries.json")); + using StreamReader reader = new StreamReader(_assembly.GetManifestResourceStream(CountriesPath)); return JsonSerializer.Deserialize<IEnumerable<CountryInfo>>(reader.ReadToEnd(), _jsonOptions); } @@ -350,23 +345,21 @@ namespace Emby.Server.Implementations.Localization private async Task CopyInto(IDictionary<string, string> dictionary, string resourcePath) { - using (var stream = _assembly.GetManifestResourceStream(resourcePath)) + await using var stream = _assembly.GetManifestResourceStream(resourcePath); + // If a Culture doesn't have a translation the stream will be null and it defaults to en-us further up the chain + if (stream != null) { - // If a Culture doesn't have a translation the stream will be null and it defaults to en-us further up the chain - if (stream != null) - { - var dict = await JsonSerializer.DeserializeAsync<Dictionary<string, string>>(stream, _jsonOptions).ConfigureAwait(false); + var dict = await JsonSerializer.DeserializeAsync<Dictionary<string, string>>(stream, _jsonOptions).ConfigureAwait(false); - foreach (var key in dict.Keys) - { - dictionary[key] = dict[key]; - } - } - else + foreach (var key in dict.Keys) { - _logger.LogError("Missing translation/culture resource: {ResourcePath}", resourcePath); + dictionary[key] = dict[key]; } } + else + { + _logger.LogError("Missing translation/culture resource: {ResourcePath}", resourcePath); + } } private static string GetResourceFilename(string culture) diff --git a/Emby.Server.Implementations/ScheduledTasks/Tasks/ChapterImagesTask.cs b/Emby.Server.Implementations/ScheduledTasks/Tasks/ChapterImagesTask.cs index baeb86a22..b764a139c 100644 --- a/Emby.Server.Implementations/ScheduledTasks/Tasks/ChapterImagesTask.cs +++ b/Emby.Server.Implementations/ScheduledTasks/Tasks/ChapterImagesTask.cs @@ -55,9 +55,19 @@ namespace Emby.Server.Implementations.ScheduledTasks _localization = localization; } - /// <summary> - /// Creates the triggers that define when the task will run. - /// </summary> + /// <inheritdoc /> + public string Name => _localization.GetLocalizedString("TaskRefreshChapterImages"); + + /// <inheritdoc /> + public string Description => _localization.GetLocalizedString("TaskRefreshChapterImagesDescription"); + + /// <inheritdoc /> + public string Category => _localization.GetLocalizedString("TasksLibraryCategory"); + + /// <inheritdoc /> + public string Key => "RefreshChapterImages"; + + /// <inheritdoc /> public IEnumerable<TaskTriggerInfo> GetDefaultTriggers() { return new[] @@ -162,26 +172,5 @@ namespace Emby.Server.Implementations.ScheduledTasks } } } - - /// <inheritdoc /> - public string Name => _localization.GetLocalizedString("TaskRefreshChapterImages"); - - /// <inheritdoc /> - public string Description => _localization.GetLocalizedString("TaskRefreshChapterImagesDescription"); - - /// <inheritdoc /> - public string Category => _localization.GetLocalizedString("TasksLibraryCategory"); - - /// <inheritdoc /> - public string Key => "RefreshChapterImages"; - - /// <inheritdoc /> - public bool IsHidden => false; - - /// <inheritdoc /> - public bool IsEnabled => true; - - /// <inheritdoc /> - public bool IsLogged => true; } } diff --git a/Jellyfin.Api/Helpers/TranscodingJobHelper.cs b/Jellyfin.Api/Helpers/TranscodingJobHelper.cs index c295af7eb..05fa5b135 100644 --- a/Jellyfin.Api/Helpers/TranscodingJobHelper.cs +++ b/Jellyfin.Api/Helpers/TranscodingJobHelper.cs @@ -380,7 +380,7 @@ namespace Jellyfin.Api.Helpers private void DeleteHlsPartialStreamFiles(string outputFilePath) { var directory = Path.GetDirectoryName(outputFilePath) - ?? throw new ArgumentException("Path can't be a root directory.", nameof(outputFilePath)); + ?? throw new ArgumentException("Path can't be a root directory.", nameof(outputFilePath)); var name = Path.GetFileNameWithoutExtension(outputFilePath); @@ -444,6 +444,10 @@ namespace Jellyfin.Api.Helpers { var audioCodec = state.ActualOutputAudioCodec; var videoCodec = state.ActualOutputVideoCodec; + var hardwareAccelerationTypeString = _serverConfigurationManager.GetEncodingOptions().HardwareAccelerationType; + HardwareEncodingType? hardwareAccelerationType = string.IsNullOrEmpty(hardwareAccelerationTypeString) + ? null + : (HardwareEncodingType)Enum.Parse(typeof(HardwareEncodingType), hardwareAccelerationTypeString, true); _sessionManager.ReportTranscodingInfo(deviceId, new TranscodingInfo { @@ -458,6 +462,7 @@ namespace Jellyfin.Api.Helpers AudioChannels = state.OutputAudioChannels, IsAudioDirect = EncodingHelper.IsCopyCodec(state.OutputAudioCodec), IsVideoDirect = EncodingHelper.IsCopyCodec(state.OutputVideoCodec), + HardwareAccelerationType = hardwareAccelerationType, TranscodeReasons = state.TranscodeReasons }); } @@ -759,8 +764,8 @@ namespace Jellyfin.Api.Helpers if (state.MediaSource.RequiresOpening && string.IsNullOrWhiteSpace(state.Request.LiveStreamId)) { var liveStreamResponse = await _mediaSourceManager.OpenLiveStream( - new LiveStreamRequest { OpenToken = state.MediaSource.OpenToken }, - cancellationTokenSource.Token) + new LiveStreamRequest { OpenToken = state.MediaSource.OpenToken }, + cancellationTokenSource.Token) .ConfigureAwait(false); var encodingOptions = _serverConfigurationManager.GetEncodingOptions(); diff --git a/Jellyfin.Api/Jellyfin.Api.csproj b/Jellyfin.Api/Jellyfin.Api.csproj index d1d0ac708..a527282d1 100644 --- a/Jellyfin.Api/Jellyfin.Api.csproj +++ b/Jellyfin.Api/Jellyfin.Api.csproj @@ -8,17 +8,16 @@ <PropertyGroup> <TargetFramework>net5.0</TargetFramework> <GenerateDocumentationFile>true</GenerateDocumentationFile> - <TreatWarningsAsErrors>true</TreatWarningsAsErrors> - <Nullable>enable</Nullable> <!-- https://github.com/microsoft/ApplicationInsights-dotnet/issues/2047 --> <NoWarn>AD0001</NoWarn> + <AnalysisMode>AllDisabledByDefault</AnalysisMode> </PropertyGroup> <ItemGroup> <PackageReference Include="Microsoft.AspNetCore.Authorization" Version="5.0.8" /> <PackageReference Include="Microsoft.Extensions.Http" Version="5.0.0" /> - <PackageReference Include="Swashbuckle.AspNetCore" Version="6.1.4" /> - <PackageReference Include="Swashbuckle.AspNetCore.ReDoc" Version="6.1.4" /> + <PackageReference Include="Swashbuckle.AspNetCore" Version="6.1.5" /> + <PackageReference Include="Swashbuckle.AspNetCore.ReDoc" Version="6.1.5" /> </ItemGroup> <ItemGroup> @@ -33,10 +32,6 @@ <PackageReference Include="SmartAnalyzers.MultithreadingAnalyzer" Version="1.1.31" PrivateAssets="All" /> </ItemGroup> - <PropertyGroup Condition=" '$(Configuration)' == 'Debug' "> - <CodeAnalysisRuleSet>../jellyfin.ruleset</CodeAnalysisRuleSet> - </PropertyGroup> - <ItemGroup> <AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleTo"> <_Parameter1>Jellyfin.Api.Tests</_Parameter1> diff --git a/Jellyfin.Data/Jellyfin.Data.csproj b/Jellyfin.Data/Jellyfin.Data.csproj index 3b14d3312..65bbd49da 100644 --- a/Jellyfin.Data/Jellyfin.Data.csproj +++ b/Jellyfin.Data/Jellyfin.Data.csproj @@ -4,10 +4,6 @@ <TargetFramework>net5.0</TargetFramework> <GenerateAssemblyInfo>false</GenerateAssemblyInfo> <GenerateDocumentationFile>true</GenerateDocumentationFile> - <TreatWarningsAsErrors>true</TreatWarningsAsErrors> - <AnalysisMode>AllEnabledByDefault</AnalysisMode> - <CodeAnalysisRuleSet>../jellyfin.ruleset</CodeAnalysisRuleSet> - <Nullable>enable</Nullable> <PublishRepositoryUrl>true</PublishRepositoryUrl> <EmbedUntrackedSources>true</EmbedUntrackedSources> <IncludeSymbols>true</IncludeSymbols> diff --git a/Jellyfin.Drawing.Skia/Jellyfin.Drawing.Skia.csproj b/Jellyfin.Drawing.Skia/Jellyfin.Drawing.Skia.csproj index 96fe00384..8cee5dcae 100644 --- a/Jellyfin.Drawing.Skia/Jellyfin.Drawing.Skia.csproj +++ b/Jellyfin.Drawing.Skia/Jellyfin.Drawing.Skia.csproj @@ -9,10 +9,6 @@ <TargetFramework>net5.0</TargetFramework> <GenerateAssemblyInfo>false</GenerateAssemblyInfo> <GenerateDocumentationFile>true</GenerateDocumentationFile> - <TreatWarningsAsErrors>true</TreatWarningsAsErrors> - <Nullable>enable</Nullable> - <AnalysisMode>AllEnabledByDefault</AnalysisMode> - <CodeAnalysisRuleSet>../jellyfin.ruleset</CodeAnalysisRuleSet> </PropertyGroup> <ItemGroup> diff --git a/Jellyfin.Networking/Jellyfin.Networking.csproj b/Jellyfin.Networking/Jellyfin.Networking.csproj index 63557e91f..227a41ce4 100644 --- a/Jellyfin.Networking/Jellyfin.Networking.csproj +++ b/Jellyfin.Networking/Jellyfin.Networking.csproj @@ -3,10 +3,6 @@ <TargetFramework>net5.0</TargetFramework> <GenerateAssemblyInfo>false</GenerateAssemblyInfo> <GenerateDocumentationFile>true</GenerateDocumentationFile> - <TreatWarningsAsErrors>true</TreatWarningsAsErrors> - <Nullable>enable</Nullable> - <AnalysisMode>AllEnabledByDefault</AnalysisMode> - <CodeAnalysisRuleSet>../jellyfin.ruleset</CodeAnalysisRuleSet> </PropertyGroup> <ItemGroup> diff --git a/Jellyfin.Server.Implementations/Activity/ActivityManager.cs b/Jellyfin.Server.Implementations/Activity/ActivityManager.cs index 27360afb0..a3a2a8baf 100644 --- a/Jellyfin.Server.Implementations/Activity/ActivityManager.cs +++ b/Jellyfin.Server.Implementations/Activity/ActivityManager.cs @@ -86,15 +86,12 @@ namespace Jellyfin.Server.Implementations.Activity private static ActivityLogEntry ConvertToOldModel(ActivityLog entry) { - return new ActivityLogEntry + return new ActivityLogEntry(entry.Name, entry.Type, entry.UserId) { Id = entry.Id, - Name = entry.Name, Overview = entry.Overview, ShortOverview = entry.ShortOverview, - Type = entry.Type, ItemId = entry.ItemId, - UserId = entry.UserId, Date = entry.DateCreated, Severity = entry.LogSeverity }; diff --git a/Jellyfin.Server.Implementations/Jellyfin.Server.Implementations.csproj b/Jellyfin.Server.Implementations/Jellyfin.Server.Implementations.csproj index f73492b7c..728f9021d 100644 --- a/Jellyfin.Server.Implementations/Jellyfin.Server.Implementations.csproj +++ b/Jellyfin.Server.Implementations/Jellyfin.Server.Implementations.csproj @@ -4,14 +4,6 @@ <TargetFramework>net5.0</TargetFramework> <GenerateAssemblyInfo>false</GenerateAssemblyInfo> <GenerateDocumentationFile>true</GenerateDocumentationFile> - <TreatWarningsAsErrors>true</TreatWarningsAsErrors> - <Nullable>enable</Nullable> - <AnalysisMode>AllEnabledByDefault</AnalysisMode> - <CodeAnalysisRuleSet>../jellyfin.ruleset</CodeAnalysisRuleSet> - </PropertyGroup> - - <PropertyGroup Condition=" '$(Configuration)' == 'Debug' "> - <CodeAnalysisRuleSet>../jellyfin.ruleset</CodeAnalysisRuleSet> </PropertyGroup> <!-- Code analysers--> diff --git a/Jellyfin.Server/Extensions/ApiServiceCollectionExtensions.cs b/Jellyfin.Server/Extensions/ApiServiceCollectionExtensions.cs index 15dc43856..f19e87aba 100644 --- a/Jellyfin.Server/Extensions/ApiServiceCollectionExtensions.cs +++ b/Jellyfin.Server/Extensions/ApiServiceCollectionExtensions.cs @@ -303,7 +303,7 @@ namespace Jellyfin.Server.Extensions { description.TryGetMethodInfo(out MethodInfo methodInfo); // Attribute name, method name, none. - return description?.ActionDescriptor?.AttributeRouteInfo?.Name + return description?.ActionDescriptor.AttributeRouteInfo?.Name ?? methodInfo?.Name ?? null; }); @@ -341,7 +341,7 @@ namespace Jellyfin.Server.Extensions { foreach (var address in host.GetAddresses()) { - AddIpAddress(config, options, addr.Address, addr.PrefixLength); + AddIpAddress(config, options, address, address.AddressFamily == AddressFamily.InterNetwork ? 32 : 128); } } } @@ -397,7 +397,7 @@ namespace Jellyfin.Server.Extensions Type = "object", Properties = typeof(ImageType).GetEnumNames().ToDictionary( name => name, - name => new OpenApiSchema + _ => new OpenApiSchema { Type = "object", AdditionalProperties = new OpenApiSchema diff --git a/Jellyfin.Server/Jellyfin.Server.csproj b/Jellyfin.Server/Jellyfin.Server.csproj index 958a44fda..49529b794 100644 --- a/Jellyfin.Server/Jellyfin.Server.csproj +++ b/Jellyfin.Server/Jellyfin.Server.csproj @@ -12,11 +12,6 @@ <ServerGarbageCollection>false</ServerGarbageCollection> <GenerateAssemblyInfo>false</GenerateAssemblyInfo> <GenerateDocumentationFile>true</GenerateDocumentationFile> - <TreatWarningsAsErrors>true</TreatWarningsAsErrors> - <Nullable>enable</Nullable> - <AnalysisMode>AllEnabledByDefault</AnalysisMode> - <CodeAnalysisRuleSet>../jellyfin.ruleset</CodeAnalysisRuleSet> - <!-- <DisableImplicitAspNetCoreAnalyzers>true</DisableImplicitAspNetCoreAnalyzers> --> </PropertyGroup> <ItemGroup> diff --git a/Jellyfin.Server/Middleware/BaseUrlRedirectionMiddleware.cs b/Jellyfin.Server/Middleware/BaseUrlRedirectionMiddleware.cs index 2eef223e5..3e5982eed 100644 --- a/Jellyfin.Server/Middleware/BaseUrlRedirectionMiddleware.cs +++ b/Jellyfin.Server/Middleware/BaseUrlRedirectionMiddleware.cs @@ -58,9 +58,12 @@ namespace Jellyfin.Server.Middleware return; } - if (!startsWithBaseUrl) + if (!startsWithBaseUrl + || localPath.Length == baseUrlPrefix.Length + // Local path is /baseUrl/ + || (localPath.Length == baseUrlPrefix.Length + 1 && localPath[^1] == '/')) { - // Always redirect back to the default path if the base prefix is invalid or missing + // Always redirect back to the default path if the base prefix is invalid, missing, or is the full path. _logger.LogDebug("Normalizing an URL at {LocalPath}", localPath); httpContext.Response.Redirect(baseUrlPrefix + "/" + _configuration[ConfigurationExtensions.DefaultRedirectKey]); return; diff --git a/Jellyfin.Server/Middleware/ExceptionMiddleware.cs b/Jellyfin.Server/Middleware/ExceptionMiddleware.cs index f6c76e4d9..db7877c31 100644 --- a/Jellyfin.Server/Middleware/ExceptionMiddleware.cs +++ b/Jellyfin.Server/Middleware/ExceptionMiddleware.cs @@ -137,11 +137,6 @@ namespace Jellyfin.Server.Middleware private string NormalizeExceptionMessage(string msg) { - if (msg == null) - { - return string.Empty; - } - // Strip any information we don't want to reveal return msg.Replace( _configuration.ApplicationPaths.ProgramSystemPath, diff --git a/Jellyfin.Server/Migrations/MigrationRunner.cs b/Jellyfin.Server/Migrations/MigrationRunner.cs index cf938ab8c..0af5cfd61 100644 --- a/Jellyfin.Server/Migrations/MigrationRunner.cs +++ b/Jellyfin.Server/Migrations/MigrationRunner.cs @@ -40,7 +40,7 @@ namespace Jellyfin.Server.Migrations .Select(m => ActivatorUtilities.CreateInstance(host.ServiceProvider, m)) .OfType<IMigrationRoutine>() .ToArray(); - var migrationOptions = ((IConfigurationManager)host.ConfigurationManager).GetConfiguration<MigrationOptions>(MigrationsListStore.StoreKey); + var migrationOptions = host.ConfigurationManager.GetConfiguration<MigrationOptions>(MigrationsListStore.StoreKey); if (!host.ConfigurationManager.Configuration.IsStartupWizardCompleted && migrationOptions.Applied.Count == 0) { diff --git a/Jellyfin.Server/Migrations/Routines/MigrateActivityLogDb.cs b/Jellyfin.Server/Migrations/Routines/MigrateActivityLogDb.cs index 6048160c6..9e22978ae 100644 --- a/Jellyfin.Server/Migrations/Routines/MigrateActivityLogDb.cs +++ b/Jellyfin.Server/Migrations/Routines/MigrateActivityLogDb.cs @@ -92,7 +92,7 @@ namespace Jellyfin.Server.Migrations.Routines if (entry[6].SQLiteType != SQLiteType.Null && !Guid.TryParse(entry[6].ToString(), out guid)) { // This is not a valid Guid, see if it is an internal ID from an old Emby schema - _logger.LogWarning("Invalid Guid in UserId column: ", entry[6].ToString()); + _logger.LogWarning("Invalid Guid in UserId column: {Guid}", entry[6].ToString()); using var statement = userDbConnection.PrepareStatement("SELECT guid FROM LocalUsersv2 WHERE Id=@Id"); statement.TryBind("@Id", entry[6].ToString()); diff --git a/Jellyfin.Server/Migrations/Routines/MigrateDisplayPreferencesDb.cs b/Jellyfin.Server/Migrations/Routines/MigrateDisplayPreferencesDb.cs index e25d29122..6ff59626d 100644 --- a/Jellyfin.Server/Migrations/Routines/MigrateDisplayPreferencesDb.cs +++ b/Jellyfin.Server/Migrations/Routines/MigrateDisplayPreferencesDb.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Globalization; using System.IO; using System.Linq; using System.Text.Json; diff --git a/Jellyfin.Server/Program.cs b/Jellyfin.Server/Program.cs index 934372a94..7018d537f 100644 --- a/Jellyfin.Server/Program.cs +++ b/Jellyfin.Server/Program.cs @@ -5,7 +5,6 @@ using System.IO; using System.Linq; using System.Net; using System.Reflection; -using System.Runtime.InteropServices; using System.Text; using System.Threading; using System.Threading.Tasks; @@ -121,11 +120,11 @@ namespace Jellyfin.Server // Log uncaught exceptions to the logging instead of std error AppDomain.CurrentDomain.UnhandledException -= UnhandledExceptionToConsole; - AppDomain.CurrentDomain.UnhandledException += (sender, e) + AppDomain.CurrentDomain.UnhandledException += (_, e) => _logger.LogCritical((Exception)e.ExceptionObject, "Unhandled Exception"); // Intercept Ctrl+C and Ctrl+Break - Console.CancelKeyPress += (sender, e) => + Console.CancelKeyPress += (_, e) => { if (_tokenSource.IsCancellationRequested) { @@ -139,7 +138,7 @@ namespace Jellyfin.Server }; // Register a SIGTERM handler - AppDomain.CurrentDomain.ProcessExit += (sender, e) => + AppDomain.CurrentDomain.ProcessExit += (_, _) => { if (_tokenSource.IsCancellationRequested) { @@ -180,7 +179,7 @@ namespace Jellyfin.Server "The server is expected to host the web client, but the provided content directory is either " + $"invalid or empty: {webContentPath}. If you do not want to host the web client with the " + "server, you may set the '--nowebclient' command line flag, or set" + - $"'{MediaBrowser.Controller.Extensions.ConfigurationExtensions.HostWebClientKey}=false' in your config settings."); + $"'{ConfigurationExtensions.HostWebClientKey}=false' in your config settings."); } } @@ -543,7 +542,7 @@ namespace Jellyfin.Server // Get a stream of the resource contents // NOTE: The .csproj name is used instead of the assembly name in the resource path const string ResourcePath = "Jellyfin.Server.Resources.Configuration.logging.json"; - await using Stream? resource = typeof(Program).Assembly.GetManifestResourceStream(ResourcePath) + await using Stream resource = typeof(Program).Assembly.GetManifestResourceStream(ResourcePath) ?? throw new InvalidOperationException($"Invalid resource path: '{ResourcePath}'"); // Copy the resource contents to the expected file path for the config file diff --git a/MediaBrowser.Common/Extensions/ProcessExtensions.cs b/MediaBrowser.Common/Extensions/ProcessExtensions.cs index c74787122..08e01bfd6 100644 --- a/MediaBrowser.Common/Extensions/ProcessExtensions.cs +++ b/MediaBrowser.Common/Extensions/ProcessExtensions.cs @@ -40,7 +40,7 @@ namespace MediaBrowser.Common.Extensions // Add an event handler for the process exit event var tcs = new TaskCompletionSource<bool>(); - process.Exited += (sender, args) => tcs.TrySetResult(true); + process.Exited += (_, _) => tcs.TrySetResult(true); // Return immediately if the process has already exited if (process.HasExitedSafe()) diff --git a/MediaBrowser.Common/MediaBrowser.Common.csproj b/MediaBrowser.Common/MediaBrowser.Common.csproj index 0299a8456..12cfaf978 100644 --- a/MediaBrowser.Common/MediaBrowser.Common.csproj +++ b/MediaBrowser.Common/MediaBrowser.Common.csproj @@ -32,10 +32,6 @@ <TargetFramework>net5.0</TargetFramework> <GenerateAssemblyInfo>false</GenerateAssemblyInfo> <GenerateDocumentationFile>true</GenerateDocumentationFile> - <TreatWarningsAsErrors>true</TreatWarningsAsErrors> - <Nullable>enable</Nullable> - <AnalysisMode>AllEnabledByDefault</AnalysisMode> - <CodeAnalysisRuleSet>../jellyfin.ruleset</CodeAnalysisRuleSet> <PublishRepositoryUrl>true</PublishRepositoryUrl> <EmbedUntrackedSources>true</EmbedUntrackedSources> <IncludeSymbols>true</IncludeSymbols> diff --git a/MediaBrowser.Common/Providers/ProviderIdParsers.cs b/MediaBrowser.Common/Providers/ProviderIdParsers.cs index 33d09ed38..487b5a6d2 100644 --- a/MediaBrowser.Common/Providers/ProviderIdParsers.cs +++ b/MediaBrowser.Common/Providers/ProviderIdParsers.cs @@ -18,7 +18,7 @@ namespace MediaBrowser.Common.Providers /// <param name="text">The text to parse.</param> /// <param name="imdbId">The parsed IMDb id.</param> /// <returns>True if parsing was successful, false otherwise.</returns> - public static bool TryFindImdbId(ReadOnlySpan<char> text, [NotNullWhen(true)] out ReadOnlySpan<char> imdbId) + public static bool TryFindImdbId(ReadOnlySpan<char> text, out ReadOnlySpan<char> imdbId) { // imdb id is at least 9 chars (tt + 7 numbers) while (text.Length >= 2 + ImdbMinNumbers) @@ -62,7 +62,7 @@ namespace MediaBrowser.Common.Providers /// <param name="text">The text with the url to parse.</param> /// <param name="tmdbId">The parsed TMDb id.</param> /// <returns>True if parsing was successful, false otherwise.</returns> - public static bool TryFindTmdbMovieId(ReadOnlySpan<char> text, [NotNullWhen(true)] out ReadOnlySpan<char> tmdbId) + public static bool TryFindTmdbMovieId(ReadOnlySpan<char> text, out ReadOnlySpan<char> tmdbId) => TryFindProviderId(text, "themoviedb.org/movie/", out tmdbId); /// <summary> @@ -71,7 +71,7 @@ namespace MediaBrowser.Common.Providers /// <param name="text">The text with the url to parse.</param> /// <param name="tmdbId">The parsed TMDb id.</param> /// <returns>True if parsing was successful, false otherwise.</returns> - public static bool TryFindTmdbSeriesId(ReadOnlySpan<char> text, [NotNullWhen(true)] out ReadOnlySpan<char> tmdbId) + public static bool TryFindTmdbSeriesId(ReadOnlySpan<char> text, out ReadOnlySpan<char> tmdbId) => TryFindProviderId(text, "themoviedb.org/tv/", out tmdbId); /// <summary> @@ -80,7 +80,7 @@ namespace MediaBrowser.Common.Providers /// <param name="text">The text with the url to parse.</param> /// <param name="tvdbId">The parsed TVDb id.</param> /// <returns>True if parsing was successful, false otherwise.</returns> - public static bool TryFindTvdbId(ReadOnlySpan<char> text, [NotNullWhen(true)] out ReadOnlySpan<char> tvdbId) + public static bool TryFindTvdbId(ReadOnlySpan<char> text, out ReadOnlySpan<char> tvdbId) => TryFindProviderId(text, "thetvdb.com/?tab=series&id=", out tvdbId); private static bool TryFindProviderId(ReadOnlySpan<char> text, ReadOnlySpan<char> searchString, [NotNullWhen(true)] out ReadOnlySpan<char> providerId) diff --git a/MediaBrowser.Controller/Channels/Channel.cs b/MediaBrowser.Controller/Channels/Channel.cs index 26a936be0..e6923b55c 100644 --- a/MediaBrowser.Controller/Channels/Channel.cs +++ b/MediaBrowser.Controller/Channels/Channel.cs @@ -17,6 +17,12 @@ namespace MediaBrowser.Controller.Channels { public class Channel : Folder { + [JsonIgnore] + public override bool SupportsInheritedParentImages => false; + + [JsonIgnore] + public override SourceType SourceType => SourceType.Channel; + public override bool IsVisible(User user) { var blockedChannelsPreference = user.GetPreferenceValues<Guid>(PreferenceKind.BlockedChannels); @@ -39,12 +45,6 @@ namespace MediaBrowser.Controller.Channels return base.IsVisible(user); } - [JsonIgnore] - public override bool SupportsInheritedParentImages => false; - - [JsonIgnore] - public override SourceType SourceType => SourceType.Channel; - protected override QueryResult<BaseItem> GetItemsInternal(InternalItemsQuery query) { try diff --git a/MediaBrowser.Controller/Channels/ChannelItemInfo.cs b/MediaBrowser.Controller/Channels/ChannelItemInfo.cs index 4d1e35f9e..55f80b240 100644 --- a/MediaBrowser.Controller/Channels/ChannelItemInfo.cs +++ b/MediaBrowser.Controller/Channels/ChannelItemInfo.cs @@ -1,6 +1,6 @@ #nullable disable -#pragma warning disable CS1591 +#pragma warning disable CA1002, CA2227, CS1591 using System; using System.Collections.Generic; diff --git a/MediaBrowser.Controller/Channels/ChannelItemResult.cs b/MediaBrowser.Controller/Channels/ChannelItemResult.cs index 6b2077662..7a0addd9f 100644 --- a/MediaBrowser.Controller/Channels/ChannelItemResult.cs +++ b/MediaBrowser.Controller/Channels/ChannelItemResult.cs @@ -1,6 +1,6 @@ #nullable disable -#pragma warning disable CS1591 +#pragma warning disable CA1002, CA2227, CS1591 using System.Collections.Generic; diff --git a/MediaBrowser.Controller/Channels/IHasFolderAttributes.cs b/MediaBrowser.Controller/Channels/IHasFolderAttributes.cs index 47277a8cc..64af8496c 100644 --- a/MediaBrowser.Controller/Channels/IHasFolderAttributes.cs +++ b/MediaBrowser.Controller/Channels/IHasFolderAttributes.cs @@ -1,4 +1,4 @@ -#pragma warning disable CS1591 +#pragma warning disable CA1819, CS1591 namespace MediaBrowser.Controller.Channels { diff --git a/MediaBrowser.Controller/Channels/InternalChannelFeatures.cs b/MediaBrowser.Controller/Channels/InternalChannelFeatures.cs index 45cd08173..394996868 100644 --- a/MediaBrowser.Controller/Channels/InternalChannelFeatures.cs +++ b/MediaBrowser.Controller/Channels/InternalChannelFeatures.cs @@ -1,6 +1,6 @@ #nullable disable -#pragma warning disable CS1591 +#pragma warning disable CA1002, CA2227, CS1591 using System.Collections.Generic; using MediaBrowser.Model.Channels; diff --git a/MediaBrowser.Controller/Chapters/IChapterManager.cs b/MediaBrowser.Controller/Chapters/IChapterManager.cs index f82e5b41a..c049bb97e 100644 --- a/MediaBrowser.Controller/Chapters/IChapterManager.cs +++ b/MediaBrowser.Controller/Chapters/IChapterManager.cs @@ -12,6 +12,8 @@ namespace MediaBrowser.Controller.Chapters /// <summary> /// Saves the chapters. /// </summary> + /// <param name="itemId">The item.</param> + /// <param name="chapters">The set of chapters.</param> void SaveChapters(Guid itemId, IReadOnlyList<ChapterInfo> chapters); } } diff --git a/MediaBrowser.Controller/Collections/CollectionCreationOptions.cs b/MediaBrowser.Controller/Collections/CollectionCreationOptions.cs index 30f5f4efa..76ad335c5 100644 --- a/MediaBrowser.Controller/Collections/CollectionCreationOptions.cs +++ b/MediaBrowser.Controller/Collections/CollectionCreationOptions.cs @@ -1,6 +1,6 @@ #nullable disable -#pragma warning disable CS1591 +#pragma warning disable CA2227, CS1591 using System; using System.Collections.Generic; diff --git a/MediaBrowser.Controller/Collections/ICollectionManager.cs b/MediaBrowser.Controller/Collections/ICollectionManager.cs index 46bc37e7f..49cc39f04 100644 --- a/MediaBrowser.Controller/Collections/ICollectionManager.cs +++ b/MediaBrowser.Controller/Collections/ICollectionManager.cs @@ -32,6 +32,7 @@ namespace MediaBrowser.Controller.Collections /// Creates the collection. /// </summary> /// <param name="options">The options.</param> + /// <returns>BoxSet wrapped in an awaitable task.</returns> Task<BoxSet> CreateCollectionAsync(CollectionCreationOptions options); /// <summary> diff --git a/MediaBrowser.Controller/Drawing/IImageEncoder.cs b/MediaBrowser.Controller/Drawing/IImageEncoder.cs index 4e640d421..4e67cfee4 100644 --- a/MediaBrowser.Controller/Drawing/IImageEncoder.cs +++ b/MediaBrowser.Controller/Drawing/IImageEncoder.cs @@ -57,6 +57,15 @@ namespace MediaBrowser.Controller.Drawing /// <summary> /// Encode an image. /// </summary> + /// <param name="inputPath">Input path of image.</param> + /// <param name="dateModified">Date modified.</param> + /// <param name="outputPath">Output path of image.</param> + /// <param name="autoOrient">Auto-orient image.</param> + /// <param name="orientation">Desired orientation of image.</param> + /// <param name="quality">Quality of encoded image.</param> + /// <param name="options">Image processing options.</param> + /// <param name="outputFormat">Image format of output.</param> + /// <returns>Path of encoded image.</returns> string EncodeImage(string inputPath, DateTime dateModified, string outputPath, bool autoOrient, ImageOrientation? orientation, int quality, ImageProcessingOptions options, ImageFormat outputFormat); /// <summary> diff --git a/MediaBrowser.Controller/Drawing/ImageStream.cs b/MediaBrowser.Controller/Drawing/ImageStream.cs index 5ee781ffa..5d552170f 100644 --- a/MediaBrowser.Controller/Drawing/ImageStream.cs +++ b/MediaBrowser.Controller/Drawing/ImageStream.cs @@ -1,4 +1,4 @@ -#pragma warning disable CS1591 +#pragma warning disable CA1711, CS1591 using System; using System.IO; diff --git a/MediaBrowser.Controller/Dto/IDtoService.cs b/MediaBrowser.Controller/Dto/IDtoService.cs index 61d796235..89aafc84f 100644 --- a/MediaBrowser.Controller/Dto/IDtoService.cs +++ b/MediaBrowser.Controller/Dto/IDtoService.cs @@ -1,4 +1,5 @@ #nullable disable +#pragma warning disable CA1002 using System.Collections.Generic; using Jellyfin.Data.Entities; diff --git a/MediaBrowser.Controller/Library/ILibraryManager.cs b/MediaBrowser.Controller/Library/ILibraryManager.cs index 7a4ba6a24..604960d8b 100644 --- a/MediaBrowser.Controller/Library/ILibraryManager.cs +++ b/MediaBrowser.Controller/Library/ILibraryManager.cs @@ -1,6 +1,6 @@ #nullable disable -#pragma warning disable CS1591 +#pragma warning disable CA1002, CS1591 using System; using System.Collections.Generic; @@ -32,6 +32,29 @@ namespace MediaBrowser.Controller.Library public interface ILibraryManager { /// <summary> + /// Occurs when [item added]. + /// </summary> + event EventHandler<ItemChangeEventArgs> ItemAdded; + + /// <summary> + /// Occurs when [item updated]. + /// </summary> + event EventHandler<ItemChangeEventArgs> ItemUpdated; + + /// <summary> + /// Occurs when [item removed]. + /// </summary> + event EventHandler<ItemChangeEventArgs> ItemRemoved; + + /// <summary> + /// Gets the root folder. + /// </summary> + /// <value>The root folder.</value> + AggregateFolder RootFolder { get; } + + bool IsScanRunning { get; } + + /// <summary> /// Resolves the path. /// </summary> /// <param name="fileInfo">The file information.</param> @@ -58,15 +81,9 @@ namespace MediaBrowser.Controller.Library string collectionType = null); /// <summary> - /// Gets the root folder. - /// </summary> - /// <value>The root folder.</value> - AggregateFolder RootFolder { get; } - - /// <summary> /// Gets a Person. /// </summary> - /// <param name="name">The name.</param> + /// <param name="name">The name of the person.</param> /// <returns>Task{Person}.</returns> Person GetPerson(string name); @@ -81,7 +98,7 @@ namespace MediaBrowser.Controller.Library /// <summary> /// Gets the artist. /// </summary> - /// <param name="name">The name.</param> + /// <param name="name">The name of the artist.</param> /// <returns>Task{Artist}.</returns> MusicArtist GetArtist(string name); @@ -90,21 +107,21 @@ namespace MediaBrowser.Controller.Library /// <summary> /// Gets a Studio. /// </summary> - /// <param name="name">The name.</param> + /// <param name="name">The name of the studio.</param> /// <returns>Task{Studio}.</returns> Studio GetStudio(string name); /// <summary> /// Gets a Genre. /// </summary> - /// <param name="name">The name.</param> + /// <param name="name">The name of the genre.</param> /// <returns>Task{Genre}.</returns> Genre GetGenre(string name); /// <summary> /// Gets the genre. /// </summary> - /// <param name="name">The name.</param> + /// <param name="name">The name of the music genre.</param> /// <returns>Task{MusicGenre}.</returns> MusicGenre GetMusicGenre(string name); @@ -113,7 +130,7 @@ namespace MediaBrowser.Controller.Library /// </summary> /// <param name="value">The value.</param> /// <returns>Task{Year}.</returns> - /// <exception cref="ArgumentOutOfRangeException"></exception> + /// <exception cref="ArgumentOutOfRangeException">Throws if year is invalid.</exception> Year GetYear(int value); /// <summary> @@ -205,16 +222,26 @@ namespace MediaBrowser.Controller.Library /// <summary> /// Creates the item. /// </summary> + /// <param name="item">Item to create.</param> + /// <param name="parent">Parent of new item.</param> void CreateItem(BaseItem item, BaseItem parent); /// <summary> /// Creates the items. /// </summary> + /// <param name="items">Items to create.</param> + /// <param name="parent">Parent of new items.</param> + /// <param name="cancellationToken">CancellationToken to use for operation.</param> void CreateItems(IReadOnlyList<BaseItem> items, BaseItem parent, CancellationToken cancellationToken); /// <summary> /// Updates the item. /// </summary> + /// <param name="items">Items to update.</param> + /// <param name="parent">Parent of updated items.</param> + /// <param name="updateReason">Reason for update.</param> + /// <param name="cancellationToken">CancellationToken to use for operation.</param> + /// <returns>Returns a Task that can be awaited.</returns> Task UpdateItemsAsync(IReadOnlyList<BaseItem> items, BaseItem parent, ItemUpdateType updateReason, CancellationToken cancellationToken); /// <summary> @@ -224,6 +251,7 @@ namespace MediaBrowser.Controller.Library /// <param name="parent">The parent item.</param> /// <param name="updateReason">The update reason.</param> /// <param name="cancellationToken">The cancellation token.</param> + /// <returns>Returns a Task that can be awaited.</returns> Task UpdateItemAsync(BaseItem item, BaseItem parent, ItemUpdateType updateReason, CancellationToken cancellationToken); /// <summary> @@ -233,23 +261,6 @@ namespace MediaBrowser.Controller.Library /// <returns>BaseItem.</returns> BaseItem RetrieveItem(Guid id); - bool IsScanRunning { get; } - - /// <summary> - /// Occurs when [item added]. - /// </summary> - event EventHandler<ItemChangeEventArgs> ItemAdded; - - /// <summary> - /// Occurs when [item updated]. - /// </summary> - event EventHandler<ItemChangeEventArgs> ItemUpdated; - - /// <summary> - /// Occurs when [item removed]. - /// </summary> - event EventHandler<ItemChangeEventArgs> ItemRemoved; - /// <summary> /// Finds the type of the collection. /// </summary> @@ -294,16 +305,25 @@ namespace MediaBrowser.Controller.Library /// <summary> /// Deletes the item. /// </summary> + /// <param name="item">Item to delete.</param> + /// <param name="options">Options to use for deletion.</param> void DeleteItem(BaseItem item, DeleteOptions options); /// <summary> /// Deletes the item. /// </summary> + /// <param name="item">Item to delete.</param> + /// <param name="options">Options to use for deletion.</param> + /// <param name="notifyParentItem">Notify parent of deletion.</param> void DeleteItem(BaseItem item, DeleteOptions options, bool notifyParentItem); /// <summary> /// Deletes the item. /// </summary> + /// <param name="item">Item to delete.</param> + /// <param name="options">Options to use for deletion.</param> + /// <param name="parent">Parent of item.</param> + /// <param name="notifyParentItem">Notify parent of deletion.</param> void DeleteItem(BaseItem item, DeleteOptions options, BaseItem parent, bool notifyParentItem); /// <summary> @@ -314,6 +334,7 @@ namespace MediaBrowser.Controller.Library /// <param name="parentId">The parent identifier.</param> /// <param name="viewType">Type of the view.</param> /// <param name="sortName">Name of the sort.</param> + /// <returns>The named view.</returns> UserView GetNamedView( User user, string name, @@ -328,6 +349,7 @@ namespace MediaBrowser.Controller.Library /// <param name="name">The name.</param> /// <param name="viewType">Type of the view.</param> /// <param name="sortName">Name of the sort.</param> + /// <returns>The named view.</returns> UserView GetNamedView( User user, string name, @@ -340,6 +362,7 @@ namespace MediaBrowser.Controller.Library /// <param name="name">The name.</param> /// <param name="viewType">Type of the view.</param> /// <param name="sortName">Name of the sort.</param> + /// <returns>The named view.</returns> UserView GetNamedView( string name, string viewType, @@ -397,6 +420,9 @@ namespace MediaBrowser.Controller.Library /// <summary> /// Fills the missing episode numbers from path. /// </summary> + /// <param name="episode">Episode to use.</param> + /// <param name="forceRefresh">Option to force refresh of episode numbers.</param> + /// <returns>True if successful.</returns> bool FillMissingEpisodeNumbersFromPath(Episode episode, bool forceRefresh); /// <summary> @@ -539,6 +565,9 @@ namespace MediaBrowser.Controller.Library /// <summary> /// Gets the items. /// </summary> + /// <param name="query">The query to use.</param> + /// <param name="parents">Items to use for query.</param> + /// <returns>List of items.</returns> List<BaseItem> GetItemList(InternalItemsQuery query, List<BaseItem> parents); /// <summary> diff --git a/MediaBrowser.Controller/Library/ILiveStream.cs b/MediaBrowser.Controller/Library/ILiveStream.cs index 85d866de5..323aa4876 100644 --- a/MediaBrowser.Controller/Library/ILiveStream.cs +++ b/MediaBrowser.Controller/Library/ILiveStream.cs @@ -1,6 +1,6 @@ #nullable disable -#pragma warning disable CS1591 +#pragma warning disable CA1711, CS1591 using System.Threading; using System.Threading.Tasks; diff --git a/MediaBrowser.Controller/Library/IMediaSourceManager.cs b/MediaBrowser.Controller/Library/IMediaSourceManager.cs index d3d85a056..fd3631da9 100644 --- a/MediaBrowser.Controller/Library/IMediaSourceManager.cs +++ b/MediaBrowser.Controller/Library/IMediaSourceManager.cs @@ -1,6 +1,6 @@ #nullable disable -#pragma warning disable CS1591 +#pragma warning disable CA1002, CS1591 using System; using System.Collections.Generic; @@ -62,16 +62,32 @@ namespace MediaBrowser.Controller.Library /// <summary> /// Gets the playack media sources. /// </summary> + /// <param name="item">Item to use.</param> + /// <param name="user">User to use for operation.</param> + /// <param name="allowMediaProbe">Option to allow media probe.</param> + /// <param name="enablePathSubstitution">Option to enable path substitution.</param> + /// <param name="cancellationToken">CancellationToken to use for operation.</param> + /// <returns>List of media sources wrapped in an awaitable task.</returns> Task<List<MediaSourceInfo>> GetPlaybackMediaSources(BaseItem item, User user, bool allowMediaProbe, bool enablePathSubstitution, CancellationToken cancellationToken); /// <summary> /// Gets the static media sources. /// </summary> + /// <param name="item">Item to use.</param> + /// <param name="enablePathSubstitution">Option to enable path substitution.</param> + /// <param name="user">User to use for operation.</param> + /// <returns>List of media sources.</returns> List<MediaSourceInfo> GetStaticMediaSources(BaseItem item, bool enablePathSubstitution, User user = null); /// <summary> /// Gets the static media source. /// </summary> + /// <param name="item">Item to use.</param> + /// <param name="mediaSourceId">Media source to get.</param> + /// <param name="liveStreamId">Live stream to use.</param> + /// <param name="enablePathSubstitution">Option to enable path substitution.</param> + /// <param name="cancellationToken">CancellationToken to use for operation.</param> + /// <returns>The static media source wrapped in an awaitable task.</returns> Task<MediaSourceInfo> GetMediaSource(BaseItem item, string mediaSourceId, string liveStreamId, bool enablePathSubstitution, CancellationToken cancellationToken); /// <summary> diff --git a/MediaBrowser.Controller/Library/IMediaSourceProvider.cs b/MediaBrowser.Controller/Library/IMediaSourceProvider.cs index 5bf4acebb..ca4b53fbe 100644 --- a/MediaBrowser.Controller/Library/IMediaSourceProvider.cs +++ b/MediaBrowser.Controller/Library/IMediaSourceProvider.cs @@ -1,4 +1,4 @@ -#pragma warning disable CS1591 +#pragma warning disable CA1002, CS1591 using System.Collections.Generic; using System.Threading; @@ -21,6 +21,10 @@ namespace MediaBrowser.Controller.Library /// <summary> /// Opens the media source. /// </summary> + /// <param name="openToken">Token to use.</param> + /// <param name="currentLiveStreams">List of live streams.</param> + /// <param name="cancellationToken">CancellationToken to use for operation.</param> + /// <returns>The media source wrapped as an awaitable task.</returns> Task<ILiveStream> OpenMediaSource(string openToken, List<ILiveStream> currentLiveStreams, CancellationToken cancellationToken); } } diff --git a/MediaBrowser.Controller/Library/IMetadataSaver.cs b/MediaBrowser.Controller/Library/IMetadataSaver.cs index 5fbfad881..d963fd249 100644 --- a/MediaBrowser.Controller/Library/IMetadataSaver.cs +++ b/MediaBrowser.Controller/Library/IMetadataSaver.cs @@ -29,7 +29,6 @@ namespace MediaBrowser.Controller.Library /// </summary> /// <param name="item">The item.</param> /// <param name="cancellationToken">The cancellation token.</param> - /// <returns>Task.</returns> void Save(BaseItem item, CancellationToken cancellationToken); } } diff --git a/MediaBrowser.Controller/Library/IMusicManager.cs b/MediaBrowser.Controller/Library/IMusicManager.cs index 5329841bf..ec34a868b 100644 --- a/MediaBrowser.Controller/Library/IMusicManager.cs +++ b/MediaBrowser.Controller/Library/IMusicManager.cs @@ -1,6 +1,6 @@ #nullable disable -#pragma warning disable CS1591 +#pragma warning disable CA1002, CS1591 using System.Collections.Generic; using Jellyfin.Data.Entities; @@ -15,16 +15,28 @@ namespace MediaBrowser.Controller.Library /// <summary> /// Gets the instant mix from song. /// </summary> + /// <param name="item">The item to use.</param> + /// <param name="user">The user to use.</param> + /// <param name="dtoOptions">The options to use.</param> + /// <returns>List of items.</returns> List<BaseItem> GetInstantMixFromItem(BaseItem item, User user, DtoOptions dtoOptions); /// <summary> /// Gets the instant mix from artist. /// </summary> + /// <param name="artist">The artist to use.</param> + /// <param name="user">The user to use.</param> + /// <param name="dtoOptions">The options to use.</param> + /// <returns>List of items.</returns> List<BaseItem> GetInstantMixFromArtist(MusicArtist artist, User user, DtoOptions dtoOptions); /// <summary> /// Gets the instant mix from genre. /// </summary> + /// <param name="genres">The genres to use.</param> + /// <param name="user">The user to use.</param> + /// <param name="dtoOptions">The options to use.</param> + /// <returns>List of items.</returns> List<BaseItem> GetInstantMixFromGenres(IEnumerable<string> genres, User user, DtoOptions dtoOptions); } } diff --git a/MediaBrowser.Controller/Library/IUserDataManager.cs b/MediaBrowser.Controller/Library/IUserDataManager.cs index e5dcfcff0..cf35b48db 100644 --- a/MediaBrowser.Controller/Library/IUserDataManager.cs +++ b/MediaBrowser.Controller/Library/IUserDataManager.cs @@ -1,6 +1,6 @@ #nullable disable -#pragma warning disable CS1591 +#pragma warning disable CA1002, CA1707, CS1591 using System; using System.Collections.Generic; @@ -42,6 +42,9 @@ namespace MediaBrowser.Controller.Library /// <summary> /// Gets the user data dto. /// </summary> + /// <param name="item">Item to use.</param> + /// <param name="user">User to use.</param> + /// <returns>User data dto.</returns> UserItemDataDto GetUserDataDto(BaseItem item, User user); UserItemDataDto GetUserDataDto(BaseItem item, BaseItemDto itemDto, User user, DtoOptions dto_options); @@ -64,6 +67,10 @@ namespace MediaBrowser.Controller.Library /// <summary> /// Updates playstate for an item and returns true or false indicating if it was played to completion. /// </summary> + /// <param name="item">Item to update.</param> + /// <param name="data">Data to update.</param> + /// <param name="positionTicks">New playstate.</param> + /// <returns>True if playstate was updated.</returns> bool UpdatePlayState(BaseItem item, UserItemData data, long? positionTicks); } } diff --git a/MediaBrowser.Controller/Library/IUserManager.cs b/MediaBrowser.Controller/Library/IUserManager.cs index 1801b1c41..21776f891 100644 --- a/MediaBrowser.Controller/Library/IUserManager.cs +++ b/MediaBrowser.Controller/Library/IUserManager.cs @@ -38,6 +38,7 @@ namespace MediaBrowser.Controller.Library /// <summary> /// Initializes the user manager and ensures that a user exists. /// </summary> + /// <returns>Awaitable task.</returns> Task InitializeAsync(); /// <summary> @@ -109,17 +110,22 @@ namespace MediaBrowser.Controller.Library /// Resets the easy password. /// </summary> /// <param name="user">The user.</param> - /// <returns>Task.</returns> void ResetEasyPassword(User user); /// <summary> /// Changes the password. /// </summary> + /// <param name="user">The user.</param> + /// <param name="newPassword">New password to use.</param> + /// <returns>Awaitable task.</returns> Task ChangePassword(User user, string newPassword); /// <summary> /// Changes the easy password. /// </summary> + /// <param name="user">The user.</param> + /// <param name="newPassword">New password to use.</param> + /// <param name="newPasswordSha1">Hash of new password.</param> void ChangeEasyPassword(User user, string newPassword, string newPasswordSha1); /// <summary> @@ -133,6 +139,12 @@ namespace MediaBrowser.Controller.Library /// <summary> /// Authenticates the user. /// </summary> + /// <param name="username">The user.</param> + /// <param name="password">The password to use.</param> + /// <param name="passwordSha1">Hash of password.</param> + /// <param name="remoteEndPoint">Remove endpoint to use.</param> + /// <param name="isUserSession">Specifies if a user session.</param> + /// <returns>User wrapped in awaitable task.</returns> Task<User> AuthenticateUser(string username, string password, string passwordSha1, string remoteEndPoint, bool isUserSession); /// <summary> diff --git a/MediaBrowser.Controller/Library/IUserViewManager.cs b/MediaBrowser.Controller/Library/IUserViewManager.cs index 46004e42f..055627d3e 100644 --- a/MediaBrowser.Controller/Library/IUserViewManager.cs +++ b/MediaBrowser.Controller/Library/IUserViewManager.cs @@ -1,6 +1,6 @@ #nullable disable -#pragma warning disable CS1591 +#pragma warning disable CA1002, CS1591 using System; using System.Collections.Generic; @@ -13,10 +13,29 @@ namespace MediaBrowser.Controller.Library { public interface IUserViewManager { + /// <summary> + /// Gets user views. + /// </summary> + /// <param name="query">Query to use.</param> + /// <returns>Set of folders.</returns> Folder[] GetUserViews(UserViewQuery query); + /// <summary> + /// Gets user sub views. + /// </summary> + /// <param name="parentId">Parent to use.</param> + /// <param name="type">Type to use.</param> + /// <param name="localizationKey">Localization key to use.</param> + /// <param name="sortName">Sort to use.</param> + /// <returns>User view.</returns> UserView GetUserSubView(Guid parentId, string type, string localizationKey, string sortName); + /// <summary> + /// Gets latest items. + /// </summary> + /// <param name="request">Query to use.</param> + /// <param name="options">Options to use.</param> + /// <returns>Set of items.</returns> List<Tuple<BaseItem, List<BaseItem>>> GetLatestItems(LatestItemsQuery request, DtoOptions options); } } diff --git a/MediaBrowser.Controller/Library/ItemChangeEventArgs.cs b/MediaBrowser.Controller/Library/ItemChangeEventArgs.cs index a37dc7af1..3586dc69d 100644 --- a/MediaBrowser.Controller/Library/ItemChangeEventArgs.cs +++ b/MediaBrowser.Controller/Library/ItemChangeEventArgs.cs @@ -1,6 +1,6 @@ #nullable disable -#pragma warning disable CS1591 +#pragma warning disable CA1711, CS1591 using MediaBrowser.Controller.Entities; diff --git a/MediaBrowser.Controller/Library/ItemResolveArgs.cs b/MediaBrowser.Controller/Library/ItemResolveArgs.cs index 521e37274..bfc1e4857 100644 --- a/MediaBrowser.Controller/Library/ItemResolveArgs.cs +++ b/MediaBrowser.Controller/Library/ItemResolveArgs.cs @@ -1,6 +1,6 @@ #nullable disable -#pragma warning disable CS1591 +#pragma warning disable CA1721, CA1819, CS1591 using System; using System.Collections.Generic; @@ -109,6 +109,21 @@ namespace MediaBrowser.Controller.Library /// <value>The additional locations.</value> private List<string> AdditionalLocations { get; set; } + /// <summary> + /// Gets the physical locations. + /// </summary> + /// <value>The physical locations.</value> + public string[] PhysicalLocations + { + get + { + var paths = string.IsNullOrEmpty(Path) ? Array.Empty<string>() : new[] { Path }; + return AdditionalLocations == null ? paths : paths.Concat(AdditionalLocations).ToArray(); + } + } + + public string CollectionType { get; set; } + public bool HasParent<T>() where T : Folder { @@ -139,6 +154,16 @@ namespace MediaBrowser.Controller.Library } /// <summary> + /// Determines whether the specified <see cref="object" /> is equal to this instance. + /// </summary> + /// <param name="obj">The object to compare with the current object.</param> + /// <returns><c>true</c> if the specified <see cref="object" /> is equal to this instance; otherwise, <c>false</c>.</returns> + public override bool Equals(object obj) + { + return Equals(obj as ItemResolveArgs); + } + + /// <summary> /// Adds the additional location. /// </summary> /// <param name="path">The path.</param> @@ -157,19 +182,6 @@ namespace MediaBrowser.Controller.Library // REVIEW: @bond /// <summary> - /// Gets the physical locations. - /// </summary> - /// <value>The physical locations.</value> - public string[] PhysicalLocations - { - get - { - var paths = string.IsNullOrEmpty(Path) ? Array.Empty<string>() : new[] { Path }; - return AdditionalLocations == null ? paths : paths.Concat(AdditionalLocations).ToArray(); - } - } - - /// <summary> /// Gets the name of the file system entry by. /// </summary> /// <param name="name">The name.</param> @@ -190,7 +202,7 @@ namespace MediaBrowser.Controller.Library /// </summary> /// <param name="path">The path.</param> /// <returns>FileSystemInfo.</returns> - /// <exception cref="ArgumentNullException"></exception> + /// <exception cref="ArgumentNullException">Throws if path is invalid.</exception> public FileSystemMetadata GetFileSystemEntryByPath(string path) { if (string.IsNullOrEmpty(path)) @@ -224,18 +236,6 @@ namespace MediaBrowser.Controller.Library return CollectionType; } - public string CollectionType { get; set; } - - /// <summary> - /// Determines whether the specified <see cref="object" /> is equal to this instance. - /// </summary> - /// <param name="obj">The object to compare with the current object.</param> - /// <returns><c>true</c> if the specified <see cref="object" /> is equal to this instance; otherwise, <c>false</c>.</returns> - public override bool Equals(object obj) - { - return Equals(obj as ItemResolveArgs); - } - /// <summary> /// Returns a hash code for this instance. /// </summary> diff --git a/MediaBrowser.Controller/Library/PlaybackProgressEventArgs.cs b/MediaBrowser.Controller/Library/PlaybackProgressEventArgs.cs index 609336ec4..76e9eb1f5 100644 --- a/MediaBrowser.Controller/Library/PlaybackProgressEventArgs.cs +++ b/MediaBrowser.Controller/Library/PlaybackProgressEventArgs.cs @@ -1,6 +1,6 @@ #nullable disable -#pragma warning disable CS1591 +#pragma warning disable CA1002, CA2227, CS1591 using System; using System.Collections.Generic; diff --git a/MediaBrowser.Controller/Library/UserDataSaveEventArgs.cs b/MediaBrowser.Controller/Library/UserDataSaveEventArgs.cs index bfe433c97..4d90346f2 100644 --- a/MediaBrowser.Controller/Library/UserDataSaveEventArgs.cs +++ b/MediaBrowser.Controller/Library/UserDataSaveEventArgs.cs @@ -1,6 +1,6 @@ #nullable disable -#pragma warning disable CS1591 +#pragma warning disable CA1002, CA2227, CS1591 using System; using System.Collections.Generic; diff --git a/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs b/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs index f4dc18e11..bd097c90a 100644 --- a/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs +++ b/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs @@ -22,12 +22,22 @@ namespace MediaBrowser.Controller.LiveTv /// </summary> public interface ILiveTvManager { + event EventHandler<GenericEventArgs<TimerEventInfo>> SeriesTimerCancelled; + + event EventHandler<GenericEventArgs<TimerEventInfo>> TimerCancelled; + + event EventHandler<GenericEventArgs<TimerEventInfo>> TimerCreated; + + event EventHandler<GenericEventArgs<TimerEventInfo>> SeriesTimerCreated; + /// <summary> /// Gets the services. /// </summary> /// <value>The services.</value> IReadOnlyList<ILiveTvService> Services { get; } + IListingsProvider[] ListingProviders { get; } + /// <summary> /// Gets the new timer defaults asynchronous. /// </summary> @@ -86,6 +96,7 @@ namespace MediaBrowser.Controller.LiveTv /// </summary> /// <param name="query">The query.</param> /// <param name="options">The options.</param> + /// <returns>A recording.</returns> QueryResult<BaseItemDto> GetRecordings(RecordingQuery query, DtoOptions options); /// <summary> @@ -176,11 +187,16 @@ namespace MediaBrowser.Controller.LiveTv /// <param name="query">The query.</param> /// <param name="options">The options.</param> /// <param name="cancellationToken">The cancellation token.</param> + /// <returns>Recommended programs.</returns> QueryResult<BaseItemDto> GetRecommendedPrograms(InternalItemsQuery query, DtoOptions options, CancellationToken cancellationToken); /// <summary> /// Gets the recommended programs internal. /// </summary> + /// <param name="query">The query.</param> + /// <param name="options">The options.</param> + /// <param name="cancellationToken">The cancellation token.</param> + /// <returns>Recommended programs.</returns> QueryResult<BaseItem> GetRecommendedProgramsInternal(InternalItemsQuery query, DtoOptions options, CancellationToken cancellationToken); /// <summary> @@ -202,6 +218,7 @@ namespace MediaBrowser.Controller.LiveTv /// Gets the live tv folder. /// </summary> /// <param name="cancellationToken">The cancellation token.</param> + /// <returns>Live TV folder.</returns> Folder GetInternalLiveTvFolder(CancellationToken cancellationToken); /// <summary> @@ -213,11 +230,18 @@ namespace MediaBrowser.Controller.LiveTv /// <summary> /// Gets the internal channels. /// </summary> + /// <param name="query">The query.</param> + /// <param name="dtoOptions">The options.</param> + /// <param name="cancellationToken">The cancellation token.</param> + /// <returns>Internal channels.</returns> QueryResult<BaseItem> GetInternalChannels(LiveTvChannelQuery query, DtoOptions dtoOptions, CancellationToken cancellationToken); /// <summary> /// Gets the channel media sources. /// </summary> + /// <param name="item">Item to search for.</param> + /// <param name="cancellationToken">CancellationToken to use for operation.</param> + /// <returns>Channel media sources wrapped in a task.</returns> Task<IEnumerable<MediaSourceInfo>> GetChannelMediaSources(BaseItem item, CancellationToken cancellationToken); /// <summary> @@ -232,6 +256,9 @@ namespace MediaBrowser.Controller.LiveTv /// <summary> /// Saves the tuner host. /// </summary> + /// <param name="info">Turner host to save.</param> + /// <param name="dataSourceChanged">Option to specify that data source has changed.</param> + /// <returns>Tuner host information wrapped in a task.</returns> Task<TunerHostInfo> SaveTunerHost(TunerHostInfo info, bool dataSourceChanged = true); /// <summary> @@ -271,20 +298,10 @@ namespace MediaBrowser.Controller.LiveTv Task<List<ChannelInfo>> GetChannelsFromListingsProviderData(string id, CancellationToken cancellationToken); - IListingsProvider[] ListingProviders { get; } - List<NameIdPair> GetTunerHostTypes(); Task<List<TunerHostInfo>> DiscoverTuners(bool newDevicesOnly, CancellationToken cancellationToken); - event EventHandler<GenericEventArgs<TimerEventInfo>> SeriesTimerCancelled; - - event EventHandler<GenericEventArgs<TimerEventInfo>> TimerCancelled; - - event EventHandler<GenericEventArgs<TimerEventInfo>> TimerCreated; - - event EventHandler<GenericEventArgs<TimerEventInfo>> SeriesTimerCreated; - string GetEmbyTvActiveRecordingPath(string id); ActiveRecordingInfo GetActiveRecordingInfo(string path); diff --git a/MediaBrowser.Controller/LiveTv/ITunerHost.cs b/MediaBrowser.Controller/LiveTv/ITunerHost.cs index 7dced9f5e..24820abb9 100644 --- a/MediaBrowser.Controller/LiveTv/ITunerHost.cs +++ b/MediaBrowser.Controller/LiveTv/ITunerHost.cs @@ -30,6 +30,8 @@ namespace MediaBrowser.Controller.LiveTv /// <summary> /// Gets the channels. /// </summary> + /// <param name="enableCache">Option to enable using cache.</param> + /// <param name="cancellationToken">The CancellationToken for this operation.</param> /// <returns>Task<IEnumerable<ChannelInfo>>.</returns> Task<List<ChannelInfo>> GetChannels(bool enableCache, CancellationToken cancellationToken); @@ -47,6 +49,7 @@ namespace MediaBrowser.Controller.LiveTv /// <param name="streamId">The stream identifier.</param> /// <param name="currentLiveStreams">The current live streams.</param> /// <param name="cancellationToken">The cancellation token to cancel operation.</param> + /// <returns>Live stream wrapped in a task.</returns> Task<ILiveStream> GetChannelStream(string channelId, string streamId, List<ILiveStream> currentLiveStreams, CancellationToken cancellationToken); /// <summary> diff --git a/MediaBrowser.Controller/LiveTv/LiveTvChannel.cs b/MediaBrowser.Controller/LiveTv/LiveTvChannel.cs index ecd3d10d9..074e023e8 100644 --- a/MediaBrowser.Controller/LiveTv/LiveTvChannel.cs +++ b/MediaBrowser.Controller/LiveTv/LiveTvChannel.cs @@ -18,23 +18,6 @@ namespace MediaBrowser.Controller.LiveTv { public class LiveTvChannel : BaseItem, IHasMediaSources, IHasProgramAttributes { - public override List<string> GetUserDataKeys() - { - var list = base.GetUserDataKeys(); - - if (!ConfigurationManager.Configuration.DisableLiveTvChannelUserDataName) - { - list.Insert(0, GetClientTypeName() + "-" + Name); - } - - return list; - } - - public override UnratedItem GetBlockUnratedType() - { - return UnratedItem.LiveTvChannel; - } - [JsonIgnore] public override bool SupportsPositionTicksResume => false; @@ -59,6 +42,67 @@ namespace MediaBrowser.Controller.LiveTv [JsonIgnore] public override LocationType LocationType => LocationType.Remote; + [JsonIgnore] + public override string MediaType => ChannelType == ChannelType.Radio ? Model.Entities.MediaType.Audio : Model.Entities.MediaType.Video; + + [JsonIgnore] + public bool IsMovie { get; set; } + + /// <summary> + /// Gets or sets a value indicating whether this instance is sports. + /// </summary> + /// <value><c>true</c> if this instance is sports; otherwise, <c>false</c>.</value> + [JsonIgnore] + public bool IsSports { get; set; } + + /// <summary> + /// Gets or sets a value indicating whether this instance is series. + /// </summary> + /// <value><c>true</c> if this instance is series; otherwise, <c>false</c>.</value> + [JsonIgnore] + public bool IsSeries { get; set; } + + /// <summary> + /// Gets or sets a value indicating whether this instance is news. + /// </summary> + /// <value><c>true</c> if this instance is news; otherwise, <c>false</c>.</value> + [JsonIgnore] + public bool IsNews { get; set; } + + /// <summary> + /// Gets a value indicating whether this instance is kids. + /// </summary> + /// <value><c>true</c> if this instance is kids; otherwise, <c>false</c>.</value> + [JsonIgnore] + public bool IsKids => Tags.Contains("Kids", StringComparer.OrdinalIgnoreCase); + + [JsonIgnore] + public bool IsRepeat { get; set; } + + /// <summary> + /// Gets or sets the episode title. + /// </summary> + /// <value>The episode title.</value> + [JsonIgnore] + public string EpisodeTitle { get; set; } + + public override List<string> GetUserDataKeys() + { + var list = base.GetUserDataKeys(); + + if (!ConfigurationManager.Configuration.DisableLiveTvChannelUserDataName) + { + list.Insert(0, GetClientTypeName() + "-" + Name); + } + + return list; + } + + public override UnratedItem GetBlockUnratedType() + { + return UnratedItem.LiveTvChannel; + } + protected override string CreateSortName() { if (!string.IsNullOrEmpty(Number)) @@ -74,9 +118,6 @@ namespace MediaBrowser.Controller.LiveTv return (Number ?? string.Empty) + "-" + (Name ?? string.Empty); } - [JsonIgnore] - public override string MediaType => ChannelType == ChannelType.Radio ? Model.Entities.MediaType.Audio : Model.Entities.MediaType.Video; - public override string GetClientTypeName() { return "TvChannel"; @@ -122,46 +163,5 @@ namespace MediaBrowser.Controller.LiveTv { return false; } - - [JsonIgnore] - public bool IsMovie { get; set; } - - /// <summary> - /// Gets or sets a value indicating whether this instance is sports. - /// </summary> - /// <value><c>true</c> if this instance is sports; otherwise, <c>false</c>.</value> - [JsonIgnore] - public bool IsSports { get; set; } - - /// <summary> - /// Gets or sets a value indicating whether this instance is series. - /// </summary> - /// <value><c>true</c> if this instance is series; otherwise, <c>false</c>.</value> - [JsonIgnore] - public bool IsSeries { get; set; } - - /// <summary> - /// Gets or sets a value indicating whether this instance is news. - /// </summary> - /// <value><c>true</c> if this instance is news; otherwise, <c>false</c>.</value> - [JsonIgnore] - public bool IsNews { get; set; } - - /// <summary> - /// Gets a value indicating whether this instance is kids. - /// </summary> - /// <value><c>true</c> if this instance is kids; otherwise, <c>false</c>.</value> - [JsonIgnore] - public bool IsKids => Tags.Contains("Kids", StringComparer.OrdinalIgnoreCase); - - [JsonIgnore] - public bool IsRepeat { get; set; } - - /// <summary> - /// Gets or sets the episode title. - /// </summary> - /// <value>The episode title.</value> - [JsonIgnore] - public string EpisodeTitle { get; set; } } } diff --git a/MediaBrowser.Controller/LiveTv/LiveTvProgram.cs b/MediaBrowser.Controller/LiveTv/LiveTvProgram.cs index 9d638a0bf..111dc0d27 100644 --- a/MediaBrowser.Controller/LiveTv/LiveTvProgram.cs +++ b/MediaBrowser.Controller/LiveTv/LiveTvProgram.cs @@ -1,6 +1,6 @@ #nullable disable -#pragma warning disable CS1591 +#pragma warning disable CS1591, SA1306 using System; using System.Collections.Generic; @@ -19,54 +19,14 @@ namespace MediaBrowser.Controller.LiveTv { public class LiveTvProgram : BaseItem, IHasLookupInfo<ItemLookupInfo>, IHasStartDate, IHasProgramAttributes { + private static string EmbyServiceName = "Emby"; + public LiveTvProgram() { IsVirtualItem = true; } - public override List<string> GetUserDataKeys() - { - var list = base.GetUserDataKeys(); - - if (!IsSeries) - { - var key = this.GetProviderId(MetadataProvider.Imdb); - if (!string.IsNullOrEmpty(key)) - { - list.Insert(0, key); - } - - key = this.GetProviderId(MetadataProvider.Tmdb); - if (!string.IsNullOrEmpty(key)) - { - list.Insert(0, key); - } - } - else if (!string.IsNullOrEmpty(EpisodeTitle)) - { - var name = GetClientTypeName(); - - list.Insert(0, name + "-" + Name + (EpisodeTitle ?? string.Empty)); - } - - return list; - } - - private static string EmbyServiceName = "Emby"; - - public override double GetDefaultPrimaryImageAspectRatio() - { - var serviceName = ServiceName; - - if (string.Equals(serviceName, EmbyServiceName, StringComparison.OrdinalIgnoreCase) || string.Equals(serviceName, "Next Pvr", StringComparison.OrdinalIgnoreCase)) - { - return 2.0 / 3; - } - else - { - return 16.0 / 9; - } - } + public string SeriesName { get; set; } [JsonIgnore] public override SourceType SourceType => SourceType.LiveTV; @@ -182,6 +142,66 @@ namespace MediaBrowser.Controller.LiveTv } } + [JsonIgnore] + public override bool SupportsPeople + { + get + { + // Optimization + if (IsNews || IsSports) + { + return false; + } + + return base.SupportsPeople; + } + } + + [JsonIgnore] + public override bool SupportsAncestors => false; + + public override List<string> GetUserDataKeys() + { + var list = base.GetUserDataKeys(); + + if (!IsSeries) + { + var key = this.GetProviderId(MetadataProvider.Imdb); + if (!string.IsNullOrEmpty(key)) + { + list.Insert(0, key); + } + + key = this.GetProviderId(MetadataProvider.Tmdb); + if (!string.IsNullOrEmpty(key)) + { + list.Insert(0, key); + } + } + else if (!string.IsNullOrEmpty(EpisodeTitle)) + { + var name = GetClientTypeName(); + + list.Insert(0, name + "-" + Name + (EpisodeTitle ?? string.Empty)); + } + + return list; + } + + public override double GetDefaultPrimaryImageAspectRatio() + { + var serviceName = ServiceName; + + if (string.Equals(serviceName, EmbyServiceName, StringComparison.OrdinalIgnoreCase) || string.Equals(serviceName, "Next Pvr", StringComparison.OrdinalIgnoreCase)) + { + return 2.0 / 3; + } + else + { + return 16.0 / 9; + } + } + public override string GetClientTypeName() { return "Program"; @@ -202,24 +222,6 @@ namespace MediaBrowser.Controller.LiveTv return false; } - [JsonIgnore] - public override bool SupportsPeople - { - get - { - // Optimization - if (IsNews || IsSports) - { - return false; - } - - return base.SupportsPeople; - } - } - - [JsonIgnore] - public override bool SupportsAncestors => false; - private LiveTvOptions GetConfiguration() { return ConfigurationManager.GetConfiguration<LiveTvOptions>("livetv"); @@ -273,7 +275,5 @@ namespace MediaBrowser.Controller.LiveTv return list; } - - public string SeriesName { get; set; } } } diff --git a/MediaBrowser.Controller/MediaBrowser.Controller.csproj b/MediaBrowser.Controller/MediaBrowser.Controller.csproj index 4bed112e4..0f697bccc 100644 --- a/MediaBrowser.Controller/MediaBrowser.Controller.csproj +++ b/MediaBrowser.Controller/MediaBrowser.Controller.csproj @@ -35,14 +35,15 @@ <TargetFramework>net5.0</TargetFramework> <GenerateAssemblyInfo>false</GenerateAssemblyInfo> <GenerateDocumentationFile>true</GenerateDocumentationFile> - <TreatWarningsAsErrors Condition=" '$(Configuration)' == 'Release' ">true</TreatWarningsAsErrors> - <Nullable>enable</Nullable> - <AnalysisMode Condition=" '$(Configuration)' == 'Debug' ">AllEnabledByDefault</AnalysisMode> - <CodeAnalysisRuleSet>../jellyfin.ruleset</CodeAnalysisRuleSet> <PublishRepositoryUrl>true</PublishRepositoryUrl> <EmbedUntrackedSources>true</EmbedUntrackedSources> <IncludeSymbols>true</IncludeSymbols> <SymbolPackageFormat>snupkg</SymbolPackageFormat> + <TreatWarningsAsErrors>false</TreatWarningsAsErrors> + </PropertyGroup> + + <PropertyGroup Condition=" '$(Configuration)' == 'Release'"> + <TreatWarningsAsErrors>true</TreatWarningsAsErrors> </PropertyGroup> <PropertyGroup Condition=" '$(Stability)'=='Unstable'"> diff --git a/MediaBrowser.Controller/MediaEncoding/BaseEncodingJobOptions.cs b/MediaBrowser.Controller/MediaEncoding/BaseEncodingJobOptions.cs index 745ee6bdb..dd6f468da 100644 --- a/MediaBrowser.Controller/MediaEncoding/BaseEncodingJobOptions.cs +++ b/MediaBrowser.Controller/MediaEncoding/BaseEncodingJobOptions.cs @@ -10,6 +10,15 @@ namespace MediaBrowser.Controller.MediaEncoding { public class BaseEncodingJobOptions { + public BaseEncodingJobOptions() + { + EnableAutoStreamCopy = true; + AllowVideoStreamCopy = true; + AllowAudioStreamCopy = true; + Context = EncodingContext.Streaming; + StreamOptions = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase); + } + /// <summary> /// Gets or sets the id. /// </summary> @@ -191,14 +200,5 @@ namespace MediaBrowser.Controller.MediaEncoding return null; } - - public BaseEncodingJobOptions() - { - EnableAutoStreamCopy = true; - AllowVideoStreamCopy = true; - AllowAudioStreamCopy = true; - Context = EncodingContext.Streaming; - StreamOptions = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase); - } } }
\ No newline at end of file diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index 3f90de318..53d238ced 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -189,6 +189,9 @@ namespace MediaBrowser.Controller.MediaEncoding /// <summary> /// Gets the name of the output video codec. /// </summary> + /// <param name="state">Encording state.</param> + /// <param name="encodingOptions">Encoding options.</param> + /// <returns>Encoder string.</returns> public string GetVideoEncoder(EncodingJobInfo state, EncodingOptions encodingOptions) { var codec = state.OutputVideoCodec; @@ -343,6 +346,11 @@ namespace MediaBrowser.Controller.MediaEncoding return container; } + /// <summary> + /// Gets decoder from a codec. + /// </summary> + /// <param name="codec">Codec to use.</param> + /// <returns>Decoder string.</returns> public string GetDecoderFromCodec(string codec) { // For these need to find out the ffmpeg names @@ -372,6 +380,8 @@ namespace MediaBrowser.Controller.MediaEncoding /// <summary> /// Infers the audio codec based on the url. /// </summary> + /// <param name="container">Container to use.</param> + /// <returns>Codec string.</returns> public string InferAudioCodec(string container) { var ext = "." + (container ?? string.Empty); @@ -517,6 +527,9 @@ namespace MediaBrowser.Controller.MediaEncoding /// <summary> /// Gets the input argument. /// </summary> + /// <param name="state">Encoding state.</param> + /// <param name="options">Encoding options.</param> + /// <returns>Input arguments.</returns> public string GetInputArgument(EncodingJobInfo state, EncodingOptions options) { var arg = new StringBuilder(); @@ -1002,6 +1015,11 @@ namespace MediaBrowser.Controller.MediaEncoding /// <summary> /// Gets the video bitrate to specify on the command line. /// </summary> + /// <param name="state">Encoding state.</param> + /// <param name="videoEncoder">Video encoder to use.</param> + /// <param name="encodingOptions">Encoding options.</param> + /// <param name="defaultPreset">Default present to use for encoding.</param> + /// <returns>Video bitrate.</returns> public string GetVideoQualityParam(EncodingJobInfo state, string videoEncoder, EncodingOptions encodingOptions, string defaultPreset) { var param = string.Empty; @@ -2003,8 +2021,12 @@ namespace MediaBrowser.Controller.MediaEncoding } /// <summary> - /// Gets the graphical subtitle param. + /// Gets the graphical subtitle parameter. /// </summary> + /// <param name="state">Encoding state.</param> + /// <param name="options">Encoding options.</param> + /// <param name="outputVideoCodec">Video codec to use.</param> + /// <returns>Graphical subtitle parameter.</returns> public string GetGraphicalSubtitleParam( EncodingJobInfo state, EncodingOptions options, @@ -2552,6 +2574,13 @@ namespace MediaBrowser.Controller.MediaEncoding return string.Format(CultureInfo.InvariantCulture, filter, widthParam, heightParam); } + /// <summary> + /// Gets the output size parameter. + /// </summary> + /// <param name="state">Encoding state.</param> + /// <param name="options">Encoding options.</param> + /// <param name="outputVideoCodec">Video codec to use.</param> + /// <returns>The output size parameter.</returns> public string GetOutputSizeParam( EncodingJobInfo state, EncodingOptions options, @@ -2562,8 +2591,13 @@ namespace MediaBrowser.Controller.MediaEncoding } /// <summary> + /// Gets the output size parameter. /// If we're going to put a fixed size on the command line, this will calculate it. /// </summary> + /// <param name="state">Encoding state.</param> + /// <param name="options">Encoding options.</param> + /// <param name="outputVideoCodec">Video codec to use.</param> + /// <returns>The output size parameter.</returns> public string GetOutputSizeParamInternal( EncodingJobInfo state, EncodingOptions options, @@ -3111,6 +3145,10 @@ namespace MediaBrowser.Controller.MediaEncoding /// <summary> /// Gets the number of threads. /// </summary> + /// <param name="state">Encoding state.</param> + /// <param name="encodingOptions">Encoding options.</param> + /// <param name="outputVideoCodec">Video codec to use.</param> + /// <returns>Number of threads.</returns> #nullable enable public static int GetNumberOfThreads(EncodingJobInfo? state, EncodingOptions encodingOptions, string? outputVideoCodec) { @@ -3759,6 +3797,11 @@ namespace MediaBrowser.Controller.MediaEncoding /// <summary> /// Gets a hw decoder name. /// </summary> + /// <param name="options">Encoding options.</param> + /// <param name="decoder">Decoder to use.</param> + /// <param name="videoCodec">Video codec to use.</param> + /// <param name="isColorDepth10">Specifies if color depth 10.</param> + /// <returns>Hardware decoder name.</returns> public string GetHwDecoderName(EncodingOptions options, string decoder, string videoCodec, bool isColorDepth10) { var isCodecAvailable = _mediaEncoder.SupportsDecoder(decoder) && options.HardwareDecodingCodecs.Contains(videoCodec, StringComparer.OrdinalIgnoreCase); @@ -3777,6 +3820,11 @@ namespace MediaBrowser.Controller.MediaEncoding /// <summary> /// Gets a hwaccel type to use as a hardware decoder(dxva/vaapi) depending on the system. /// </summary> + /// <param name="state">Encoding state.</param> + /// <param name="options">Encoding options.</param> + /// <param name="videoCodec">Video codec to use.</param> + /// <param name="isColorDepth10">Specifies if color depth 10.</param> + /// <returns>Hardware accelerator type.</returns> public string GetHwaccelType(EncodingJobInfo state, EncodingOptions options, string videoCodec, bool isColorDepth10) { var isWindows = OperatingSystem.IsWindows(); diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs b/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs index bc0318ad7..fa9f40d60 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs @@ -1,6 +1,6 @@ #nullable disable -#pragma warning disable CS1591 +#pragma warning disable CS1591, SA1401 using System; using System.Collections.Generic; @@ -20,6 +20,44 @@ namespace MediaBrowser.Controller.MediaEncoding // For now, a common base class until the API and MediaEncoding classes are unified public class EncodingJobInfo { + public int? OutputAudioBitrate; + public int? OutputAudioChannels; + + private TranscodeReason[] _transcodeReasons = null; + + public EncodingJobInfo(TranscodingJobType jobType) + { + TranscodingType = jobType; + RemoteHttpHeaders = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase); + SupportedAudioCodecs = Array.Empty<string>(); + SupportedVideoCodecs = Array.Empty<string>(); + SupportedSubtitleCodecs = Array.Empty<string>(); + } + + public TranscodeReason[] TranscodeReasons + { + get + { + if (_transcodeReasons == null) + { + 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)) + .ToArray(); + } + + return _transcodeReasons; + } + } + + public IProgress<double> Progress { get; set; } + public MediaStream VideoStream { get; set; } public VideoType VideoType { get; set; } @@ -58,40 +96,6 @@ namespace MediaBrowser.Controller.MediaEncoding public string MimeType { get; set; } - public string GetMimeType(string outputPath, bool enableStreamDefault = true) - { - if (!string.IsNullOrEmpty(MimeType)) - { - return MimeType; - } - - return MimeTypes.GetMimeType(outputPath, enableStreamDefault); - } - - private TranscodeReason[] _transcodeReasons = null; - - public TranscodeReason[] TranscodeReasons - { - get - { - if (_transcodeReasons == null) - { - 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)) - .ToArray(); - } - - return _transcodeReasons; - } - } - public bool IgnoreInputDts => MediaSource.IgnoreDts; public bool IgnoreInputIndex => MediaSource.IgnoreIndex; @@ -144,196 +148,17 @@ namespace MediaBrowser.Controller.MediaEncoding public BaseEncodingJobOptions BaseRequest { get; set; } - public long? StartTimeTicks => BaseRequest.StartTimeTicks; - - public bool CopyTimestamps => BaseRequest.CopyTimestamps; - - public int? OutputAudioBitrate; - public int? OutputAudioChannels; - - public bool DeInterlace(string videoCodec, bool forceDeinterlaceIfSourceIsInterlaced) - { - var videoStream = VideoStream; - var isInputInterlaced = videoStream != null && videoStream.IsInterlaced; - - if (!isInputInterlaced) - { - return false; - } - - // Support general param - if (BaseRequest.DeInterlace) - { - return true; - } - - if (!string.IsNullOrEmpty(videoCodec)) - { - if (string.Equals(BaseRequest.GetOption(videoCodec, "deinterlace"), "true", StringComparison.OrdinalIgnoreCase)) - { - return true; - } - } - - return forceDeinterlaceIfSourceIsInterlaced && isInputInterlaced; - } - - public string[] GetRequestedProfiles(string codec) - { - if (!string.IsNullOrEmpty(BaseRequest.Profile)) - { - return BaseRequest.Profile.Split(new[] { '|', ',' }, StringSplitOptions.RemoveEmptyEntries); - } - - if (!string.IsNullOrEmpty(codec)) - { - var profile = BaseRequest.GetOption(codec, "profile"); - - if (!string.IsNullOrEmpty(profile)) - { - return profile.Split(new[] { '|', ',' }, StringSplitOptions.RemoveEmptyEntries); - } - } - - return Array.Empty<string>(); - } - - public string GetRequestedLevel(string codec) - { - if (!string.IsNullOrEmpty(BaseRequest.Level)) - { - return BaseRequest.Level; - } - - if (!string.IsNullOrEmpty(codec)) - { - return BaseRequest.GetOption(codec, "level"); - } - - return null; - } - - public int? GetRequestedMaxRefFrames(string codec) - { - if (BaseRequest.MaxRefFrames.HasValue) - { - return BaseRequest.MaxRefFrames; - } - - if (!string.IsNullOrEmpty(codec)) - { - var value = BaseRequest.GetOption(codec, "maxrefframes"); - if (!string.IsNullOrEmpty(value) - && int.TryParse(value, NumberStyles.Any, CultureInfo.InvariantCulture, out var result)) - { - return result; - } - } - - return null; - } - - public int? GetRequestedVideoBitDepth(string codec) - { - if (BaseRequest.MaxVideoBitDepth.HasValue) - { - return BaseRequest.MaxVideoBitDepth; - } - - if (!string.IsNullOrEmpty(codec)) - { - var value = BaseRequest.GetOption(codec, "videobitdepth"); - if (!string.IsNullOrEmpty(value) - && int.TryParse(value, NumberStyles.Any, CultureInfo.InvariantCulture, out var result)) - { - return result; - } - } - - return null; - } - - public int? GetRequestedAudioBitDepth(string codec) - { - if (BaseRequest.MaxAudioBitDepth.HasValue) - { - return BaseRequest.MaxAudioBitDepth; - } - - if (!string.IsNullOrEmpty(codec)) - { - var value = BaseRequest.GetOption(codec, "audiobitdepth"); - if (!string.IsNullOrEmpty(value) - && int.TryParse(value, NumberStyles.Any, CultureInfo.InvariantCulture, out var result)) - { - return result; - } - } - - return null; - } - - public int? GetRequestedAudioChannels(string codec) - { - if (!string.IsNullOrEmpty(codec)) - { - var value = BaseRequest.GetOption(codec, "audiochannels"); - if (!string.IsNullOrEmpty(value) - && int.TryParse(value, NumberStyles.Any, CultureInfo.InvariantCulture, out var result)) - { - return result; - } - } - - if (BaseRequest.MaxAudioChannels.HasValue) - { - return BaseRequest.MaxAudioChannels; - } - - if (BaseRequest.AudioChannels.HasValue) - { - return BaseRequest.AudioChannels; - } - - if (BaseRequest.TranscodingMaxAudioChannels.HasValue) - { - return BaseRequest.TranscodingMaxAudioChannels; - } - - return null; - } - public bool IsVideoRequest { get; set; } public TranscodingJobType TranscodingType { get; set; } - public EncodingJobInfo(TranscodingJobType jobType) - { - TranscodingType = jobType; - RemoteHttpHeaders = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase); - SupportedAudioCodecs = Array.Empty<string>(); - SupportedVideoCodecs = Array.Empty<string>(); - SupportedSubtitleCodecs = Array.Empty<string>(); - } + public long? StartTimeTicks => BaseRequest.StartTimeTicks; + + public bool CopyTimestamps => BaseRequest.CopyTimestamps; public bool IsSegmentedLiveStream => TranscodingType != TranscodingJobType.Progressive && !RunTimeTicks.HasValue; - public bool EnableBreakOnNonKeyFrames(string videoCodec) - { - if (TranscodingType != TranscodingJobType.Progressive) - { - if (IsSegmentedLiveStream) - { - return false; - } - - return BaseRequest.BreakOnNonKeyFrames && EncodingHelper.IsCopyCodec(videoCodec); - } - - return false; - } - public int? TotalOutputBitrate => (OutputAudioBitrate ?? 0) + (OutputVideoBitrate ?? 0); public int? OutputWidth @@ -682,6 +507,21 @@ namespace MediaBrowser.Controller.MediaEncoding public int HlsListSize => 0; + public bool EnableBreakOnNonKeyFrames(string videoCodec) + { + if (TranscodingType != TranscodingJobType.Progressive) + { + if (IsSegmentedLiveStream) + { + return false; + } + + return BaseRequest.BreakOnNonKeyFrames && EncodingHelper.IsCopyCodec(videoCodec); + } + + return false; + } + private int? GetMediaStreamCount(MediaStreamType type, int limit) { var count = MediaSource.GetStreamCount(type); @@ -694,7 +534,167 @@ namespace MediaBrowser.Controller.MediaEncoding return count; } - public IProgress<double> Progress { get; set; } + public string GetMimeType(string outputPath, bool enableStreamDefault = true) + { + if (!string.IsNullOrEmpty(MimeType)) + { + return MimeType; + } + + return MimeTypes.GetMimeType(outputPath, enableStreamDefault); + } + + public bool DeInterlace(string videoCodec, bool forceDeinterlaceIfSourceIsInterlaced) + { + var videoStream = VideoStream; + var isInputInterlaced = videoStream != null && videoStream.IsInterlaced; + + if (!isInputInterlaced) + { + return false; + } + + // Support general param + if (BaseRequest.DeInterlace) + { + return true; + } + + if (!string.IsNullOrEmpty(videoCodec)) + { + if (string.Equals(BaseRequest.GetOption(videoCodec, "deinterlace"), "true", StringComparison.OrdinalIgnoreCase)) + { + return true; + } + } + + return forceDeinterlaceIfSourceIsInterlaced && isInputInterlaced; + } + + public string[] GetRequestedProfiles(string codec) + { + if (!string.IsNullOrEmpty(BaseRequest.Profile)) + { + return BaseRequest.Profile.Split(new[] { '|', ',' }, StringSplitOptions.RemoveEmptyEntries); + } + + if (!string.IsNullOrEmpty(codec)) + { + var profile = BaseRequest.GetOption(codec, "profile"); + + if (!string.IsNullOrEmpty(profile)) + { + return profile.Split(new[] { '|', ',' }, StringSplitOptions.RemoveEmptyEntries); + } + } + + return Array.Empty<string>(); + } + + public string GetRequestedLevel(string codec) + { + if (!string.IsNullOrEmpty(BaseRequest.Level)) + { + return BaseRequest.Level; + } + + if (!string.IsNullOrEmpty(codec)) + { + return BaseRequest.GetOption(codec, "level"); + } + + return null; + } + + public int? GetRequestedMaxRefFrames(string codec) + { + if (BaseRequest.MaxRefFrames.HasValue) + { + return BaseRequest.MaxRefFrames; + } + + if (!string.IsNullOrEmpty(codec)) + { + var value = BaseRequest.GetOption(codec, "maxrefframes"); + if (!string.IsNullOrEmpty(value) + && int.TryParse(value, NumberStyles.Any, CultureInfo.InvariantCulture, out var result)) + { + return result; + } + } + + return null; + } + + public int? GetRequestedVideoBitDepth(string codec) + { + if (BaseRequest.MaxVideoBitDepth.HasValue) + { + return BaseRequest.MaxVideoBitDepth; + } + + if (!string.IsNullOrEmpty(codec)) + { + var value = BaseRequest.GetOption(codec, "videobitdepth"); + if (!string.IsNullOrEmpty(value) + && int.TryParse(value, NumberStyles.Any, CultureInfo.InvariantCulture, out var result)) + { + return result; + } + } + + return null; + } + + public int? GetRequestedAudioBitDepth(string codec) + { + if (BaseRequest.MaxAudioBitDepth.HasValue) + { + return BaseRequest.MaxAudioBitDepth; + } + + if (!string.IsNullOrEmpty(codec)) + { + var value = BaseRequest.GetOption(codec, "audiobitdepth"); + if (!string.IsNullOrEmpty(value) + && int.TryParse(value, NumberStyles.Any, CultureInfo.InvariantCulture, out var result)) + { + return result; + } + } + + return null; + } + + public int? GetRequestedAudioChannels(string codec) + { + if (!string.IsNullOrEmpty(codec)) + { + var value = BaseRequest.GetOption(codec, "audiochannels"); + if (!string.IsNullOrEmpty(value) + && int.TryParse(value, NumberStyles.Any, CultureInfo.InvariantCulture, out var result)) + { + return result; + } + } + + if (BaseRequest.MaxAudioChannels.HasValue) + { + return BaseRequest.MaxAudioChannels; + } + + if (BaseRequest.AudioChannels.HasValue) + { + return BaseRequest.AudioChannels; + } + + if (BaseRequest.TranscodingMaxAudioChannels.HasValue) + { + return BaseRequest.TranscodingMaxAudioChannels; + } + + return null; + } public virtual void ReportTranscodingProgress(TimeSpan? transcodingPosition, float? framerate, double? percentComplete, long? bytesTranscoded, int? bitRate) { diff --git a/MediaBrowser.Controller/MediaEncoding/IEncodingManager.cs b/MediaBrowser.Controller/MediaEncoding/IEncodingManager.cs index 773547872..8ce40a58d 100644 --- a/MediaBrowser.Controller/MediaEncoding/IEncodingManager.cs +++ b/MediaBrowser.Controller/MediaEncoding/IEncodingManager.cs @@ -16,6 +16,13 @@ namespace MediaBrowser.Controller.MediaEncoding /// <summary> /// Refreshes the chapter images. /// </summary> + /// <param name="video">Video to use.</param> + /// <param name="directoryService">Directory service to use.</param> + /// <param name="chapters">Set of chapters to refresh.</param> + /// <param name="extractImages">Option to extract images.</param> + /// <param name="saveChapters">Option to save chapters.</param> + /// <param name="cancellationToken">CancellationToken to use for operation.</param> + /// <returns><c>true</c> if successful, <c>false</c> if not.</returns> Task<bool> RefreshChapterImages(Video video, IDirectoryService directoryService, IReadOnlyList<ChapterInfo> chapters, bool extractImages, bool saveChapters, CancellationToken cancellationToken); } } diff --git a/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs b/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs index 31913acef..15d4fd494 100644 --- a/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs +++ b/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs @@ -83,13 +83,42 @@ namespace MediaBrowser.Controller.MediaEncoding /// <summary> /// Extracts the video image. /// </summary> + /// <param name="inputFile">Input file.</param> + /// <param name="container">Video container type.</param> + /// <param name="mediaSource">Media source information.</param> + /// <param name="videoStream">Media stream information.</param> + /// <param name="threedFormat">Video 3D format.</param> + /// <param name="offset">Time offset.</param> + /// <param name="cancellationToken">CancellationToken to use for operation.</param> + /// <returns>Location of video image.</returns> Task<string> ExtractVideoImage(string inputFile, string container, MediaSourceInfo mediaSource, MediaStream videoStream, Video3DFormat? threedFormat, TimeSpan? offset, CancellationToken cancellationToken); + /// <summary> + /// Extracts the video image. + /// </summary> + /// <param name="inputFile">Input file.</param> + /// <param name="container">Video container type.</param> + /// <param name="mediaSource">Media source information.</param> + /// <param name="imageStream">Media stream information.</param> + /// <param name="imageStreamIndex">Index of the stream to extract from.</param> + /// <param name="cancellationToken">CancellationToken to use for operation.</param> + /// <returns>Location of video image.</returns> Task<string> ExtractVideoImage(string inputFile, string container, MediaSourceInfo mediaSource, MediaStream imageStream, int? imageStreamIndex, CancellationToken cancellationToken); /// <summary> /// Extracts the video images on interval. /// </summary> + /// <param name="inputFile">Input file.</param> + /// <param name="container">Video container type.</param> + /// <param name="videoStream">Media stream information.</param> + /// <param name="mediaSource">Media source information.</param> + /// <param name="threedFormat">Video 3D format.</param> + /// <param name="interval">Time interval.</param> + /// <param name="targetDirectory">Directory to write images.</param> + /// <param name="filenamePrefix">Filename prefix to use.</param> + /// <param name="maxWidth">Maximum width of image.</param> + /// <param name="cancellationToken">CancellationToken to use for operation.</param> + /// <returns>A task.</returns> Task ExtractVideoImagesOnInterval( string inputFile, string container, @@ -134,10 +163,24 @@ namespace MediaBrowser.Controller.MediaEncoding /// <returns>System.String.</returns> string EscapeSubtitleFilterPath(string path); + /// <summary> + /// Sets the path to find FFmpeg. + /// </summary> void SetFFmpegPath(); + /// <summary> + /// Updates the encoder path. + /// </summary> + /// <param name="path">The path.</param> + /// <param name="pathType">The type of path.</param> void UpdateEncoderPath(string path, string pathType); + /// <summary> + /// Gets the primary playlist of .vob files. + /// </summary> + /// <param name="path">The to the .vob files.</param> + /// <param name="titleNumber">The title number to start with.</param> + /// <returns>A playlist.</returns> IEnumerable<string> GetPrimaryPlaylistVobFiles(string path, uint? titleNumber); } } diff --git a/MediaBrowser.Controller/MediaEncoding/ISubtitleEncoder.cs b/MediaBrowser.Controller/MediaEncoding/ISubtitleEncoder.cs index 3fb2c47e1..4483cf708 100644 --- a/MediaBrowser.Controller/MediaEncoding/ISubtitleEncoder.cs +++ b/MediaBrowser.Controller/MediaEncoding/ISubtitleEncoder.cs @@ -15,6 +15,14 @@ namespace MediaBrowser.Controller.MediaEncoding /// <summary> /// Gets the subtitles. /// </summary> + /// <param name="item">Item to use.</param> + /// <param name="mediaSourceId">Media source.</param> + /// <param name="subtitleStreamIndex">Subtitle stream to use.</param> + /// <param name="outputFormat">Output format to use.</param> + /// <param name="startTimeTicks">Start time.</param> + /// <param name="endTimeTicks">End time.</param> + /// <param name="preserveOriginalTimestamps">Option to preserve original timestamps.</param> + /// <param name="cancellationToken">The cancellation token for the operation.</param> /// <returns>Task{Stream}.</returns> Task<Stream> GetSubtitles( BaseItem item, diff --git a/MediaBrowser.Controller/Providers/AlbumInfo.cs b/MediaBrowser.Controller/Providers/AlbumInfo.cs index c7fad5974..aefa520e7 100644 --- a/MediaBrowser.Controller/Providers/AlbumInfo.cs +++ b/MediaBrowser.Controller/Providers/AlbumInfo.cs @@ -1,4 +1,4 @@ -#pragma warning disable CS1591 +#pragma warning disable CA1002, CA2227, CS1591 using System; using System.Collections.Generic; diff --git a/MediaBrowser.Controller/Providers/ArtistInfo.cs b/MediaBrowser.Controller/Providers/ArtistInfo.cs index e9181f476..4854d1a5f 100644 --- a/MediaBrowser.Controller/Providers/ArtistInfo.cs +++ b/MediaBrowser.Controller/Providers/ArtistInfo.cs @@ -1,4 +1,4 @@ -#pragma warning disable CS1591 +#pragma warning disable CA1002, CA2227, CS1591 using System.Collections.Generic; diff --git a/MediaBrowser.Controller/Providers/EpisodeInfo.cs b/MediaBrowser.Controller/Providers/EpisodeInfo.cs index 0c932fa87..b59a03738 100644 --- a/MediaBrowser.Controller/Providers/EpisodeInfo.cs +++ b/MediaBrowser.Controller/Providers/EpisodeInfo.cs @@ -1,6 +1,6 @@ #nullable disable -#pragma warning disable CS1591 +#pragma warning disable CA2227, CS1591 using System; using System.Collections.Generic; diff --git a/MediaBrowser.Controller/Providers/IDirectoryService.cs b/MediaBrowser.Controller/Providers/IDirectoryService.cs index b1a36e102..e5138ca14 100644 --- a/MediaBrowser.Controller/Providers/IDirectoryService.cs +++ b/MediaBrowser.Controller/Providers/IDirectoryService.cs @@ -1,4 +1,4 @@ -#pragma warning disable CS1591 +#pragma warning disable CA1002, CS1591 using System.Collections.Generic; using MediaBrowser.Model.IO; diff --git a/MediaBrowser.Controller/Providers/IProviderManager.cs b/MediaBrowser.Controller/Providers/IProviderManager.cs index 684bd9e68..9f7a76be6 100644 --- a/MediaBrowser.Controller/Providers/IProviderManager.cs +++ b/MediaBrowser.Controller/Providers/IProviderManager.cs @@ -31,6 +31,9 @@ namespace MediaBrowser.Controller.Providers /// <summary> /// Queues the refresh. /// </summary> + /// <param name="itemId">Item ID.</param> + /// <param name="options">MetadataRefreshOptions for operation.</param> + /// <param name="priority">RefreshPriority for operation.</param> void QueueRefresh(Guid itemId, MetadataRefreshOptions options, RefreshPriority priority); /// <summary> @@ -85,6 +88,13 @@ namespace MediaBrowser.Controller.Providers /// <summary> /// Saves the image. /// </summary> + /// <param name="item">Image to save.</param> + /// <param name="source">Source of image.</param> + /// <param name="mimeType">Mime type image.</param> + /// <param name="type">Type of image.</param> + /// <param name="imageIndex">Index of image.</param> + /// <param name="saveLocallyWithMedia">Option to save locally.</param> + /// <param name="cancellationToken">CancellationToken to use with operation.</param> /// <returns>Task.</returns> Task SaveImage(BaseItem item, string source, string mimeType, ImageType type, int? imageIndex, bool? saveLocallyWithMedia, CancellationToken cancellationToken); @@ -93,6 +103,11 @@ namespace MediaBrowser.Controller.Providers /// <summary> /// Adds the metadata providers. /// </summary> + /// <param name="imageProviders">Image providers to use.</param> + /// <param name="metadataServices">Metadata services to use.</param> + /// <param name="metadataProviders">Metadata providers to use.</param> + /// <param name="metadataSavers">Metadata savers to use.</param> + /// <param name="externalIds">External IDs to use.</param> void AddParts( IEnumerable<IImageProvider> imageProviders, IEnumerable<IMetadataService> metadataServices, diff --git a/MediaBrowser.Controller/Providers/ImageRefreshOptions.cs b/MediaBrowser.Controller/Providers/ImageRefreshOptions.cs index 81a22affb..2ac4c728b 100644 --- a/MediaBrowser.Controller/Providers/ImageRefreshOptions.cs +++ b/MediaBrowser.Controller/Providers/ImageRefreshOptions.cs @@ -1,6 +1,6 @@ #nullable disable -#pragma warning disable CS1591 +#pragma warning disable CA1819, CS1591 using System; using System.Linq; @@ -10,6 +10,15 @@ namespace MediaBrowser.Controller.Providers { public class ImageRefreshOptions { + public ImageRefreshOptions(IDirectoryService directoryService) + { + ImageRefreshMode = MetadataRefreshMode.Default; + DirectoryService = directoryService; + + ReplaceImages = Array.Empty<ImageType>(); + IsAutomated = true; + } + public MetadataRefreshMode ImageRefreshMode { get; set; } public IDirectoryService DirectoryService { get; private set; } @@ -20,15 +29,6 @@ namespace MediaBrowser.Controller.Providers public bool IsAutomated { get; set; } - public ImageRefreshOptions(IDirectoryService directoryService) - { - ImageRefreshMode = MetadataRefreshMode.Default; - DirectoryService = directoryService; - - ReplaceImages = Array.Empty<ImageType>(); - IsAutomated = true; - } - public bool IsReplacingImage(ImageType type) { return ImageRefreshMode == MetadataRefreshMode.FullRefresh && diff --git a/MediaBrowser.Controller/Providers/ItemLookupInfo.cs b/MediaBrowser.Controller/Providers/ItemLookupInfo.cs index 2219b62b8..460f4e500 100644 --- a/MediaBrowser.Controller/Providers/ItemLookupInfo.cs +++ b/MediaBrowser.Controller/Providers/ItemLookupInfo.cs @@ -1,6 +1,6 @@ #nullable disable -#pragma warning disable CS1591 +#pragma warning disable CA2227, CS1591 using System; using System.Collections.Generic; diff --git a/MediaBrowser.Controller/Providers/MetadataRefreshOptions.cs b/MediaBrowser.Controller/Providers/MetadataRefreshOptions.cs index 2cf536779..a42c7f8b5 100644 --- a/MediaBrowser.Controller/Providers/MetadataRefreshOptions.cs +++ b/MediaBrowser.Controller/Providers/MetadataRefreshOptions.cs @@ -1,6 +1,6 @@ #nullable disable -#pragma warning disable CS1591 +#pragma warning disable CA1819, CS1591 using System; using System.Linq; diff --git a/MediaBrowser.Controller/Providers/MetadataResult.cs b/MediaBrowser.Controller/Providers/MetadataResult.cs index 7ec1eefcd..2085ae4ad 100644 --- a/MediaBrowser.Controller/Providers/MetadataResult.cs +++ b/MediaBrowser.Controller/Providers/MetadataResult.cs @@ -1,6 +1,6 @@ #nullable disable -#pragma warning disable CS1591 +#pragma warning disable CA1002, CA2227, CS1591 using System; using System.Collections.Generic; diff --git a/MediaBrowser.Controller/Providers/SeasonInfo.cs b/MediaBrowser.Controller/Providers/SeasonInfo.cs index 7e39bc37a..1edceb0e4 100644 --- a/MediaBrowser.Controller/Providers/SeasonInfo.cs +++ b/MediaBrowser.Controller/Providers/SeasonInfo.cs @@ -1,4 +1,4 @@ -#pragma warning disable CS1591 +#pragma warning disable CA2227, CS1591 using System; using System.Collections.Generic; diff --git a/MediaBrowser.Controller/Providers/SongInfo.cs b/MediaBrowser.Controller/Providers/SongInfo.cs index c90717a2e..4b64a8a98 100644 --- a/MediaBrowser.Controller/Providers/SongInfo.cs +++ b/MediaBrowser.Controller/Providers/SongInfo.cs @@ -9,16 +9,16 @@ namespace MediaBrowser.Controller.Providers { public class SongInfo : ItemLookupInfo { - public IReadOnlyList<string> AlbumArtists { get; set; } - - public string Album { get; set; } - - public IReadOnlyList<string> Artists { get; set; } - public SongInfo() { Artists = Array.Empty<string>(); AlbumArtists = Array.Empty<string>(); } + + public IReadOnlyList<string> AlbumArtists { get; set; } + + public string Album { get; set; } + + public IReadOnlyList<string> Artists { get; set; } } } diff --git a/MediaBrowser.Controller/Security/IAuthenticationRepository.cs b/MediaBrowser.Controller/Security/IAuthenticationRepository.cs index 1dd69ccd8..bd1289c1a 100644 --- a/MediaBrowser.Controller/Security/IAuthenticationRepository.cs +++ b/MediaBrowser.Controller/Security/IAuthenticationRepository.cs @@ -13,14 +13,12 @@ namespace MediaBrowser.Controller.Security /// Creates the specified information. /// </summary> /// <param name="info">The information.</param> - /// <returns>Task.</returns> void Create(AuthenticationInfo info); /// <summary> /// Updates the specified information. /// </summary> /// <param name="info">The information.</param> - /// <returns>Task.</returns> void Update(AuthenticationInfo info); /// <summary> diff --git a/MediaBrowser.Controller/Session/ISessionController.cs b/MediaBrowser.Controller/Session/ISessionController.cs index 6bc39d6f4..b38ee1146 100644 --- a/MediaBrowser.Controller/Session/ISessionController.cs +++ b/MediaBrowser.Controller/Session/ISessionController.cs @@ -26,6 +26,12 @@ namespace MediaBrowser.Controller.Session /// <summary> /// Sends the message. /// </summary> + /// <typeparam name="T">The type of data.</typeparam> + /// <param name="name">Name of message type.</param> + /// <param name="messageId">Message ID.</param> + /// <param name="data">Data to send.</param> + /// <param name="cancellationToken">CancellationToken for operation.</param> + /// <returns>A task.</returns> Task SendMessage<T>(SessionMessageType name, Guid messageId, T data, CancellationToken cancellationToken); } } diff --git a/MediaBrowser.Controller/Session/ISessionManager.cs b/MediaBrowser.Controller/Session/ISessionManager.cs index 4c3cf5ffe..0ff32fb53 100644 --- a/MediaBrowser.Controller/Session/ISessionManager.cs +++ b/MediaBrowser.Controller/Session/ISessionManager.cs @@ -83,6 +83,7 @@ namespace MediaBrowser.Controller.Session /// <param name="deviceName">Name of the device.</param> /// <param name="remoteEndPoint">The remote end point.</param> /// <param name="user">The user.</param> + /// <returns>Session information.</returns> SessionInfo LogSessionActivity(string appName, string appVersion, string deviceId, string deviceName, string remoteEndPoint, Jellyfin.Data.Entities.User user); /// <summary> @@ -105,7 +106,7 @@ namespace MediaBrowser.Controller.Session /// </summary> /// <param name="info">The info.</param> /// <returns>Task.</returns> - /// <exception cref="ArgumentNullException"></exception> + /// <exception cref="ArgumentNullException">Throws if an argument is null.</exception> Task OnPlaybackProgress(PlaybackProgressInfo info); Task OnPlaybackProgress(PlaybackProgressInfo info, bool isAutomated); @@ -115,14 +116,13 @@ namespace MediaBrowser.Controller.Session /// </summary> /// <param name="info">The info.</param> /// <returns>Task.</returns> - /// <exception cref="ArgumentNullException"></exception> + /// <exception cref="ArgumentNullException">Throws if an argument is null.</exception> Task OnPlaybackStopped(PlaybackStopInfo info); /// <summary> /// Reports the session ended. /// </summary> /// <param name="sessionId">The session identifier.</param> - /// <returns>Task.</returns> void ReportSessionEnded(string sessionId); /// <summary> @@ -170,6 +170,7 @@ namespace MediaBrowser.Controller.Session /// <param name="session">The session.</param> /// <param name="command">The group update.</param> /// <param name="cancellationToken">The cancellation token.</param> + /// <typeparam name="T">Type of group.</typeparam> /// <returns>Task.</returns> Task SendSyncPlayGroupUpdate<T>(SessionInfo session, GroupUpdate<T> command, CancellationToken cancellationToken); @@ -196,8 +197,8 @@ namespace MediaBrowser.Controller.Session /// <summary> /// Sends the message to admin sessions. /// </summary> - /// <typeparam name="T"></typeparam> - /// <param name="name">The name.</param> + /// <typeparam name="T">Type of data.</typeparam> + /// <param name="name">Message type name.</param> /// <param name="data">The data.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <returns>Task.</returns> @@ -206,18 +207,31 @@ namespace MediaBrowser.Controller.Session /// <summary> /// Sends the message to user sessions. /// </summary> - /// <typeparam name="T"></typeparam> + /// <typeparam name="T">Type of data.</typeparam> + /// <param name="userIds">Users to send messages to.</param> + /// <param name="name">Message type name.</param> + /// <param name="data">The data.</param> + /// <param name="cancellationToken">The cancellation token.</param> /// <returns>Task.</returns> Task SendMessageToUserSessions<T>(List<Guid> userIds, SessionMessageType name, T data, CancellationToken cancellationToken); + /// <summary> + /// Sends the message to user sessions. + /// </summary> + /// <typeparam name="T">Type of data.</typeparam> + /// <param name="userIds">Users to send messages to.</param> + /// <param name="name">Message type name.</param> + /// <param name="dataFn">Data function.</param> + /// <param name="cancellationToken">The cancellation token.</param> + /// <returns>Task.</returns> Task SendMessageToUserSessions<T>(List<Guid> userIds, SessionMessageType name, Func<T> dataFn, CancellationToken cancellationToken); /// <summary> /// Sends the message to user device sessions. /// </summary> - /// <typeparam name="T"></typeparam> + /// <typeparam name="T">Type of data.</typeparam> /// <param name="deviceId">The device identifier.</param> - /// <param name="name">The name.</param> + /// <param name="name">Message type name.</param> /// <param name="data">The data.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <returns>Task.</returns> @@ -353,6 +367,8 @@ namespace MediaBrowser.Controller.Session /// <summary> /// Revokes the user tokens. /// </summary> + /// <param name="userId">User ID.</param> + /// <param name="currentAccessToken">Current access token.</param> void RevokeUserTokens(Guid userId, string currentAccessToken); /// <summary> diff --git a/MediaBrowser.LocalMetadata/MediaBrowser.LocalMetadata.csproj b/MediaBrowser.LocalMetadata/MediaBrowser.LocalMetadata.csproj index eb2077a5f..1cf8fcd1b 100644 --- a/MediaBrowser.LocalMetadata/MediaBrowser.LocalMetadata.csproj +++ b/MediaBrowser.LocalMetadata/MediaBrowser.LocalMetadata.csproj @@ -14,10 +14,6 @@ <TargetFramework>net5.0</TargetFramework> <GenerateAssemblyInfo>false</GenerateAssemblyInfo> <GenerateDocumentationFile>true</GenerateDocumentationFile> - <TreatWarningsAsErrors>true</TreatWarningsAsErrors> - <Nullable>enable</Nullable> - <AnalysisMode>AllEnabledByDefault</AnalysisMode> - <CodeAnalysisRuleSet>../jellyfin.ruleset</CodeAnalysisRuleSet> </PropertyGroup> <ItemGroup> diff --git a/MediaBrowser.LocalMetadata/Parsers/BaseItemXmlParser.cs b/MediaBrowser.LocalMetadata/Parsers/BaseItemXmlParser.cs index 32e5ac761..ef130ee74 100644 --- a/MediaBrowser.LocalMetadata/Parsers/BaseItemXmlParser.cs +++ b/MediaBrowser.LocalMetadata/Parsers/BaseItemXmlParser.cs @@ -81,7 +81,7 @@ namespace MediaBrowser.LocalMetadata.Parsers var id = info.Key + "Id"; if (!_validProviderIds.ContainsKey(id)) { - _validProviderIds.Add(id, info.Key!); + _validProviderIds.Add(id, info.Key); } } @@ -750,46 +750,6 @@ namespace MediaBrowser.LocalMetadata.Parsers item.Shares = list.ToArray(); } - private Share GetShareFromNode(XmlReader reader) - { - var share = new Share(); - - reader.MoveToContent(); - reader.Read(); - - // Loop through each element - while (!reader.EOF && reader.ReadState == ReadState.Interactive) - { - if (reader.NodeType == XmlNodeType.Element) - { - switch (reader.Name) - { - case "UserId": - { - share.UserId = reader.ReadElementContentAsString(); - break; - } - - case "CanEdit": - { - share.CanEdit = string.Equals(reader.ReadElementContentAsString(), true.ToString(CultureInfo.InvariantCulture), StringComparison.OrdinalIgnoreCase); - break; - } - - default: - reader.Skip(); - break; - } - } - else - { - reader.Read(); - } - } - - return share; - } - private void FetchFromCountriesNode(XmlReader reader) { reader.MoveToContent(); @@ -1101,7 +1061,7 @@ namespace MediaBrowser.LocalMetadata.Parsers switch (reader.Name) { case "Name": - name = reader.ReadElementContentAsString() ?? string.Empty; + name = reader.ReadElementContentAsString(); break; case "Type": @@ -1270,8 +1230,6 @@ namespace MediaBrowser.LocalMetadata.Parsers /// <returns>IEnumerable{System.String}.</returns> private IEnumerable<string> SplitNames(string value) { - value ??= string.Empty; - // Only split by comma if there is no pipe in the string // We have to be careful to not split names like Matthew, Jr. var separator = !value.Contains('|', StringComparison.Ordinal) diff --git a/MediaBrowser.LocalMetadata/Savers/BaseXmlSaver.cs b/MediaBrowser.LocalMetadata/Savers/BaseXmlSaver.cs index 98ed3dcf7..dd824206f 100644 --- a/MediaBrowser.LocalMetadata/Savers/BaseXmlSaver.cs +++ b/MediaBrowser.LocalMetadata/Savers/BaseXmlSaver.cs @@ -33,16 +33,12 @@ namespace MediaBrowser.LocalMetadata.Savers /// <param name="fileSystem">Instance of the <see cref="IFileSystem"/> interface.</param> /// <param name="configurationManager">Instance of the <see cref="IServerConfigurationManager"/> interface.</param> /// <param name="libraryManager">Instance of the <see cref="ILibraryManager"/> interface.</param> - /// <param name="userManager">Instance of the <see cref="IUserManager"/> interface.</param> - /// <param name="userDataManager">Instance of the <see cref="IUserDataManager"/> interface.</param> /// <param name="logger">Instance of the <see cref="ILogger{BaseXmlSaver}"/> interface.</param> - protected BaseXmlSaver(IFileSystem fileSystem, IServerConfigurationManager configurationManager, ILibraryManager libraryManager, IUserManager userManager, IUserDataManager userDataManager, ILogger<BaseXmlSaver> logger) + protected BaseXmlSaver(IFileSystem fileSystem, IServerConfigurationManager configurationManager, ILibraryManager libraryManager, ILogger<BaseXmlSaver> logger) { FileSystem = fileSystem; ConfigurationManager = configurationManager; LibraryManager = libraryManager; - UserManager = userManager; - UserDataManager = userDataManager; Logger = logger; } @@ -62,16 +58,6 @@ namespace MediaBrowser.LocalMetadata.Savers protected ILibraryManager LibraryManager { get; private set; } /// <summary> - /// Gets the user manager. - /// </summary> - protected IUserManager UserManager { get; private set; } - - /// <summary> - /// Gets the user data manager. - /// </summary> - protected IUserDataManager UserDataManager { get; private set; } - - /// <summary> /// Gets the logger. /// </summary> protected ILogger<BaseXmlSaver> Logger { get; private set; } @@ -334,7 +320,7 @@ namespace MediaBrowser.LocalMetadata.Savers if (runTimeTicks.HasValue) { - var timespan = TimeSpan.FromTicks(runTimeTicks!.Value); + var timespan = TimeSpan.FromTicks(runTimeTicks.Value); writer.WriteElementString("RunningTime", Math.Floor(timespan.TotalMinutes).ToString(_usCulture)); } diff --git a/MediaBrowser.LocalMetadata/Savers/BoxSetXmlSaver.cs b/MediaBrowser.LocalMetadata/Savers/BoxSetXmlSaver.cs index b08387b0c..8a5da95bf 100644 --- a/MediaBrowser.LocalMetadata/Savers/BoxSetXmlSaver.cs +++ b/MediaBrowser.LocalMetadata/Savers/BoxSetXmlSaver.cs @@ -20,11 +20,9 @@ namespace MediaBrowser.LocalMetadata.Savers /// <param name="fileSystem">Instance of the <see cref="IFileSystem"/> interface.</param> /// <param name="configurationManager">Instance of the <see cref="IServerConfigurationManager"/> interface.</param> /// <param name="libraryManager">Instance of the <see cref="ILibraryManager"/> interface.</param> - /// <param name="userManager">Instance of the <see cref="IUserManager"/> interface.</param> - /// <param name="userDataManager">Instance of the <see cref="IUserDataManager"/> interface.</param> /// <param name="logger">Instance of the <see cref="ILogger{BoxSetXmlSaver}"/> interface.</param> - public BoxSetXmlSaver(IFileSystem fileSystem, IServerConfigurationManager configurationManager, ILibraryManager libraryManager, IUserManager userManager, IUserDataManager userDataManager, ILogger<BoxSetXmlSaver> logger) - : base(fileSystem, configurationManager, libraryManager, userManager, userDataManager, logger) + public BoxSetXmlSaver(IFileSystem fileSystem, IServerConfigurationManager configurationManager, ILibraryManager libraryManager, ILogger<BoxSetXmlSaver> logger) + : base(fileSystem, configurationManager, libraryManager, logger) { } diff --git a/MediaBrowser.LocalMetadata/Savers/PlaylistXmlSaver.cs b/MediaBrowser.LocalMetadata/Savers/PlaylistXmlSaver.cs index c2f106423..76252bc09 100644 --- a/MediaBrowser.LocalMetadata/Savers/PlaylistXmlSaver.cs +++ b/MediaBrowser.LocalMetadata/Savers/PlaylistXmlSaver.cs @@ -25,11 +25,9 @@ namespace MediaBrowser.LocalMetadata.Savers /// <param name="fileSystem">Instance of the <see cref="IFileSystem"/> interface.</param> /// <param name="configurationManager">Instance of the <see cref="IServerConfigurationManager"/> interface.</param> /// <param name="libraryManager">Instance of the <see cref="ILibraryManager"/> interface.</param> - /// <param name="userManager">Instance of the <see cref="IUserManager"/> interface.</param> - /// <param name="userDataManager">Instance of the <see cref="IUserDataManager"/> interface.</param> /// <param name="logger">Instance of the <see cref="ILogger{PlaylistXmlSaver}"/> interface.</param> - public PlaylistXmlSaver(IFileSystem fileSystem, IServerConfigurationManager configurationManager, ILibraryManager libraryManager, IUserManager userManager, IUserDataManager userDataManager, ILogger<PlaylistXmlSaver> logger) - : base(fileSystem, configurationManager, libraryManager, userManager, userDataManager, logger) + public PlaylistXmlSaver(IFileSystem fileSystem, IServerConfigurationManager configurationManager, ILibraryManager libraryManager, ILogger<PlaylistXmlSaver> logger) + : base(fileSystem, configurationManager, libraryManager, logger) { } diff --git a/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj b/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj index 7733e715f..6da9886a4 100644 --- a/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj +++ b/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj @@ -9,10 +9,6 @@ <TargetFramework>net5.0</TargetFramework> <GenerateAssemblyInfo>false</GenerateAssemblyInfo> <GenerateDocumentationFile>true</GenerateDocumentationFile> - <TreatWarningsAsErrors>true</TreatWarningsAsErrors> - <Nullable>enable</Nullable> - <AnalysisMode>AllEnabledByDefault</AnalysisMode> - <CodeAnalysisRuleSet>../jellyfin.ruleset</CodeAnalysisRuleSet> </PropertyGroup> <ItemGroup> @@ -30,7 +26,7 @@ <PackageReference Include="libse" Version="3.6.0" /> <PackageReference Include="Microsoft.Extensions.Http" Version="5.0.0" /> <PackageReference Include="System.Text.Encoding.CodePages" Version="5.0.0" /> - <PackageReference Include="UTF.Unknown" Version="2.3.0" /> + <PackageReference Include="UTF.Unknown" Version="2.4.0" /> </ItemGroup> <!-- Code Analyzers--> diff --git a/MediaBrowser.MediaEncoding/Probing/FFProbeHelpers.cs b/MediaBrowser.MediaEncoding/Probing/FFProbeHelpers.cs index d0a76c4ca..9196fe139 100644 --- a/MediaBrowser.MediaEncoding/Probing/FFProbeHelpers.cs +++ b/MediaBrowser.MediaEncoding/Probing/FFProbeHelpers.cs @@ -63,7 +63,8 @@ namespace MediaBrowser.MediaEncoding.Probing public static DateTime? GetDictionaryDateTime(IReadOnlyDictionary<string, string> tags, string key) { if (tags.TryGetValue(key, out var val) - && DateTime.TryParse(val, DateTimeFormatInfo.CurrentInfo, DateTimeStyles.AssumeUniversal, out var dateTime)) + && (DateTime.TryParse(val, DateTimeFormatInfo.CurrentInfo, DateTimeStyles.AssumeUniversal, out var dateTime) + || DateTime.TryParseExact(val, "yyyy", DateTimeFormatInfo.CurrentInfo, DateTimeStyles.AssumeUniversal, out dateTime))) { return dateTime.ToUniversalTime(); } diff --git a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs index d6799a170..93093bb18 100644 --- a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs +++ b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs @@ -121,6 +121,7 @@ namespace MediaBrowser.MediaEncoding.Probing // Several different forms of retail/premiere date info.PremiereDate = + FFProbeHelpers.GetDictionaryDateTime(tags, "originaldate") ?? FFProbeHelpers.GetDictionaryDateTime(tags, "retaildate") ?? FFProbeHelpers.GetDictionaryDateTime(tags, "retail date") ?? FFProbeHelpers.GetDictionaryDateTime(tags, "retail_date") ?? diff --git a/MediaBrowser.Model/Activity/ActivityLogEntry.cs b/MediaBrowser.Model/Activity/ActivityLogEntry.cs index 1d47ef9f6..f83dde56d 100644 --- a/MediaBrowser.Model/Activity/ActivityLogEntry.cs +++ b/MediaBrowser.Model/Activity/ActivityLogEntry.cs @@ -1,14 +1,27 @@ -#nullable disable -#pragma warning disable CS1591 - using System; using Microsoft.Extensions.Logging; namespace MediaBrowser.Model.Activity { + /// <summary> + /// An activity log entry. + /// </summary> public class ActivityLogEntry { /// <summary> + /// Initializes a new instance of the <see cref="ActivityLogEntry"/> class. + /// </summary> + /// <param name="name">The name.</param> + /// <param name="type">The type.</param> + /// <param name="userId">The user id.</param> + public ActivityLogEntry(string name, string type, Guid userId) + { + Name = name; + Type = type; + UserId = userId; + } + + /// <summary> /// Gets or sets the identifier. /// </summary> /// <value>The identifier.</value> @@ -24,13 +37,13 @@ namespace MediaBrowser.Model.Activity /// Gets or sets the overview. /// </summary> /// <value>The overview.</value> - public string Overview { get; set; } + public string? Overview { get; set; } /// <summary> /// Gets or sets the short overview. /// </summary> /// <value>The short overview.</value> - public string ShortOverview { get; set; } + public string? ShortOverview { get; set; } /// <summary> /// Gets or sets the type. @@ -42,7 +55,7 @@ namespace MediaBrowser.Model.Activity /// Gets or sets the item identifier. /// </summary> /// <value>The item identifier.</value> - public string ItemId { get; set; } + public string? ItemId { get; set; } /// <summary> /// Gets or sets the date. @@ -61,7 +74,7 @@ namespace MediaBrowser.Model.Activity /// </summary> /// <value>The user primary image tag.</value> [Obsolete("UserPrimaryImageTag is not used.")] - public string UserPrimaryImageTag { get; set; } + public string? UserPrimaryImageTag { get; set; } /// <summary> /// Gets or sets the log severity. diff --git a/MediaBrowser.Model/Branding/BrandingOptions.cs b/MediaBrowser.Model/Branding/BrandingOptions.cs index 5ddf1e7e6..7f19a5b85 100644 --- a/MediaBrowser.Model/Branding/BrandingOptions.cs +++ b/MediaBrowser.Model/Branding/BrandingOptions.cs @@ -1,4 +1,3 @@ -#nullable disable #pragma warning disable CS1591 namespace MediaBrowser.Model.Branding @@ -9,12 +8,12 @@ namespace MediaBrowser.Model.Branding /// Gets or sets the login disclaimer. /// </summary> /// <value>The login disclaimer.</value> - public string LoginDisclaimer { get; set; } + public string? LoginDisclaimer { get; set; } /// <summary> /// Gets or sets the custom CSS. /// </summary> /// <value>The custom CSS.</value> - public string CustomCss { get; set; } + public string? CustomCss { get; set; } } } diff --git a/MediaBrowser.Model/Channels/ChannelInfo.cs b/MediaBrowser.Model/Channels/ChannelInfo.cs deleted file mode 100644 index f2432aaeb..000000000 --- a/MediaBrowser.Model/Channels/ChannelInfo.cs +++ /dev/null @@ -1,32 +0,0 @@ -#nullable disable -#pragma warning disable CS1591 - -namespace MediaBrowser.Model.Channels -{ - public class ChannelInfo - { - /// <summary> - /// Gets or sets the name. - /// </summary> - /// <value>The name.</value> - public string Name { get; set; } - - /// <summary> - /// Gets or sets the identifier. - /// </summary> - /// <value>The identifier.</value> - public string Id { get; set; } - - /// <summary> - /// Gets or sets the home page URL. - /// </summary> - /// <value>The home page URL.</value> - public string HomePageUrl { get; set; } - - /// <summary> - /// Gets or sets the features. - /// </summary> - /// <value>The features.</value> - public ChannelFeatures Features { get; set; } - } -} diff --git a/MediaBrowser.Model/Entities/MediaStream.cs b/MediaBrowser.Model/Entities/MediaStream.cs index 275b438f5..9653a8ece 100644 --- a/MediaBrowser.Model/Entities/MediaStream.cs +++ b/MediaBrowser.Model/Entities/MediaStream.cs @@ -469,7 +469,7 @@ namespace MediaBrowser.Model.Entities /// <value><c>true</c> if this instance is anamorphic; otherwise, <c>false</c>.</value> public bool? IsAnamorphic { get; set; } - private string GetResolutionText() + internal string GetResolutionText() { if (!Width.HasValue || !Height.HasValue) { diff --git a/MediaBrowser.Model/MediaBrowser.Model.csproj b/MediaBrowser.Model/MediaBrowser.Model.csproj index c475d905a..a371afc2c 100644 --- a/MediaBrowser.Model/MediaBrowser.Model.csproj +++ b/MediaBrowser.Model/MediaBrowser.Model.csproj @@ -17,14 +17,15 @@ <TargetFramework>net5.0</TargetFramework> <GenerateAssemblyInfo>false</GenerateAssemblyInfo> <GenerateDocumentationFile>true</GenerateDocumentationFile> - <TreatWarningsAsErrors>true</TreatWarningsAsErrors> - <Nullable>enable</Nullable> - <!-- <AnalysisMode>AllEnabledByDefault</AnalysisMode> --> - <CodeAnalysisRuleSet>../jellyfin.ruleset</CodeAnalysisRuleSet> <PublishRepositoryUrl>true</PublishRepositoryUrl> <EmbedUntrackedSources>true</EmbedUntrackedSources> <IncludeSymbols>true</IncludeSymbols> <SymbolPackageFormat>snupkg</SymbolPackageFormat> + <TreatWarningsAsErrors>false</TreatWarningsAsErrors> + </PropertyGroup> + + <PropertyGroup Condition=" '$(Configuration)' == 'Release'"> + <TreatWarningsAsErrors>true</TreatWarningsAsErrors> </PropertyGroup> <PropertyGroup Condition=" '$(Stability)'=='Unstable'"> diff --git a/MediaBrowser.Model/Properties/AssemblyInfo.cs b/MediaBrowser.Model/Properties/AssemblyInfo.cs index f99e9ece9..e50baf604 100644 --- a/MediaBrowser.Model/Properties/AssemblyInfo.cs +++ b/MediaBrowser.Model/Properties/AssemblyInfo.cs @@ -1,5 +1,6 @@ using System.Reflection; using System.Resources; +using System.Runtime.CompilerServices; using System.Runtime.InteropServices; // General Information about an assembly is controlled through the following @@ -14,6 +15,7 @@ using System.Runtime.InteropServices; [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] [assembly: NeutralResourcesLanguage("en")] +[assembly: InternalsVisibleTo("Jellyfin.Model.Tests")] // 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 diff --git a/MediaBrowser.Model/Session/HardwareEncodingType.cs b/MediaBrowser.Model/Session/HardwareEncodingType.cs new file mode 100644 index 000000000..0e172f35f --- /dev/null +++ b/MediaBrowser.Model/Session/HardwareEncodingType.cs @@ -0,0 +1,48 @@ +namespace MediaBrowser.Model.Session +{ + /// <summary> + /// Enum HardwareEncodingType. + /// </summary> + public enum HardwareEncodingType + { + /// <summary> + /// AMD AMF + /// </summary> + AMF = 0, + + /// <summary> + /// Intel Quick Sync Video + /// </summary> + QSV = 1, + + /// <summary> + /// NVIDIA NVENC + /// </summary> + NVENC = 2, + + /// <summary> + /// OpenMax OMX + /// </summary> + OMX = 3, + + /// <summary> + /// Exynos V4L2 MFC + /// </summary> + V4L2M2M = 4, + + /// <summary> + /// MediaCodec Android + /// </summary> + MediaCodec = 5, + + /// <summary> + /// Video Acceleration API (VAAPI) + /// </summary> + VAAPI = 6, + + /// <summary> + /// Video ToolBox + /// </summary> + VideoToolBox = 7 + } +} diff --git a/MediaBrowser.Model/Session/TranscodingInfo.cs b/MediaBrowser.Model/Session/TranscodingInfo.cs index 064a087d5..68ab691f8 100644 --- a/MediaBrowser.Model/Session/TranscodingInfo.cs +++ b/MediaBrowser.Model/Session/TranscodingInfo.cs @@ -34,6 +34,8 @@ namespace MediaBrowser.Model.Session public int? AudioChannels { get; set; } + public HardwareEncodingType? HardwareAccelerationType { get; set; } + public TranscodeReason[] TranscodeReasons { get; set; } } } diff --git a/MediaBrowser.Model/Users/UserActionType.cs b/MediaBrowser.Model/Users/UserActionType.cs deleted file mode 100644 index dbb1513f2..000000000 --- a/MediaBrowser.Model/Users/UserActionType.cs +++ /dev/null @@ -1,9 +0,0 @@ -#pragma warning disable CS1591 - -namespace MediaBrowser.Model.Users -{ - public enum UserActionType - { - PlayedItem = 0 - } -} diff --git a/MediaBrowser.Providers/MediaBrowser.Providers.csproj b/MediaBrowser.Providers/MediaBrowser.Providers.csproj index cdb07a15d..6174f18b2 100644 --- a/MediaBrowser.Providers/MediaBrowser.Providers.csproj +++ b/MediaBrowser.Providers/MediaBrowser.Providers.csproj @@ -29,9 +29,12 @@ <TargetFramework>net5.0</TargetFramework> <GenerateAssemblyInfo>false</GenerateAssemblyInfo> <GenerateDocumentationFile>true</GenerateDocumentationFile> - <TreatWarningsAsErrors Condition=" '$(Configuration)' == 'Release'">true</TreatWarningsAsErrors> - <AnalysisMode Condition=" '$(Configuration)' == 'Debug'">AllEnabledByDefault</AnalysisMode> - <CodeAnalysisRuleSet>../jellyfin.ruleset</CodeAnalysisRuleSet> + <TreatWarningsAsErrors>false</TreatWarningsAsErrors> + <Nullable>disable</Nullable> + </PropertyGroup> + + <PropertyGroup Condition=" '$(Configuration)' == 'Release'"> + <TreatWarningsAsErrors>true</TreatWarningsAsErrors> </PropertyGroup> <!-- Code Analyzers--> diff --git a/MediaBrowser.XbmcMetadata/MediaBrowser.XbmcMetadata.csproj b/MediaBrowser.XbmcMetadata/MediaBrowser.XbmcMetadata.csproj index 2904b40ec..3e2a9bacf 100644 --- a/MediaBrowser.XbmcMetadata/MediaBrowser.XbmcMetadata.csproj +++ b/MediaBrowser.XbmcMetadata/MediaBrowser.XbmcMetadata.csproj @@ -18,10 +18,6 @@ <TargetFramework>net5.0</TargetFramework> <GenerateAssemblyInfo>false</GenerateAssemblyInfo> <GenerateDocumentationFile>true</GenerateDocumentationFile> - <TreatWarningsAsErrors>true</TreatWarningsAsErrors> - <Nullable>enable</Nullable> - <AnalysisMode>AllEnabledByDefault</AnalysisMode> - <CodeAnalysisRuleSet>../jellyfin.ruleset</CodeAnalysisRuleSet> </PropertyGroup> <!-- Code Analyzers--> diff --git a/MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs b/MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs index 302c93f0b..2c86f9242 100644 --- a/MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs +++ b/MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs @@ -1205,7 +1205,7 @@ namespace MediaBrowser.XbmcMetadata.Parsers switch (reader.Name) { case "name": - name = reader.ReadElementContentAsString() ?? string.Empty; + name = reader.ReadElementContentAsString(); break; case "role": @@ -68,6 +68,8 @@ Check out our <a href="https://translate.jellyfin.org">Weblate instance</a> to h <img src="https://translate.jellyfin.org/widgets/jellyfin/-/jellyfin-web/multi-auto.svg" alt="Detailed Translation Status"/> </a> +--- + ## Jellyfin Server This repository contains the code for Jellyfin's backend server. Note that this is only one of many projects under the Jellyfin GitHub [organization](https://github.com/jellyfin/) on GitHub. If you want to contribute, you can start by checking out our [documentation](https://jellyfin.org/docs/general/contributing/index.html) to see what to work on. @@ -162,3 +164,13 @@ switch `--nowebclient` or the environment variable `JELLYFIN_NOWEBCONTENT=true`. Since this is a common scenario, there is also a separate launch profile defined for Visual Studio called `Jellyfin.Server (nowebcontent)` that can be selected from the 'Start Debugging' dropdown in the main toolbar. **NOTE:** The setup wizard can not be run if the web client is hosted separately. + +--- +<p align="center"> +This project is supported by: +<br/> +<br/> +<a href="https://www.digitalocean.com"><img src="https://opensource.nyc3.cdn.digitaloceanspaces.com/attribution/assets/SVG/DO_Logo_horizontal_blue.svg" height="50px" alt="DigitalOcean"></a> + +<a href="https://www.jetbrains.com"><img src="https://gist.githubusercontent.com/anthonylavado/e8b2403deee9581e0b4cb8cd675af7db/raw/fa104b7d73f759d7262794b94569f1b89df41c0b/jetbrains.svg" height="50px" alt="JetBrains logo"></a> +</p> diff --git a/RSSDP/RSSDP.csproj b/RSSDP/RSSDP.csproj index c64ee9389..54113d464 100644 --- a/RSSDP/RSSDP.csproj +++ b/RSSDP/RSSDP.csproj @@ -13,7 +13,9 @@ <PropertyGroup> <TargetFramework>net5.0</TargetFramework> <GenerateAssemblyInfo>false</GenerateAssemblyInfo> - <TreatWarningsAsErrors>true</TreatWarningsAsErrors> + <AnalysisMode>AllDisabledByDefault</AnalysisMode> + <Nullable>disable</Nullable> + <NoWarn>CA2016</NoWarn> </PropertyGroup> </Project> diff --git a/deployment/Dockerfile.centos.amd64 b/deployment/Dockerfile.centos.amd64 index 01fc1aaac..326e995be 100644 --- a/deployment/Dockerfile.centos.amd64 +++ b/deployment/Dockerfile.centos.amd64 @@ -9,21 +9,21 @@ ENV ARTIFACT_DIR=/dist ENV IS_DOCKER=YES # Prepare CentOS environment -RUN yum update -y \ - && yum install -y epel-release \ - && yum install -y @buildsys-build rpmdevtools yum-plugins-core libcurl-devel fontconfig-devel freetype-devel openssl-devel glibc-devel libicu-devel git +RUN yum update -yq \ + && yum install -yq epel-release \ + && yum install -yq @buildsys-build rpmdevtools yum-plugins-core libcurl-devel fontconfig-devel freetype-devel openssl-devel glibc-devel libicu-devel git # Install DotNET SDK RUN rpm -Uvh https://packages.microsoft.com/config/rhel/7/packages-microsoft-prod.rpm \ - && rpmdev-setuptree \ - && yum install -y dotnet-sdk-${SDK_VERSION} + && rpmdev-setuptree \ + && yum install -yq dotnet-sdk-${SDK_VERSION} # Create symlinks and directories RUN ln -sf ${SOURCE_DIR}/deployment/build.centos.amd64 /build.sh \ - && mkdir -p ${SOURCE_DIR}/SPECS \ - && ln -s ${SOURCE_DIR}/fedora/jellyfin.spec ${SOURCE_DIR}/SPECS/jellyfin.spec \ - && mkdir -p ${SOURCE_DIR}/SOURCES \ - && ln -s ${SOURCE_DIR}/fedora ${SOURCE_DIR}/SOURCES + && mkdir -p ${SOURCE_DIR}/SPECS \ + && ln -s ${SOURCE_DIR}/fedora/jellyfin.spec ${SOURCE_DIR}/SPECS/jellyfin.spec \ + && mkdir -p ${SOURCE_DIR}/SOURCES \ + && ln -s ${SOURCE_DIR}/fedora ${SOURCE_DIR}/SOURCES VOLUME ${SOURCE_DIR}/ diff --git a/deployment/Dockerfile.debian.amd64 b/deployment/Dockerfile.debian.amd64 index 67a5c9c99..23b662526 100644 --- a/deployment/Dockerfile.debian.amd64 +++ b/deployment/Dockerfile.debian.amd64 @@ -1,8 +1,7 @@ -FROM debian:10 +FROM mcr.microsoft.com/dotnet/sdk:5.0-buster-slim # Docker build arguments ARG SOURCE_DIR=/jellyfin ARG ARTIFACT_DIR=/dist -ARG SDK_VERSION=5.0 # Docker run environment ENV SOURCE_DIR=/jellyfin ENV ARTIFACT_DIR=/dist @@ -11,15 +10,11 @@ ENV ARCH=amd64 ENV IS_DOCKER=YES # Prepare Debian build environment -RUN apt-get update \ - && apt-get install -y apt-transport-https debhelper gnupg wget devscripts mmv libc6-dev libcurl4-openssl-dev libfontconfig1-dev libfreetype6-dev libssl-dev libssl1.1 liblttng-ust0 - -# Install dotnet repository -# https://dotnet.microsoft.com/download/linux-package-manager/debian9/sdk-current -RUN wget https://download.visualstudio.microsoft.com/download/pr/8468e541-a99a-4191-8470-654fa0747a9a/cb32548d2fd3d60ef3fe8fc80cd735ef/dotnet-sdk-5.0.302-linux-x64.tar.gz -O dotnet-sdk.tar.gz \ - && mkdir -p dotnet-sdk \ - && tar -xzf dotnet-sdk.tar.gz -C dotnet-sdk \ - && ln -s $( pwd )/dotnet-sdk/dotnet /usr/bin/dotnet +RUN apt-get update -yqq \ + && apt-get install -yqq --no-install-recommends \ + apt-transport-https debhelper gnupg devscripts build-essential mmv \ + libcurl4-openssl-dev libfontconfig1-dev libfreetype6-dev libssl-dev \ + libssl1.1 liblttng-ust0 # Link to build script RUN ln -sf ${SOURCE_DIR}/deployment/build.debian.amd64 /build.sh diff --git a/deployment/Dockerfile.debian.arm64 b/deployment/Dockerfile.debian.arm64 index c341068f6..a33099031 100644 --- a/deployment/Dockerfile.debian.arm64 +++ b/deployment/Dockerfile.debian.arm64 @@ -1,8 +1,7 @@ -FROM debian:10 +FROM mcr.microsoft.com/dotnet/sdk:5.0-buster-slim # Docker build arguments ARG SOURCE_DIR=/jellyfin ARG ARTIFACT_DIR=/dist -ARG SDK_VERSION=5.0 # Docker run environment ENV SOURCE_DIR=/jellyfin ENV ARTIFACT_DIR=/dist @@ -11,23 +10,24 @@ ENV ARCH=amd64 ENV IS_DOCKER=YES # Prepare Debian build environment -RUN apt-get update \ - && apt-get install -y apt-transport-https debhelper gnupg wget devscripts mmv - -# Install dotnet repository -# https://dotnet.microsoft.com/download/linux-package-manager/debian9/sdk-current -RUN wget https://download.visualstudio.microsoft.com/download/pr/8468e541-a99a-4191-8470-654fa0747a9a/cb32548d2fd3d60ef3fe8fc80cd735ef/dotnet-sdk-5.0.302-linux-x64.tar.gz -O dotnet-sdk.tar.gz \ - && mkdir -p dotnet-sdk \ - && tar -xzf dotnet-sdk.tar.gz -C dotnet-sdk \ - && ln -s $( pwd )/dotnet-sdk/dotnet /usr/bin/dotnet +RUN apt-get update -yqq \ + && apt-get install -yqq --no-install-recommends \ + apt-transport-https debhelper gnupg devscripts build-essential mmv # Prepare the cross-toolchain RUN dpkg --add-architecture arm64 \ - && apt-get update \ - && apt-get install -y cross-gcc-dev \ - && TARGET_LIST="arm64" cross-gcc-gensource 8 \ - && cd cross-gcc-packages-amd64/cross-gcc-8-arm64 \ - && apt-get install -y gcc-8-source libstdc++-8-dev-arm64-cross binutils-aarch64-linux-gnu bison flex libtool gdb sharutils netbase libmpc-dev libmpfr-dev libgmp-dev systemtap-sdt-dev autogen expect chrpath zlib1g-dev zip libc6-dev:arm64 linux-libc-dev:arm64 libgcc1:arm64 libcurl4-openssl-dev:arm64 libfontconfig1-dev:arm64 libfreetype6-dev:arm64 libssl-dev:arm64 liblttng-ust0:arm64 libstdc++-8-dev:arm64 + && apt-get update -yqq \ + && apt-get install -yqq --no-install-recommends cross-gcc-dev \ + && TARGET_LIST="arm64" cross-gcc-gensource 8 \ + && cd cross-gcc-packages-amd64/cross-gcc-8-arm64 \ + && apt-get install -yqq --no-install-recommends \ + gcc-8-source libstdc++-8-dev-arm64-cross \ + binutils-aarch64-linux-gnu bison flex libtool \ + gdb sharutils netbase libmpc-dev libmpfr-dev libgmp-dev \ + systemtap-sdt-dev autogen expect chrpath zlib1g-dev zip \ + libc6-dev:arm64 linux-libc-dev:arm64 libgcc1:arm64 \ + libcurl4-openssl-dev:arm64 libfontconfig1-dev:arm64 \ + libfreetype6-dev:arm64 libssl-dev:arm64 liblttng-ust0:arm64 libstdc++-8-dev:arm64 # Link to build script RUN ln -sf ${SOURCE_DIR}/deployment/build.debian.arm64 /build.sh diff --git a/deployment/Dockerfile.debian.armhf b/deployment/Dockerfile.debian.armhf index 19be363b6..bc5e3543f 100644 --- a/deployment/Dockerfile.debian.armhf +++ b/deployment/Dockerfile.debian.armhf @@ -1,8 +1,7 @@ -FROM debian:10 +FROM mcr.microsoft.com/dotnet/sdk:5.0-buster-slim # Docker build arguments ARG SOURCE_DIR=/jellyfin ARG ARTIFACT_DIR=/dist -ARG SDK_VERSION=5.0 # Docker run environment ENV SOURCE_DIR=/jellyfin ENV ARTIFACT_DIR=/dist @@ -11,23 +10,25 @@ ENV ARCH=amd64 ENV IS_DOCKER=YES # Prepare Debian build environment -RUN apt-get update \ - && apt-get install -y apt-transport-https debhelper gnupg wget devscripts mmv - -# Install dotnet repository -# https://dotnet.microsoft.com/download/linux-package-manager/debian9/sdk-current -RUN wget https://download.visualstudio.microsoft.com/download/pr/8468e541-a99a-4191-8470-654fa0747a9a/cb32548d2fd3d60ef3fe8fc80cd735ef/dotnet-sdk-5.0.302-linux-x64.tar.gz -O dotnet-sdk.tar.gz \ - && mkdir -p dotnet-sdk \ - && tar -xzf dotnet-sdk.tar.gz -C dotnet-sdk \ - && ln -s $( pwd )/dotnet-sdk/dotnet /usr/bin/dotnet +RUN apt-get update -yqq \ + && apt-get install -yqq --no-install-recommends \ + apt-transport-https debhelper gnupg devscripts build-essential mmv # Prepare the cross-toolchain RUN dpkg --add-architecture armhf \ - && apt-get update \ - && apt-get install -y cross-gcc-dev \ - && TARGET_LIST="armhf" cross-gcc-gensource 8 \ - && cd cross-gcc-packages-amd64/cross-gcc-8-armhf \ - && apt-get install -y gcc-8-source libstdc++-8-dev-armhf-cross binutils-aarch64-linux-gnu bison flex libtool gdb sharutils netbase libmpc-dev libmpfr-dev libgmp-dev systemtap-sdt-dev autogen expect chrpath zlib1g-dev zip binutils-arm-linux-gnueabihf libc6-dev:armhf linux-libc-dev:armhf libgcc1:armhf libcurl4-openssl-dev:armhf libfontconfig1-dev:armhf libfreetype6-dev:armhf libssl-dev:armhf liblttng-ust0:armhf libstdc++-8-dev:armhf + && apt-get update -yqq \ + && apt-get install -yqq --no-install-recommends cross-gcc-dev \ + && TARGET_LIST="armhf" cross-gcc-gensource 8 \ + && cd cross-gcc-packages-amd64/cross-gcc-8-armhf \ + && apt-get install -yqq --no-install-recommends\ + gcc-8-source libstdc++-8-dev-armhf-cross \ + binutils-aarch64-linux-gnu bison flex libtool gdb \ + sharutils netbase libmpc-dev libmpfr-dev libgmp-dev \ + systemtap-sdt-dev autogen expect chrpath zlib1g-dev \ + zip binutils-arm-linux-gnueabihf libc6-dev:armhf \ + linux-libc-dev:armhf libgcc1:armhf libcurl4-openssl-dev:armhf \ + libfontconfig1-dev:armhf libfreetype6-dev:armhf libssl-dev:armhf \ + liblttng-ust0:armhf libstdc++-8-dev:armhf # Link to build script RUN ln -sf ${SOURCE_DIR}/deployment/build.debian.armhf /build.sh diff --git a/deployment/Dockerfile.fedora.amd64 b/deployment/Dockerfile.fedora.amd64 index 137e56ecf..590cde167 100644 --- a/deployment/Dockerfile.fedora.amd64 +++ b/deployment/Dockerfile.fedora.amd64 @@ -9,18 +9,18 @@ ENV ARTIFACT_DIR=/dist ENV IS_DOCKER=YES # Prepare Fedora environment -RUN dnf update -y \ - && dnf install -y @buildsys-build rpmdevtools git dnf-plugins-core libcurl-devel fontconfig-devel freetype-devel openssl-devel glibc-devel libicu-devel systemd +RUN dnf update -yq \ + && dnf install -yq @buildsys-build rpmdevtools git dnf-plugins-core libcurl-devel fontconfig-devel freetype-devel openssl-devel glibc-devel libicu-devel systemd # Install DotNET SDK -RUN dnf install -y dotnet-sdk-${SDK_VERSION} dotnet-runtime-${SDK_VERSION} +RUN dnf install -yq dotnet-sdk-${SDK_VERSION} dotnet-runtime-${SDK_VERSION} # Create symlinks and directories RUN ln -sf ${SOURCE_DIR}/deployment/build.fedora.amd64 /build.sh \ - && mkdir -p ${SOURCE_DIR}/SPECS \ - && ln -s ${SOURCE_DIR}/fedora/jellyfin.spec ${SOURCE_DIR}/SPECS/jellyfin.spec \ - && mkdir -p ${SOURCE_DIR}/SOURCES \ - && ln -s ${SOURCE_DIR}/fedora ${SOURCE_DIR}/SOURCES + && mkdir -p ${SOURCE_DIR}/SPECS \ + && ln -s ${SOURCE_DIR}/fedora/jellyfin.spec ${SOURCE_DIR}/SPECS/jellyfin.spec \ + && mkdir -p ${SOURCE_DIR}/SOURCES \ + && ln -s ${SOURCE_DIR}/fedora ${SOURCE_DIR}/SOURCES VOLUME ${SOURCE_DIR}/ diff --git a/deployment/Dockerfile.linux.amd64 b/deployment/Dockerfile.linux.amd64 index a89fe9289..3c7e2b87f 100644 --- a/deployment/Dockerfile.linux.amd64 +++ b/deployment/Dockerfile.linux.amd64 @@ -1,8 +1,7 @@ -FROM debian:10 +FROM mcr.microsoft.com/dotnet/sdk:5.0-buster-slim # Docker build arguments ARG SOURCE_DIR=/jellyfin ARG ARTIFACT_DIR=/dist -ARG SDK_VERSION=5.0 # Docker run environment ENV SOURCE_DIR=/jellyfin ENV ARTIFACT_DIR=/dist @@ -11,15 +10,11 @@ ENV ARCH=amd64 ENV IS_DOCKER=YES # Prepare Debian build environment -RUN apt-get update \ - && apt-get install -y apt-transport-https debhelper gnupg wget devscripts mmv libc6-dev libcurl4-openssl-dev libfontconfig1-dev libfreetype6-dev libssl-dev libssl1.1 liblttng-ust0 - -# Install dotnet repository -# https://dotnet.microsoft.com/download/linux-package-manager/debian9/sdk-current -RUN wget https://download.visualstudio.microsoft.com/download/pr/8468e541-a99a-4191-8470-654fa0747a9a/cb32548d2fd3d60ef3fe8fc80cd735ef/dotnet-sdk-5.0.302-linux-x64.tar.gz -O dotnet-sdk.tar.gz \ - && mkdir -p dotnet-sdk \ - && tar -xzf dotnet-sdk.tar.gz -C dotnet-sdk \ - && ln -s $( pwd )/dotnet-sdk/dotnet /usr/bin/dotnet +RUN apt-get update -yqq \ + && apt-get install -yqq --no-install-recommends \ + apt-transport-https debhelper gnupg devscripts unzip \ + mmv libcurl4-openssl-dev libfontconfig1-dev \ + libfreetype6-dev libssl-dev libssl1.1 liblttng-ust0 # Link to docker-build script RUN ln -sf ${SOURCE_DIR}/deployment/build.linux.amd64 /build.sh diff --git a/deployment/Dockerfile.linux.amd64-musl b/deployment/Dockerfile.linux.amd64-musl index f7fb722f2..3cda9ad23 100644 --- a/deployment/Dockerfile.linux.amd64-musl +++ b/deployment/Dockerfile.linux.amd64-musl @@ -1,8 +1,7 @@ -FROM debian:10 +FROM mcr.microsoft.com/dotnet/sdk:5.0-buster-slim # Docker build arguments ARG SOURCE_DIR=/jellyfin ARG ARTIFACT_DIR=/dist -ARG SDK_VERSION=5.0 # Docker run environment ENV SOURCE_DIR=/jellyfin ENV ARTIFACT_DIR=/dist @@ -11,15 +10,11 @@ ENV ARCH=amd64 ENV IS_DOCKER=YES # Prepare Debian build environment -RUN apt-get update \ - && apt-get install -y apt-transport-https debhelper gnupg wget devscripts mmv libc6-dev libcurl4-openssl-dev libfontconfig1-dev libfreetype6-dev libssl-dev libssl1.1 liblttng-ust0 - -# Install dotnet repository -# https://dotnet.microsoft.com/download/linux-package-manager/debian9/sdk-current -RUN wget https://download.visualstudio.microsoft.com/download/pr/8468e541-a99a-4191-8470-654fa0747a9a/cb32548d2fd3d60ef3fe8fc80cd735ef/dotnet-sdk-5.0.302-linux-x64.tar.gz -O dotnet-sdk.tar.gz \ - && mkdir -p dotnet-sdk \ - && tar -xzf dotnet-sdk.tar.gz -C dotnet-sdk \ - && ln -s $( pwd )/dotnet-sdk/dotnet /usr/bin/dotnet +RUN apt-get update -yqq \ + && apt-get install -yqq --no-install-recommends \ + apt-transport-https debhelper gnupg devscripts unzip \ + mmv libcurl4-openssl-dev libfontconfig1-dev \ + libfreetype6-dev libssl-dev libssl1.1 liblttng-ust0 # Link to docker-build script RUN ln -sf ${SOURCE_DIR}/deployment/build.linux.amd64-musl /build.sh diff --git a/deployment/Dockerfile.linux.arm64 b/deployment/Dockerfile.linux.arm64 index 1b57441a0..ddf97cbd1 100644 --- a/deployment/Dockerfile.linux.arm64 +++ b/deployment/Dockerfile.linux.arm64 @@ -1,8 +1,7 @@ -FROM debian:10 +FROM mcr.microsoft.com/dotnet/sdk:5.0-buster-slim # Docker build arguments ARG SOURCE_DIR=/jellyfin ARG ARTIFACT_DIR=/dist -ARG SDK_VERSION=5.0 # Docker run environment ENV SOURCE_DIR=/jellyfin ENV ARTIFACT_DIR=/dist @@ -11,15 +10,11 @@ ENV ARCH=arm64 ENV IS_DOCKER=YES # Prepare Debian build environment -RUN apt-get update \ - && apt-get install -y apt-transport-https debhelper gnupg wget devscripts mmv libc6-dev libcurl4-openssl-dev libfontconfig1-dev libfreetype6-dev libssl-dev libssl1.1 liblttng-ust0 - -# Install dotnet repository -# https://dotnet.microsoft.com/download/linux-package-manager/debian9/sdk-current -RUN wget https://download.visualstudio.microsoft.com/download/pr/8468e541-a99a-4191-8470-654fa0747a9a/cb32548d2fd3d60ef3fe8fc80cd735ef/dotnet-sdk-5.0.302-linux-x64.tar.gz -O dotnet-sdk.tar.gz \ - && mkdir -p dotnet-sdk \ - && tar -xzf dotnet-sdk.tar.gz -C dotnet-sdk \ - && ln -s $( pwd )/dotnet-sdk/dotnet /usr/bin/dotnet +RUN apt-get update -yqq \ + && apt-get install -yqq --no-install-recommends \ + apt-transport-https debhelper gnupg devscripts unzip \ + mmv libcurl4-openssl-dev libfontconfig1-dev \ + libfreetype6-dev libssl-dev libssl1.1 liblttng-ust0 # Link to docker-build script RUN ln -sf ${SOURCE_DIR}/deployment/build.linux.arm64 /build.sh diff --git a/deployment/Dockerfile.linux.armhf b/deployment/Dockerfile.linux.armhf index 20cf33e13..49e1c7bbf 100644 --- a/deployment/Dockerfile.linux.armhf +++ b/deployment/Dockerfile.linux.armhf @@ -1,8 +1,7 @@ -FROM debian:10 +FROM mcr.microsoft.com/dotnet/sdk:5.0-buster-slim # Docker build arguments ARG SOURCE_DIR=/jellyfin ARG ARTIFACT_DIR=/dist -ARG SDK_VERSION=5.0 # Docker run environment ENV SOURCE_DIR=/jellyfin ENV ARTIFACT_DIR=/dist @@ -11,15 +10,11 @@ ENV ARCH=armhf ENV IS_DOCKER=YES # Prepare Debian build environment -RUN apt-get update \ - && apt-get install -y apt-transport-https debhelper gnupg wget devscripts mmv libc6-dev libcurl4-openssl-dev libfontconfig1-dev libfreetype6-dev libssl-dev libssl1.1 liblttng-ust0 - -# Install dotnet repository -# https://dotnet.microsoft.com/download/linux-package-manager/debian9/sdk-current -RUN wget https://download.visualstudio.microsoft.com/download/pr/8468e541-a99a-4191-8470-654fa0747a9a/cb32548d2fd3d60ef3fe8fc80cd735ef/dotnet-sdk-5.0.302-linux-x64.tar.gz -O dotnet-sdk.tar.gz \ - && mkdir -p dotnet-sdk \ - && tar -xzf dotnet-sdk.tar.gz -C dotnet-sdk \ - && ln -s $( pwd )/dotnet-sdk/dotnet /usr/bin/dotnet +RUN apt-get update -yqq \ + && apt-get install -yqq --no-install-recommends \ + apt-transport-https debhelper gnupg devscripts unzip \ + mmv libcurl4-openssl-dev libfontconfig1-dev \ + libfreetype6-dev libssl-dev libssl1.1 liblttng-ust0 # Link to docker-build script RUN ln -sf ${SOURCE_DIR}/deployment/build.linux.armhf /build.sh diff --git a/deployment/Dockerfile.macos b/deployment/Dockerfile.macos index 4ddd106bb..fad44ef83 100644 --- a/deployment/Dockerfile.macos +++ b/deployment/Dockerfile.macos @@ -1,8 +1,7 @@ -FROM debian:10 +FROM mcr.microsoft.com/dotnet/sdk:5.0-buster-slim # Docker build arguments ARG SOURCE_DIR=/jellyfin ARG ARTIFACT_DIR=/dist -ARG SDK_VERSION=5.0 # Docker run environment ENV SOURCE_DIR=/jellyfin ENV ARTIFACT_DIR=/dist @@ -11,15 +10,11 @@ ENV ARCH=amd64 ENV IS_DOCKER=YES # Prepare Debian build environment -RUN apt-get update \ - && apt-get install -y apt-transport-https debhelper gnupg wget devscripts mmv libc6-dev libcurl4-openssl-dev libfontconfig1-dev libfreetype6-dev libssl-dev libssl1.1 liblttng-ust0 - -# Install dotnet repository -# https://dotnet.microsoft.com/download/linux-package-manager/debian9/sdk-current -RUN wget https://download.visualstudio.microsoft.com/download/pr/8468e541-a99a-4191-8470-654fa0747a9a/cb32548d2fd3d60ef3fe8fc80cd735ef/dotnet-sdk-5.0.302-linux-x64.tar.gz -O dotnet-sdk.tar.gz \ - && mkdir -p dotnet-sdk \ - && tar -xzf dotnet-sdk.tar.gz -C dotnet-sdk \ - && ln -s $( pwd )/dotnet-sdk/dotnet /usr/bin/dotnet +RUN apt-get update -yqq \ + && apt-get install -yqq --no-install-recommends \ + apt-transport-https debhelper gnupg devscripts \ + mmv libcurl4-openssl-dev libfontconfig1-dev \ + libfreetype6-dev libssl-dev libssl1.1 liblttng-ust0 # Link to docker-build script RUN ln -sf ${SOURCE_DIR}/deployment/build.macos /build.sh diff --git a/deployment/Dockerfile.portable b/deployment/Dockerfile.portable index e56a480c6..90cc0717b 100644 --- a/deployment/Dockerfile.portable +++ b/deployment/Dockerfile.portable @@ -1,8 +1,7 @@ -FROM debian:10 +FROM mcr.microsoft.com/dotnet/sdk:5.0-buster-slim # Docker build arguments ARG SOURCE_DIR=/jellyfin ARG ARTIFACT_DIR=/dist -ARG SDK_VERSION=5.0 # Docker run environment ENV SOURCE_DIR=/jellyfin ENV ARTIFACT_DIR=/dist @@ -10,15 +9,11 @@ ENV DEB_BUILD_OPTIONS=noddebs ENV IS_DOCKER=YES # Prepare Debian build environment -RUN apt-get update \ - && apt-get install -y apt-transport-https debhelper gnupg wget devscripts mmv libc6-dev libcurl4-openssl-dev libfontconfig1-dev libfreetype6-dev libssl-dev libssl1.1 liblttng-ust0 - -# Install dotnet repository -# https://dotnet.microsoft.com/download/linux-package-manager/debian9/sdk-current -RUN wget https://download.visualstudio.microsoft.com/download/pr/8468e541-a99a-4191-8470-654fa0747a9a/cb32548d2fd3d60ef3fe8fc80cd735ef/dotnet-sdk-5.0.302-linux-x64.tar.gz -O dotnet-sdk.tar.gz \ - && mkdir -p dotnet-sdk \ - && tar -xzf dotnet-sdk.tar.gz -C dotnet-sdk \ - && ln -s $( pwd )/dotnet-sdk/dotnet /usr/bin/dotnet +RUN apt-get update -yqq \ + && apt-get install -yqq --no-install-recommends \ + apt-transport-https debhelper gnupg devscripts \ + mmv libcurl4-openssl-dev libfontconfig1-dev \ + libfreetype6-dev libssl-dev libssl1.1 liblttng-ust0 # Link to docker-build script RUN ln -sf ${SOURCE_DIR}/deployment/build.portable /build.sh diff --git a/deployment/Dockerfile.ubuntu.amd64 b/deployment/Dockerfile.ubuntu.amd64 index 03d4c185c..97e3ff802 100644 --- a/deployment/Dockerfile.ubuntu.amd64 +++ b/deployment/Dockerfile.ubuntu.amd64 @@ -11,15 +11,18 @@ ENV ARCH=amd64 ENV IS_DOCKER=YES # Prepare Debian build environment -RUN apt-get update \ - && apt-get install -y apt-transport-https debhelper gnupg wget devscripts mmv libc6-dev libcurl4-openssl-dev libfontconfig1-dev libfreetype6-dev libssl-dev libssl1.1 liblttng-ust0 +RUN apt-get update -yqq \ + && apt-get install -yqq --no-install-recommends \ + apt-transport-https debhelper gnupg wget ca-certificates devscripts \ + mmv build-essential libcurl4-openssl-dev libfontconfig1-dev \ + libfreetype6-dev libssl-dev libssl1.1 liblttng-ust0 # Install dotnet repository # https://dotnet.microsoft.com/download/linux-package-manager/debian9/sdk-current -RUN wget https://download.visualstudio.microsoft.com/download/pr/8468e541-a99a-4191-8470-654fa0747a9a/cb32548d2fd3d60ef3fe8fc80cd735ef/dotnet-sdk-5.0.302-linux-x64.tar.gz -O dotnet-sdk.tar.gz \ - && mkdir -p dotnet-sdk \ - && tar -xzf dotnet-sdk.tar.gz -C dotnet-sdk \ - && ln -s $( pwd )/dotnet-sdk/dotnet /usr/bin/dotnet +RUN wget -q https://download.visualstudio.microsoft.com/download/pr/8468e541-a99a-4191-8470-654fa0747a9a/cb32548d2fd3d60ef3fe8fc80cd735ef/dotnet-sdk-5.0.302-linux-x64.tar.gz -O dotnet-sdk.tar.gz \ + && mkdir -p dotnet-sdk \ + && tar -xzf dotnet-sdk.tar.gz -C dotnet-sdk \ + && ln -s $( pwd )/dotnet-sdk/dotnet /usr/bin/dotnet # Link to build script RUN ln -sf ${SOURCE_DIR}/deployment/build.ubuntu.amd64 /build.sh diff --git a/deployment/Dockerfile.ubuntu.arm64 b/deployment/Dockerfile.ubuntu.arm64 index 9e0b60e0b..c94ee91dd 100644 --- a/deployment/Dockerfile.ubuntu.arm64 +++ b/deployment/Dockerfile.ubuntu.arm64 @@ -11,34 +11,41 @@ ENV ARCH=amd64 ENV IS_DOCKER=YES # Prepare Debian build environment -RUN apt-get update \ - && apt-get install -y apt-transport-https debhelper gnupg wget devscripts mmv +RUN apt-get update -yqq \ + && apt-get install -yqq --no-install-recommends \ + apt-transport-https debhelper gnupg wget ca-certificates devscripts \ + mmv build-essential lsb-release # Install dotnet repository # https://dotnet.microsoft.com/download/linux-package-manager/debian9/sdk-current -RUN wget https://download.visualstudio.microsoft.com/download/pr/8468e541-a99a-4191-8470-654fa0747a9a/cb32548d2fd3d60ef3fe8fc80cd735ef/dotnet-sdk-5.0.302-linux-x64.tar.gz -O dotnet-sdk.tar.gz \ - && mkdir -p dotnet-sdk \ - && tar -xzf dotnet-sdk.tar.gz -C dotnet-sdk \ - && ln -s $( pwd )/dotnet-sdk/dotnet /usr/bin/dotnet +RUN wget -q https://download.visualstudio.microsoft.com/download/pr/8468e541-a99a-4191-8470-654fa0747a9a/cb32548d2fd3d60ef3fe8fc80cd735ef/dotnet-sdk-5.0.302-linux-x64.tar.gz -O dotnet-sdk.tar.gz \ + && mkdir -p dotnet-sdk \ + && tar -xzf dotnet-sdk.tar.gz -C dotnet-sdk \ + && ln -s $( pwd )/dotnet-sdk/dotnet /usr/bin/dotnet # Prepare the cross-toolchain RUN rm /etc/apt/sources.list \ - && export CODENAME="$( lsb_release -c -s )" \ - && echo "deb [arch=amd64] http://archive.ubuntu.com/ubuntu/ ${CODENAME} main restricted universe multiverse" >>/etc/apt/sources.list.d/amd64.list \ - && echo "deb [arch=amd64] http://archive.ubuntu.com/ubuntu/ ${CODENAME}-updates main restricted universe multiverse" >>/etc/apt/sources.list.d/amd64.list \ - && echo "deb [arch=amd64] http://archive.ubuntu.com/ubuntu/ ${CODENAME}-backports main restricted universe multiverse" >>/etc/apt/sources.list.d/amd64.list \ - && echo "deb [arch=amd64] http://archive.ubuntu.com/ubuntu/ ${CODENAME}-security main restricted universe multiverse" >>/etc/apt/sources.list.d/amd64.list \ - && echo "deb [arch=arm64] http://ports.ubuntu.com/ ${CODENAME} main restricted universe multiverse" >>/etc/apt/sources.list.d/arm64.list \ - && echo "deb [arch=arm64] http://ports.ubuntu.com/ ${CODENAME}-updates main restricted universe multiverse" >>/etc/apt/sources.list.d/arm64.list \ - && echo "deb [arch=arm64] http://ports.ubuntu.com/ ${CODENAME}-backports main restricted universe multiverse" >>/etc/apt/sources.list.d/arm64.list \ - && echo "deb [arch=arm64] http://ports.ubuntu.com/ ${CODENAME}-security main restricted universe multiverse" >>/etc/apt/sources.list.d/arm64.list \ - && dpkg --add-architecture arm64 \ - && apt-get update \ - && apt-get install -y cross-gcc-dev \ - && TARGET_LIST="arm64" cross-gcc-gensource 6 \ - && cd cross-gcc-packages-amd64/cross-gcc-6-arm64 \ - && ln -fs /usr/share/zoneinfo/America/Toronto /etc/localtime \ - && apt-get install -y gcc-6-source libstdc++6-arm64-cross binutils-aarch64-linux-gnu bison flex libtool gdb sharutils netbase libcloog-isl-dev libmpc-dev libmpfr-dev libgmp-dev systemtap-sdt-dev autogen expect chrpath zlib1g-dev zip libc6-dev:arm64 linux-libc-dev:arm64 libgcc1:arm64 libcurl4-openssl-dev:arm64 libfontconfig1-dev:arm64 libfreetype6-dev:arm64 liblttng-ust0:arm64 libstdc++6:arm64 libssl-dev:arm64 + && export CODENAME="$( lsb_release -c -s )" \ + && echo "deb [arch=amd64] http://archive.ubuntu.com/ubuntu/ ${CODENAME} main restricted universe multiverse" >>/etc/apt/sources.list.d/amd64.list \ + && echo "deb [arch=amd64] http://archive.ubuntu.com/ubuntu/ ${CODENAME}-updates main restricted universe multiverse" >>/etc/apt/sources.list.d/amd64.list \ + && echo "deb [arch=amd64] http://archive.ubuntu.com/ubuntu/ ${CODENAME}-backports main restricted universe multiverse" >>/etc/apt/sources.list.d/amd64.list \ + && echo "deb [arch=amd64] http://archive.ubuntu.com/ubuntu/ ${CODENAME}-security main restricted universe multiverse" >>/etc/apt/sources.list.d/amd64.list \ + && echo "deb [arch=arm64] http://ports.ubuntu.com/ ${CODENAME} main restricted universe multiverse" >>/etc/apt/sources.list.d/arm64.list \ + && echo "deb [arch=arm64] http://ports.ubuntu.com/ ${CODENAME}-updates main restricted universe multiverse" >>/etc/apt/sources.list.d/arm64.list \ + && echo "deb [arch=arm64] http://ports.ubuntu.com/ ${CODENAME}-backports main restricted universe multiverse" >>/etc/apt/sources.list.d/arm64.list \ + && echo "deb [arch=arm64] http://ports.ubuntu.com/ ${CODENAME}-security main restricted universe multiverse" >>/etc/apt/sources.list.d/arm64.list \ + && dpkg --add-architecture arm64 \ + && apt-get update -yqq \ + && apt-get install -yqq --no-install-recommends cross-gcc-dev \ + && TARGET_LIST="arm64" cross-gcc-gensource 6 \ + && cd cross-gcc-packages-amd64/cross-gcc-6-arm64 \ + && ln -fs /usr/share/zoneinfo/America/Toronto /etc/localtime \ + && apt-get install -yqq --no-install-recommends \ + gcc-6-source libstdc++6-arm64-cross binutils-aarch64-linux-gnu \ + bison flex libtool gdb sharutils netbase libcloog-isl-dev libmpc-dev \ + libmpfr-dev libgmp-dev systemtap-sdt-dev autogen expect chrpath zlib1g-dev \ + zip libc6-dev:arm64 linux-libc-dev:arm64 libgcc1:arm64 libcurl4-openssl-dev:arm64 \ + libfontconfig1-dev:arm64 libfreetype6-dev:arm64 liblttng-ust0:arm64 libstdc++6:arm64 libssl-dev:arm64 # Link to build script RUN ln -sf ${SOURCE_DIR}/deployment/build.ubuntu.arm64 /build.sh diff --git a/deployment/Dockerfile.ubuntu.armhf b/deployment/Dockerfile.ubuntu.armhf index 0392f7b2f..aaaedda82 100644 --- a/deployment/Dockerfile.ubuntu.armhf +++ b/deployment/Dockerfile.ubuntu.armhf @@ -11,34 +11,41 @@ ENV ARCH=amd64 ENV IS_DOCKER=YES # Prepare Debian build environment -RUN apt-get update \ - && apt-get install -y apt-transport-https debhelper gnupg wget devscripts mmv +RUN apt-get update -yqq \ + && apt-get install -yqq --no-install-recommends \ + apt-transport-https debhelper gnupg wget ca-certificates devscripts \ + mmv build-essential lsb-release # Install dotnet repository # https://dotnet.microsoft.com/download/linux-package-manager/debian9/sdk-current -RUN wget https://download.visualstudio.microsoft.com/download/pr/8468e541-a99a-4191-8470-654fa0747a9a/cb32548d2fd3d60ef3fe8fc80cd735ef/dotnet-sdk-5.0.302-linux-x64.tar.gz -O dotnet-sdk.tar.gz \ - && mkdir -p dotnet-sdk \ - && tar -xzf dotnet-sdk.tar.gz -C dotnet-sdk \ - && ln -s $( pwd )/dotnet-sdk/dotnet /usr/bin/dotnet +RUN wget -q https://download.visualstudio.microsoft.com/download/pr/8468e541-a99a-4191-8470-654fa0747a9a/cb32548d2fd3d60ef3fe8fc80cd735ef/dotnet-sdk-5.0.302-linux-x64.tar.gz -O dotnet-sdk.tar.gz \ + && mkdir -p dotnet-sdk \ + && tar -xzf dotnet-sdk.tar.gz -C dotnet-sdk \ + && ln -s $( pwd )/dotnet-sdk/dotnet /usr/bin/dotnet # Prepare the cross-toolchain RUN rm /etc/apt/sources.list \ - && export CODENAME="$( lsb_release -c -s )" \ - && echo "deb [arch=amd64] http://archive.ubuntu.com/ubuntu/ ${CODENAME} main restricted universe multiverse" >>/etc/apt/sources.list.d/amd64.list \ - && echo "deb [arch=amd64] http://archive.ubuntu.com/ubuntu/ ${CODENAME}-updates main restricted universe multiverse" >>/etc/apt/sources.list.d/amd64.list \ - && echo "deb [arch=amd64] http://archive.ubuntu.com/ubuntu/ ${CODENAME}-backports main restricted universe multiverse" >>/etc/apt/sources.list.d/amd64.list \ - && echo "deb [arch=amd64] http://archive.ubuntu.com/ubuntu/ ${CODENAME}-security main restricted universe multiverse" >>/etc/apt/sources.list.d/amd64.list \ - && echo "deb [arch=armhf] http://ports.ubuntu.com/ ${CODENAME} main restricted universe multiverse" >>/etc/apt/sources.list.d/armhf.list \ - && echo "deb [arch=armhf] http://ports.ubuntu.com/ ${CODENAME}-updates main restricted universe multiverse" >>/etc/apt/sources.list.d/armhf.list \ - && echo "deb [arch=armhf] http://ports.ubuntu.com/ ${CODENAME}-backports main restricted universe multiverse" >>/etc/apt/sources.list.d/armhf.list \ - && echo "deb [arch=armhf] http://ports.ubuntu.com/ ${CODENAME}-security main restricted universe multiverse" >>/etc/apt/sources.list.d/armhf.list \ - && dpkg --add-architecture armhf \ - && apt-get update \ - && apt-get install -y cross-gcc-dev \ - && TARGET_LIST="armhf" cross-gcc-gensource 6 \ - && cd cross-gcc-packages-amd64/cross-gcc-6-armhf \ - && ln -fs /usr/share/zoneinfo/America/Toronto /etc/localtime \ - && apt-get install -y gcc-6-source libstdc++6-armhf-cross binutils-arm-linux-gnueabihf bison flex libtool gdb sharutils netbase libcloog-isl-dev libmpc-dev libmpfr-dev libgmp-dev systemtap-sdt-dev autogen expect chrpath zlib1g-dev zip libc6-dev:armhf linux-libc-dev:armhf libgcc1:armhf libcurl4-openssl-dev:armhf libfontconfig1-dev:armhf libfreetype6-dev:armhf liblttng-ust0:armhf libstdc++6:armhf libssl-dev:armhf + && export CODENAME="$( lsb_release -c -s )" \ + && echo "deb [arch=amd64] http://archive.ubuntu.com/ubuntu/ ${CODENAME} main restricted universe multiverse" >>/etc/apt/sources.list.d/amd64.list \ + && echo "deb [arch=amd64] http://archive.ubuntu.com/ubuntu/ ${CODENAME}-updates main restricted universe multiverse" >>/etc/apt/sources.list.d/amd64.list \ + && echo "deb [arch=amd64] http://archive.ubuntu.com/ubuntu/ ${CODENAME}-backports main restricted universe multiverse" >>/etc/apt/sources.list.d/amd64.list \ + && echo "deb [arch=amd64] http://archive.ubuntu.com/ubuntu/ ${CODENAME}-security main restricted universe multiverse" >>/etc/apt/sources.list.d/amd64.list \ + && echo "deb [arch=armhf] http://ports.ubuntu.com/ ${CODENAME} main restricted universe multiverse" >>/etc/apt/sources.list.d/armhf.list \ + && echo "deb [arch=armhf] http://ports.ubuntu.com/ ${CODENAME}-updates main restricted universe multiverse" >>/etc/apt/sources.list.d/armhf.list \ + && echo "deb [arch=armhf] http://ports.ubuntu.com/ ${CODENAME}-backports main restricted universe multiverse" >>/etc/apt/sources.list.d/armhf.list \ + && echo "deb [arch=armhf] http://ports.ubuntu.com/ ${CODENAME}-security main restricted universe multiverse" >>/etc/apt/sources.list.d/armhf.list \ + && dpkg --add-architecture armhf \ + && apt-get update -yqq \ + && apt-get install -yqq cross-gcc-dev \ + && TARGET_LIST="armhf" cross-gcc-gensource 6 \ + && cd cross-gcc-packages-amd64/cross-gcc-6-armhf \ + && ln -fs /usr/share/zoneinfo/America/Toronto /etc/localtime \ + && apt-get install -yqq --no-install-recommends \ + gcc-6-source libstdc++6-armhf-cross binutils-arm-linux-gnueabihf \ + bison flex libtool gdb sharutils netbase libcloog-isl-dev libmpc-dev \ + libmpfr-dev libgmp-dev systemtap-sdt-dev autogen expect chrpath zlib1g-dev \ + zip libc6-dev:armhf linux-libc-dev:armhf libgcc1:armhf libcurl4-openssl-dev:armhf \ + libfontconfig1-dev:armhf libfreetype6-dev:armhf liblttng-ust0:armhf libstdc++6:armhf libssl-dev:armhf # Link to build script RUN ln -sf ${SOURCE_DIR}/deployment/build.debian.armhf /build.sh diff --git a/deployment/Dockerfile.windows.amd64 b/deployment/Dockerfile.windows.amd64 index 9c78897a4..acd0e1854 100644 --- a/deployment/Dockerfile.windows.amd64 +++ b/deployment/Dockerfile.windows.amd64 @@ -1,8 +1,7 @@ -FROM debian:10 +FROM mcr.microsoft.com/dotnet/sdk:5.0-buster-slim # Docker build arguments ARG SOURCE_DIR=/jellyfin ARG ARTIFACT_DIR=/dist -ARG SDK_VERSION=5.0 # Docker run environment ENV SOURCE_DIR=/jellyfin ENV ARTIFACT_DIR=/dist @@ -10,15 +9,11 @@ ENV DEB_BUILD_OPTIONS=noddebs ENV IS_DOCKER=YES # Prepare Debian build environment -RUN apt-get update \ - && apt-get install -y apt-transport-https debhelper gnupg wget devscripts mmv libc6-dev libcurl4-openssl-dev libfontconfig1-dev libfreetype6-dev libssl-dev libssl1.1 liblttng-ust0 zip - -# Install dotnet repository -# https://dotnet.microsoft.com/download/linux-package-manager/debian9/sdk-current -RUN wget https://download.visualstudio.microsoft.com/download/pr/8468e541-a99a-4191-8470-654fa0747a9a/cb32548d2fd3d60ef3fe8fc80cd735ef/dotnet-sdk-5.0.302-linux-x64.tar.gz -O dotnet-sdk.tar.gz \ - && mkdir -p dotnet-sdk \ - && tar -xzf dotnet-sdk.tar.gz -C dotnet-sdk \ - && ln -s $( pwd )/dotnet-sdk/dotnet /usr/bin/dotnet +RUN apt-get update -yqq \ + && apt-get install -yqq --no-install-recommends \ + apt-transport-https debhelper gnupg devscripts unzip \ + mmv libcurl4-openssl-dev libfontconfig1-dev \ + libfreetype6-dev libssl-dev libssl1.1 liblttng-ust0 zip # Link to docker-build script RUN ln -sf ${SOURCE_DIR}/deployment/build.windows.amd64 /build.sh diff --git a/src/Jellyfin.Extensions/Jellyfin.Extensions.csproj b/src/Jellyfin.Extensions/Jellyfin.Extensions.csproj index f343be1e3..981b796e0 100644 --- a/src/Jellyfin.Extensions/Jellyfin.Extensions.csproj +++ b/src/Jellyfin.Extensions/Jellyfin.Extensions.csproj @@ -4,10 +4,6 @@ <TargetFramework>net5.0</TargetFramework> <GenerateAssemblyInfo>false</GenerateAssemblyInfo> <GenerateDocumentationFile>true</GenerateDocumentationFile> - <TreatWarningsAsErrors>true</TreatWarningsAsErrors> - <Nullable>enable</Nullable> - <AnalysisMode>AllEnabledByDefault</AnalysisMode> - <CodeAnalysisRuleSet>../../jellyfin.ruleset</CodeAnalysisRuleSet> </PropertyGroup> <PropertyGroup> diff --git a/tests/Jellyfin.Api.Tests/Jellyfin.Api.Tests.csproj b/tests/Jellyfin.Api.Tests/Jellyfin.Api.Tests.csproj index 07538b38b..4edd84384 100644 --- a/tests/Jellyfin.Api.Tests/Jellyfin.Api.Tests.csproj +++ b/tests/Jellyfin.Api.Tests/Jellyfin.Api.Tests.csproj @@ -8,9 +8,6 @@ <PropertyGroup> <TargetFramework>net5.0</TargetFramework> <IsPackable>false</IsPackable> - <TreatWarningsAsErrors>true</TreatWarningsAsErrors> - <Nullable>enable</Nullable> - <AnalysisMode>AllEnabledByDefault</AnalysisMode> <CodeAnalysisRuleSet>../jellyfin-tests.ruleset</CodeAnalysisRuleSet> </PropertyGroup> @@ -23,7 +20,7 @@ <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.10.0" /> <PackageReference Include="xunit" Version="2.4.1" /> <PackageReference Include="xunit.runner.visualstudio" Version="2.4.3" /> - <PackageReference Include="coverlet.collector" Version="3.0.3" /> + <PackageReference Include="coverlet.collector" Version="3.1.0" /> <PackageReference Include="Moq" Version="4.16.1" /> </ItemGroup> diff --git a/tests/Jellyfin.Common.Tests/Jellyfin.Common.Tests.csproj b/tests/Jellyfin.Common.Tests/Jellyfin.Common.Tests.csproj index 546b2487e..e4350c336 100644 --- a/tests/Jellyfin.Common.Tests/Jellyfin.Common.Tests.csproj +++ b/tests/Jellyfin.Common.Tests/Jellyfin.Common.Tests.csproj @@ -8,9 +8,6 @@ <PropertyGroup> <TargetFramework>net5.0</TargetFramework> <IsPackable>false</IsPackable> - <TreatWarningsAsErrors>true</TreatWarningsAsErrors> - <Nullable>enable</Nullable> - <AnalysisMode>AllEnabledByDefault</AnalysisMode> <CodeAnalysisRuleSet>../jellyfin-tests.ruleset</CodeAnalysisRuleSet> </PropertyGroup> @@ -18,7 +15,7 @@ <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.10.0" /> <PackageReference Include="xunit" Version="2.4.1" /> <PackageReference Include="xunit.runner.visualstudio" Version="2.4.3" /> - <PackageReference Include="coverlet.collector" Version="3.0.3" /> + <PackageReference Include="coverlet.collector" Version="3.1.0" /> <PackageReference Include="FsCheck.Xunit" Version="2.15.3" /> </ItemGroup> diff --git a/tests/Jellyfin.Controller.Tests/Jellyfin.Controller.Tests.csproj b/tests/Jellyfin.Controller.Tests/Jellyfin.Controller.Tests.csproj index 9a8ddafa0..5b269a4b2 100644 --- a/tests/Jellyfin.Controller.Tests/Jellyfin.Controller.Tests.csproj +++ b/tests/Jellyfin.Controller.Tests/Jellyfin.Controller.Tests.csproj @@ -8,9 +8,6 @@ <PropertyGroup> <TargetFramework>net5.0</TargetFramework> <IsPackable>false</IsPackable> - <TreatWarningsAsErrors>true</TreatWarningsAsErrors> - <Nullable>enable</Nullable> - <AnalysisMode>AllEnabledByDefault</AnalysisMode> <CodeAnalysisRuleSet>../jellyfin-tests.ruleset</CodeAnalysisRuleSet> </PropertyGroup> @@ -19,7 +16,7 @@ <PackageReference Include="Moq" Version="4.16.1" /> <PackageReference Include="xunit" Version="2.4.1" /> <PackageReference Include="xunit.runner.visualstudio" Version="2.4.3" /> - <PackageReference Include="coverlet.collector" Version="3.0.3" /> + <PackageReference Include="coverlet.collector" Version="3.1.0" /> </ItemGroup> <!-- Code Analyzers --> diff --git a/tests/Jellyfin.Dlna.Tests/Jellyfin.Dlna.Tests.csproj b/tests/Jellyfin.Dlna.Tests/Jellyfin.Dlna.Tests.csproj index 1f6cd541c..713f6423c 100644 --- a/tests/Jellyfin.Dlna.Tests/Jellyfin.Dlna.Tests.csproj +++ b/tests/Jellyfin.Dlna.Tests/Jellyfin.Dlna.Tests.csproj @@ -3,9 +3,6 @@ <PropertyGroup> <TargetFramework>net5.0</TargetFramework> <IsPackable>false</IsPackable> - <TreatWarningsAsErrors>true</TreatWarningsAsErrors> - <Nullable>enable</Nullable> - <AnalysisMode>AllEnabledByDefault</AnalysisMode> <CodeAnalysisRuleSet>../jellyfin-tests.ruleset</CodeAnalysisRuleSet> </PropertyGroup> @@ -14,7 +11,7 @@ <PackageReference Include="Moq" Version="4.16.1" /> <PackageReference Include="xunit" Version="2.4.1" /> <PackageReference Include="xunit.runner.visualstudio" Version="2.4.3" /> - <PackageReference Include="coverlet.collector" Version="3.0.3" /> + <PackageReference Include="coverlet.collector" Version="3.1.0" /> </ItemGroup> <!-- Code Analyzers --> diff --git a/tests/Jellyfin.Extensions.Tests/Jellyfin.Extensions.Tests.csproj b/tests/Jellyfin.Extensions.Tests/Jellyfin.Extensions.Tests.csproj index f87e63be2..9272d5eef 100644 --- a/tests/Jellyfin.Extensions.Tests/Jellyfin.Extensions.Tests.csproj +++ b/tests/Jellyfin.Extensions.Tests/Jellyfin.Extensions.Tests.csproj @@ -3,9 +3,6 @@ <PropertyGroup> <TargetFramework>net5.0</TargetFramework> <IsPackable>false</IsPackable> - <TreatWarningsAsErrors>true</TreatWarningsAsErrors> - <Nullable>enable</Nullable> - <AnalysisMode>AllEnabledByDefault</AnalysisMode> <CodeAnalysisRuleSet>../jellyfin-tests.ruleset</CodeAnalysisRuleSet> </PropertyGroup> @@ -16,7 +13,7 @@ <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <PrivateAssets>all</PrivateAssets> </PackageReference> - <PackageReference Include="coverlet.collector" Version="1.3.0"> + <PackageReference Include="coverlet.collector" Version="3.1.0"> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <PrivateAssets>all</PrivateAssets> </PackageReference> diff --git a/tests/Jellyfin.MediaEncoding.Tests/Jellyfin.MediaEncoding.Tests.csproj b/tests/Jellyfin.MediaEncoding.Tests/Jellyfin.MediaEncoding.Tests.csproj index 6b828e113..a6a948e2b 100644 --- a/tests/Jellyfin.MediaEncoding.Tests/Jellyfin.MediaEncoding.Tests.csproj +++ b/tests/Jellyfin.MediaEncoding.Tests/Jellyfin.MediaEncoding.Tests.csproj @@ -8,9 +8,6 @@ <PropertyGroup> <TargetFramework>net5.0</TargetFramework> <IsPackable>false</IsPackable> - <TreatWarningsAsErrors>true</TreatWarningsAsErrors> - <Nullable>enable</Nullable> - <AnalysisMode>AllEnabledByDefault</AnalysisMode> <CodeAnalysisRuleSet>../jellyfin-tests.ruleset</CodeAnalysisRuleSet> </PropertyGroup> @@ -24,7 +21,7 @@ <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.10.0" /> <PackageReference Include="xunit" Version="2.4.1" /> <PackageReference Include="xunit.runner.visualstudio" Version="2.4.3" /> - <PackageReference Include="coverlet.collector" Version="3.0.3" /> + <PackageReference Include="coverlet.collector" Version="3.1.0" /> </ItemGroup> <!-- Code Analyzers --> diff --git a/tests/Jellyfin.MediaEncoding.Tests/Probing/ProbeResultNormalizerTests.cs b/tests/Jellyfin.MediaEncoding.Tests/Probing/ProbeResultNormalizerTests.cs index d8089eea2..59037c263 100644 --- a/tests/Jellyfin.MediaEncoding.Tests/Probing/ProbeResultNormalizerTests.cs +++ b/tests/Jellyfin.MediaEncoding.Tests/Probing/ProbeResultNormalizerTests.cs @@ -71,5 +71,25 @@ namespace Jellyfin.MediaEncoding.Tests.Probing Assert.True(res.PremiereDate.HasValue); Assert.Equal(DateTime.Parse("2021-01-01T00:00Z", DateTimeFormatInfo.CurrentInfo).ToUniversalTime(), res.PremiereDate); } + + [Fact] + public void GetMediaInfo_GivenOriginalDateContainsOnlyYear_Success() + { + var bytes = File.ReadAllBytes("Test Data/Probing/music_year_only_metadata.json"); + var internalMediaInfoResult = JsonSerializer.Deserialize<InternalMediaInfoResult>(bytes, _jsonOptions); + MediaInfo res = _probeResultNormalizer.GetMediaInfo(internalMediaInfoResult, null, true, "Test Data/Probing/music.flac", MediaProtocol.File); + + Assert.Equal("Baker Street", res.Name); + Assert.Single(res.Artists); + Assert.Equal("Gerry Rafferty", res.Artists[0]); + Assert.Equal("City to City", res.Album); + Assert.Equal(1978, res.ProductionYear); + Assert.True(res.PremiereDate.HasValue); + Assert.Equal(DateTime.Parse("1978-01-01T00:00Z", DateTimeFormatInfo.CurrentInfo).ToUniversalTime(), res.PremiereDate); + Assert.Contains("Electronic", res.Genres); + Assert.Contains("Ambient", res.Genres); + Assert.Contains("Pop", res.Genres); + Assert.Contains("Jazz", res.Genres); + } } } diff --git a/tests/Jellyfin.MediaEncoding.Tests/Test Data/Probing/music_year_only_metadata.json b/tests/Jellyfin.MediaEncoding.Tests/Test Data/Probing/music_year_only_metadata.json new file mode 100644 index 000000000..ddf890c45 --- /dev/null +++ b/tests/Jellyfin.MediaEncoding.Tests/Test Data/Probing/music_year_only_metadata.json @@ -0,0 +1,147 @@ +{ + "streams": [ + { + "index": 0, + "codec_name": "flac", + "codec_long_name": "FLAC (Free Lossless Audio Codec)", + "codec_type": "audio", + "codec_tag_string": "[0][0][0][0]", + "codec_tag": "0x0000", + "sample_fmt": "s16", + "sample_rate": "44100", + "channels": 2, + "channel_layout": "stereo", + "bits_per_sample": 0, + "r_frame_rate": "0/0", + "avg_frame_rate": "0/0", + "time_base": "1/44100", + "start_pts": 0, + "start_time": "0.000000", + "duration_ts": 16394616, + "duration": "371.760000", + "bits_per_raw_sample": "16", + "disposition": { + "default": 0, + "dub": 0, + "original": 0, + "comment": 0, + "lyrics": 0, + "karaoke": 0, + "forced": 0, + "hearing_impaired": 0, + "visual_impaired": 0, + "clean_effects": 0, + "attached_pic": 0, + "timed_thumbnails": 0 + } + }, + { + "index": 1, + "codec_name": "mjpeg", + "codec_long_name": "Motion JPEG", + "profile": "Baseline", + "codec_type": "video", + "codec_tag_string": "[0][0][0][0]", + "codec_tag": "0x0000", + "width": 500, + "height": 498, + "coded_width": 500, + "coded_height": 498, + "closed_captions": 0, + "has_b_frames": 0, + "sample_aspect_ratio": "1:1", + "display_aspect_ratio": "250:249", + "pix_fmt": "yuvj420p", + "level": -99, + "color_range": "pc", + "color_space": "bt470bg", + "chroma_location": "center", + "refs": 1, + "r_frame_rate": "90000/1", + "avg_frame_rate": "0/0", + "time_base": "1/90000", + "start_pts": 0, + "start_time": "0.000000", + "duration_ts": 33458400, + "duration": "371.760000", + "bits_per_raw_sample": "8", + "disposition": { + "default": 0, + "dub": 0, + "original": 0, + "comment": 0, + "lyrics": 0, + "karaoke": 0, + "forced": 0, + "hearing_impaired": 0, + "visual_impaired": 0, + "clean_effects": 0, + "attached_pic": 1, + "timed_thumbnails": 0 + }, + "tags": { + "comment": "Cover (front)" + } + } + ], + "format": { + "filename": "02 Baker Street.flac", + "nb_streams": 2, + "nb_programs": 0, + "format_name": "flac", + "format_long_name": "raw FLAC", + "start_time": "0.000000", + "duration": "371.760000", + "size": "37072649", + "bit_rate": "797775", + "probe_score": 100, + "tags": { + "MUSICBRAINZ_RELEASEGROUPID": "238c3fb4-5792-342b-b217-02f66298b424", + "ORIGINALDATE": "1978", + "ORIGINALYEAR": "1978", + "RELEASETYPE": "album", + "MUSICBRAINZ_ALBUMID": "30156786-e511-3106-ac95-66f0e880b24b", + "ASIN": "B000007O5H", + "MUSICBRAINZ_ALBUMARTISTID": "563201cb-721c-4cfb-acca-c1ba69e3d1fb", + "album_artist": "Gerry Rafferty", + "ALBUMARTISTSORT": "Rafferty, Gerry", + "LABEL": "Liberty EMI Records UK", + "CATALOGNUMBER": "CDP 7 46049 2", + "DATE": "1989-07-26", + "RELEASECOUNTRY": "GB", + "BARCODE": "077774604925", + "ALBUM": "City to City", + "SCRIPT": "Latn", + "RELEASESTATUS": "official", + "TOTALDISCS": "1", + "disc": "1", + "MEDIA": "CD", + "TOTALTRACKS": "10", + "MUSICBRAINZ_TRACKID": "9235e22e-afbd-48f7-b329-21dae6da2810", + "ISRC": "GBAYE1100924;GBAYE7800619", + "PERFORMER": "Hugh Burns (electric guitar);Nigel Jenkins (electric guitar);Tommy Eyre (keyboard and Moog);Glen LeFleur (percussion);Raphael Ravenscroft (saxophone);Henry Spinetti (drums (drum set));Gary Taylor (bass);Gerry Rafferty (lead vocals)", + "ARRANGER": "Graham Preskett", + "MIXER": "Declan O’Doherty", + "PRODUCER": "Hugh Murphy;Gerry Rafferty", + "MUSICBRAINZ_WORKID": "a9eb3c45-784c-3c32-860c-4b406f03961b", + "LANGUAGE": "eng", + "WORK": "Baker Street", + "COMPOSER": "Gerry Rafferty", + "COMPOSERSORT": "Rafferty, Gerry", + "LYRICIST": "Gerry Rafferty", + "TITLE": "Baker Street", + "MUSICBRAINZ_ARTISTID": "563201cb-721c-4cfb-acca-c1ba69e3d1fb", + "ARTIST": "Gerry Rafferty", + "ARTISTSORT": "Rafferty, Gerry", + "ARTISTS": "Gerry Rafferty", + "MUSICBRAINZ_RELEASETRACKID": "407cf7f7-440d-3e76-8b89-8686198868ea", + "track": "2", + "GENRE": "Electronic;Ambient;Pop;Jazz", + "WEBSITE": "http://www.gerryrafferty.com/", + "ACOUSTID_ID": "68f8d979-a659-4aa0-a216-eb3721a951eb", + "MOOD": "Acoustic;Not aggressive;Not electronic;Not happy;Party;Relaxed;Not sad", + "TRACKTOTAL": "10", + "DISCTOTAL": "1" + } + } +} diff --git a/tests/Jellyfin.Model.Tests/Entities/MediaStreamTests.cs b/tests/Jellyfin.Model.Tests/Entities/MediaStreamTests.cs new file mode 100644 index 000000000..e2274e19e --- /dev/null +++ b/tests/Jellyfin.Model.Tests/Entities/MediaStreamTests.cs @@ -0,0 +1,76 @@ +using MediaBrowser.Model.Entities; +using Xunit; + +namespace Jellyfin.Model.Tests.Entities +{ + public class MediaStreamTests + { + [Theory] + [InlineData(null, null, false, null)] + [InlineData(null, 0, false, null)] + [InlineData(0, null, false, null)] + [InlineData(640, 480, false, "480p")] + [InlineData(640, 480, true, "480i")] + [InlineData(720, 576, false, "576p")] + [InlineData(720, 576, true, "576i")] + [InlineData(960, 540, false, "540p")] + [InlineData(960, 540, true, "540i")] + [InlineData(1280, 720, false, "720p")] + [InlineData(1280, 720, true, "720i")] + [InlineData(1920, 1080, false, "1080p")] + [InlineData(1920, 1080, true, "1080i")] + [InlineData(4096, 3072, false, "4K")] + [InlineData(8192, 6144, false, "8K")] + [InlineData(512, 384, false, "480p")] + [InlineData(576, 336, false, "480p")] + [InlineData(624, 352, false, "480p")] + [InlineData(640, 352, false, "480p")] + [InlineData(704, 396, false, "480p")] + [InlineData(720, 404, false, "480p")] + [InlineData(720, 480, false, "480p")] + [InlineData(768, 576, false, "576p")] + [InlineData(960, 720, false, "720p")] + [InlineData(1280, 528, false, "720p")] + [InlineData(1280, 532, false, "720p")] + [InlineData(1280, 534, false, "720p")] + [InlineData(1280, 536, false, "720p")] + [InlineData(1280, 544, false, "720p")] + [InlineData(1280, 690, false, "720p")] + [InlineData(1280, 694, false, "720p")] + [InlineData(1280, 696, false, "720p")] + [InlineData(1280, 716, false, "720p")] + [InlineData(1280, 718, false, "720p")] + [InlineData(1912, 792, false, "1080p")] + [InlineData(1916, 1076, false, "1080p")] + [InlineData(1918, 1080, false, "1080p")] + [InlineData(1920, 796, false, "1080p")] + [InlineData(1920, 800, false, "1080p")] + [InlineData(1920, 802, false, "1080p")] + [InlineData(1920, 804, false, "1080p")] + [InlineData(1920, 808, false, "1080p")] + [InlineData(1920, 816, false, "1080p")] + [InlineData(1920, 856, false, "1080p")] + [InlineData(1920, 960, false, "1080p")] + [InlineData(1920, 1024, false, "1080p")] + [InlineData(1920, 1040, false, "1080p")] + [InlineData(1920, 1072, false, "1080p")] + [InlineData(1440, 1072, false, "1080p")] + [InlineData(1440, 1080, false, "1080p")] + [InlineData(3840, 1600, false, "4K")] + [InlineData(3840, 1606, false, "4K")] + [InlineData(3840, 1608, false, "4K")] + [InlineData(3840, 2160, false, "4K")] + [InlineData(7680, 4320, false, "8K")] + public void GetResolutionText_Valid(int? width, int? height, bool interlaced, string expected) + { + var mediaStream = new MediaStream() + { + Width = width, + Height = height, + IsInterlaced = interlaced + }; + + Assert.Equal(expected, mediaStream.GetResolutionText()); + } + } +} diff --git a/tests/Jellyfin.Model.Tests/Jellyfin.Model.Tests.csproj b/tests/Jellyfin.Model.Tests/Jellyfin.Model.Tests.csproj index 40c51e524..06ff22c7e 100644 --- a/tests/Jellyfin.Model.Tests/Jellyfin.Model.Tests.csproj +++ b/tests/Jellyfin.Model.Tests/Jellyfin.Model.Tests.csproj @@ -3,9 +3,6 @@ <PropertyGroup> <TargetFramework>net5.0</TargetFramework> <IsPackable>false</IsPackable> - <TreatWarningsAsErrors>true</TreatWarningsAsErrors> - <Nullable>enable</Nullable> - <AnalysisMode>AllEnabledByDefault</AnalysisMode> <CodeAnalysisRuleSet>../jellyfin-tests.ruleset</CodeAnalysisRuleSet> </PropertyGroup> @@ -13,7 +10,7 @@ <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.10.0" /> <PackageReference Include="xunit" Version="2.4.1" /> <PackageReference Include="xunit.runner.visualstudio" Version="2.4.1" /> - <PackageReference Include="coverlet.collector" Version="3.0.3" /> + <PackageReference Include="coverlet.collector" Version="3.1.0" /> <PackageReference Include="FsCheck.Xunit" Version="2.15.3" /> </ItemGroup> diff --git a/tests/Jellyfin.Naming.Tests/Jellyfin.Naming.Tests.csproj b/tests/Jellyfin.Naming.Tests/Jellyfin.Naming.Tests.csproj index e386cb8c1..510c8f60a 100644 --- a/tests/Jellyfin.Naming.Tests/Jellyfin.Naming.Tests.csproj +++ b/tests/Jellyfin.Naming.Tests/Jellyfin.Naming.Tests.csproj @@ -8,9 +8,6 @@ <PropertyGroup> <TargetFramework>net5.0</TargetFramework> <IsPackable>false</IsPackable> - <TreatWarningsAsErrors>true</TreatWarningsAsErrors> - <Nullable>enable</Nullable> - <AnalysisMode>AllEnabledByDefault</AnalysisMode> <CodeAnalysisRuleSet>../jellyfin-tests.ruleset</CodeAnalysisRuleSet> </PropertyGroup> @@ -18,7 +15,7 @@ <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.10.0" /> <PackageReference Include="xunit" Version="2.4.1" /> <PackageReference Include="xunit.runner.visualstudio" Version="2.4.3" /> - <PackageReference Include="coverlet.collector" Version="3.0.3" /> + <PackageReference Include="coverlet.collector" Version="3.1.0" /> </ItemGroup> <ItemGroup> diff --git a/tests/Jellyfin.Naming.Tests/TV/SimpleEpisodeTests.cs b/tests/Jellyfin.Naming.Tests/TV/SimpleEpisodeTests.cs index 89579c037..6d49ac832 100644 --- a/tests/Jellyfin.Naming.Tests/TV/SimpleEpisodeTests.cs +++ b/tests/Jellyfin.Naming.Tests/TV/SimpleEpisodeTests.cs @@ -21,7 +21,8 @@ namespace Jellyfin.Naming.Tests.TV [InlineData("[Baz-Bar]Foo - [1080p][Multiple Subtitle]/[Baz-Bar] Foo - 05 [1080p][Multiple Subtitle].mkv", "Foo", null, 5)] [InlineData(@"/Foo/The.Series.Name.S01E04.WEBRip.x264-Baz[Bar]/the.series.name.s01e04.webrip.x264-Baz[Bar].mkv", "The.Series.Name", 1, 4)] [InlineData(@"Love.Death.and.Robots.S01.1080p.NF.WEB-DL.DDP5.1.x264-NTG/Love.Death.and.Robots.S01E01.Sonnies.Edge.1080p.NF.WEB-DL.DDP5.1.x264-NTG.mkv", "Love.Death.and.Robots", 1, 1)] - // TODO: [InlineData("[Baz-Bar]Foo - 01 - 12[1080p][Multiple Subtitle]/[Baz-Bar] Foo - 05 [1080p][Multiple Subtitle].mkv", "Foo", null, 5)] + [InlineData("[YuiSubs] Tensura Nikki - Tensei Shitara Slime Datta Ken/[YuiSubs] Tensura Nikki - Tensei Shitara Slime Datta Ken - 12 (NVENC H.265 1080p).mkv", "Tensura Nikki - Tensei Shitara Slime Datta Ken", null, 12)] + [InlineData("[Baz-Bar]Foo - 01 - 12[1080p][Multiple Subtitle]/[Baz-Bar] Foo - 05 [1080p][Multiple Subtitle].mkv", "Foo", null, 5)] // TODO: [InlineData("E:\\Anime\\Yahari Ore no Seishun Love Comedy wa Machigatteiru\\Yahari Ore no Seishun Love Comedy wa Machigatteiru. Zoku\\Oregairu Zoku 11 - Hayama Hayato Always Renconds to Everyone's Expectations..mkv", "Yahari Ore no Seishun Love Comedy wa Machigatteiru", null, 11)] // TODO: [InlineData(@"/Library/Series/The Grand Tour (2016)/Season 1/S01E01 The Holy Trinity.mkv", "The Grand Tour", 1, 1)] public void TestSimple(string path, string seriesName, int? seasonNumber, int? episodeNumber) diff --git a/tests/Jellyfin.Networking.Tests/Jellyfin.Networking.Tests.csproj b/tests/Jellyfin.Networking.Tests/Jellyfin.Networking.Tests.csproj index 97bf673ae..2c6e2e5f6 100644 --- a/tests/Jellyfin.Networking.Tests/Jellyfin.Networking.Tests.csproj +++ b/tests/Jellyfin.Networking.Tests/Jellyfin.Networking.Tests.csproj @@ -8,9 +8,6 @@ <PropertyGroup> <TargetFramework>net5.0</TargetFramework> <IsPackable>false</IsPackable> - <TreatWarningsAsErrors>true</TreatWarningsAsErrors> - <Nullable>enable</Nullable> - <AnalysisMode>AllEnabledByDefault</AnalysisMode> <CodeAnalysisRuleSet>../jellyfin-tests.ruleset</CodeAnalysisRuleSet> </PropertyGroup> @@ -18,7 +15,7 @@ <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.10.0" /> <PackageReference Include="xunit" Version="2.4.1" /> <PackageReference Include="xunit.runner.visualstudio" Version="2.4.1" /> - <PackageReference Include="coverlet.collector" Version="3.0.3" /> + <PackageReference Include="coverlet.collector" Version="3.1.0" /> <PackageReference Include="FsCheck.Xunit" Version="2.15.3" /> <PackageReference Include="Moq" Version="4.16.1" /> </ItemGroup> diff --git a/tests/Jellyfin.Providers.Tests/Jellyfin.Providers.Tests.csproj b/tests/Jellyfin.Providers.Tests/Jellyfin.Providers.Tests.csproj index 14bd53db5..195fc8801 100644 --- a/tests/Jellyfin.Providers.Tests/Jellyfin.Providers.Tests.csproj +++ b/tests/Jellyfin.Providers.Tests/Jellyfin.Providers.Tests.csproj @@ -3,9 +3,6 @@ <PropertyGroup> <TargetFramework>net5.0</TargetFramework> <IsPackable>false</IsPackable> - <TreatWarningsAsErrors>true</TreatWarningsAsErrors> - <Nullable>enable</Nullable> - <AnalysisMode>AllEnabledByDefault</AnalysisMode> <CodeAnalysisRuleSet>../jellyfin-tests.ruleset</CodeAnalysisRuleSet> </PropertyGroup> @@ -17,7 +14,7 @@ <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <PrivateAssets>all</PrivateAssets> </PackageReference> - <PackageReference Include="coverlet.collector" Version="3.0.3"> + <PackageReference Include="coverlet.collector" Version="3.1.0"> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <PrivateAssets>all</PrivateAssets> </PackageReference> diff --git a/tests/Jellyfin.Server.Implementations.Tests/Jellyfin.Server.Implementations.Tests.csproj b/tests/Jellyfin.Server.Implementations.Tests/Jellyfin.Server.Implementations.Tests.csproj index adbca8344..387f259ce 100644 --- a/tests/Jellyfin.Server.Implementations.Tests/Jellyfin.Server.Implementations.Tests.csproj +++ b/tests/Jellyfin.Server.Implementations.Tests/Jellyfin.Server.Implementations.Tests.csproj @@ -8,9 +8,6 @@ <PropertyGroup> <TargetFramework>net5.0</TargetFramework> <IsPackable>false</IsPackable> - <TreatWarningsAsErrors>true</TreatWarningsAsErrors> - <Nullable>enable</Nullable> - <AnalysisMode>AllEnabledByDefault</AnalysisMode> <CodeAnalysisRuleSet>../jellyfin-tests.ruleset</CodeAnalysisRuleSet> <RootNamespace>Jellyfin.Server.Implementations.Tests</RootNamespace> </PropertyGroup> @@ -29,7 +26,7 @@ <PackageReference Include="xunit" Version="2.4.1" /> <PackageReference Include="xunit.runner.visualstudio" Version="2.4.3" /> <PackageReference Include="Xunit.SkippableFact" Version="1.4.13" /> - <PackageReference Include="coverlet.collector" Version="3.0.3" /> + <PackageReference Include="coverlet.collector" Version="3.1.0" /> </ItemGroup> <!-- Code Analyzers --> diff --git a/tests/Jellyfin.Server.Implementations.Tests/Localization/LocalizationManagerTests.cs b/tests/Jellyfin.Server.Implementations.Tests/Localization/LocalizationManagerTests.cs new file mode 100644 index 000000000..edd4b1e55 --- /dev/null +++ b/tests/Jellyfin.Server.Implementations.Tests/Localization/LocalizationManagerTests.cs @@ -0,0 +1,179 @@ +using System; +using System.Linq; +using System.Threading.Tasks; +using Emby.Server.Implementations.Localization; +using MediaBrowser.Controller.Configuration; +using MediaBrowser.Model.Configuration; +using Microsoft.Extensions.Logging.Abstractions; +using Moq; +using Xunit; + +namespace Jellyfin.Server.Implementations.Tests.Localization +{ + public class LocalizationManagerTests + { + [Fact] + public void GetCountries_All_Success() + { + var localizationManager = Setup(new ServerConfiguration + { + UICulture = "de-DE" + }); + var countries = localizationManager.GetCountries().ToList(); + + Assert.Equal(139, countries.Count); + + var germany = countries.FirstOrDefault(x => x.Name.Equals("DE", StringComparison.Ordinal)); + Assert.NotNull(germany); + Assert.Equal("Germany", germany!.DisplayName); + Assert.Equal("DEU", germany.ThreeLetterISORegionName); + Assert.Equal("DE", germany.TwoLetterISORegionName); + } + + [Fact] + public async Task GetCultures_All_Success() + { + var localizationManager = Setup(new ServerConfiguration + { + UICulture = "de-DE" + }); + await localizationManager.LoadAll(); + var cultures = localizationManager.GetCultures().ToList(); + + Assert.Equal(189, cultures.Count); + + var germany = cultures.FirstOrDefault(x => x.TwoLetterISOLanguageName.Equals("de", StringComparison.Ordinal)); + Assert.NotNull(germany); + Assert.Equal("ger", germany!.ThreeLetterISOLanguageName); + Assert.Equal("German", germany.DisplayName); + Assert.Equal("German", germany.Name); + Assert.Contains("deu", germany.ThreeLetterISOLanguageNames); + Assert.Contains("ger", germany.ThreeLetterISOLanguageNames); + } + + [Theory] + [InlineData("de")] + [InlineData("ger")] + [InlineData("german")] + public async Task FindLanguageInfo_Valid_Success(string identifier) + { + var localizationManager = Setup(new ServerConfiguration + { + UICulture = "de-DE" + }); + await localizationManager.LoadAll(); + + var germany = localizationManager.FindLanguageInfo(identifier); + Assert.NotNull(germany); + + Assert.Equal("ger", germany.ThreeLetterISOLanguageName); + Assert.Equal("German", germany.DisplayName); + Assert.Equal("German", germany.Name); + Assert.Contains("deu", germany.ThreeLetterISOLanguageNames); + Assert.Contains("ger", germany.ThreeLetterISOLanguageNames); + } + + [Fact] + public async Task GetParentalRatings_Default_Success() + { + var localizationManager = Setup(new ServerConfiguration + { + UICulture = "de-DE" + }); + await localizationManager.LoadAll(); + var ratings = localizationManager.GetParentalRatings().ToList(); + + Assert.Equal(23, ratings.Count); + + var tvma = ratings.FirstOrDefault(x => x.Name.Equals("TV-MA", StringComparison.Ordinal)); + Assert.NotNull(tvma); + Assert.Equal(9, tvma!.Value); + } + + [Fact] + public async Task GetParentalRatings_ConfiguredCountryCode_Success() + { + var localizationManager = Setup(new ServerConfiguration() + { + MetadataCountryCode = "DE" + }); + await localizationManager.LoadAll(); + var ratings = localizationManager.GetParentalRatings().ToList(); + + Assert.Equal(10, ratings.Count); + + var fsk = ratings.FirstOrDefault(x => x.Name.Equals("FSK-12", StringComparison.Ordinal)); + Assert.NotNull(fsk); + Assert.Equal(7, fsk!.Value); + } + + [Theory] + [InlineData("CA-R", "CA", 10)] + [InlineData("FSK-16", "DE", 8)] + [InlineData("FSK-18", "DE", 9)] + [InlineData("FSK-18", "US", 9)] + [InlineData("TV-MA", "US", 9)] + [InlineData("XXX", "asdf", 100)] + [InlineData("Germany: FSK-18", "DE", 9)] + public async Task GetRatingLevel_GivenValidString_Success(string value, string countryCode, int expectedLevel) + { + var localizationManager = Setup(new ServerConfiguration() + { + MetadataCountryCode = countryCode + }); + await localizationManager.LoadAll(); + var level = localizationManager.GetRatingLevel(value); + Assert.NotNull(level); + Assert.Equal(expectedLevel, level!); + } + + [Fact] + public async Task GetRatingLevel_GivenUnratedString_Success() + { + var localizationManager = Setup(new ServerConfiguration() + { + UICulture = "de-DE" + }); + await localizationManager.LoadAll(); + Assert.Null(localizationManager.GetRatingLevel("n/a")); + } + + [Theory] + [InlineData("Default", "Default")] + [InlineData("HeaderLiveTV", "Live TV")] + public void GetLocalizedString_Valid_Success(string key, string expected) + { + var localizationManager = Setup(new ServerConfiguration() + { + UICulture = "en-US" + }); + + var translated = localizationManager.GetLocalizedString(key); + Assert.NotNull(translated); + Assert.Equal(expected, translated); + } + + [Fact] + public void GetLocalizedString_Invalid_Success() + { + var localizationManager = Setup(new ServerConfiguration() + { + UICulture = "en-US" + }); + + var key = "SuperInvalidTranslationKeyThatWillNeverBeAdded"; + + var translated = localizationManager.GetLocalizedString(key); + Assert.NotNull(translated); + Assert.Equal(key, translated); + } + + private LocalizationManager Setup(ServerConfiguration config) + { + var mockConfiguration = new Mock<IServerConfigurationManager>(); + mockConfiguration.SetupGet(x => x.Configuration).Returns(config); + + return new LocalizationManager(mockConfiguration.Object, new NullLogger<LocalizationManager>()); + } + } +} diff --git a/tests/Jellyfin.Server.Integration.Tests/Jellyfin.Server.Integration.Tests.csproj b/tests/Jellyfin.Server.Integration.Tests/Jellyfin.Server.Integration.Tests.csproj index 8bbe58387..cf4215339 100644 --- a/tests/Jellyfin.Server.Integration.Tests/Jellyfin.Server.Integration.Tests.csproj +++ b/tests/Jellyfin.Server.Integration.Tests/Jellyfin.Server.Integration.Tests.csproj @@ -2,9 +2,6 @@ <PropertyGroup> <TargetFramework>net5.0</TargetFramework> <IsPackable>false</IsPackable> - <TreatWarningsAsErrors>true</TreatWarningsAsErrors> - <Nullable>enable</Nullable> - <AnalysisMode>AllEnabledByDefault</AnalysisMode> <CodeAnalysisRuleSet>../jellyfin-tests.ruleset</CodeAnalysisRuleSet> </PropertyGroup> @@ -18,7 +15,7 @@ <PackageReference Include="xunit" Version="2.4.1" /> <PackageReference Include="xunit.runner.visualstudio" Version="2.4.3" /> <PackageReference Include="Xunit.Priority" Version="1.1.6" /> - <PackageReference Include="coverlet.collector" Version="3.0.3" /> + <PackageReference Include="coverlet.collector" Version="3.1.0" /> <PackageReference Include="Moq" Version="4.16.0" /> </ItemGroup> diff --git a/tests/Jellyfin.Server.Tests/Jellyfin.Server.Tests.csproj b/tests/Jellyfin.Server.Tests/Jellyfin.Server.Tests.csproj index 0bd48e8ab..2f95f5c01 100644 --- a/tests/Jellyfin.Server.Tests/Jellyfin.Server.Tests.csproj +++ b/tests/Jellyfin.Server.Tests/Jellyfin.Server.Tests.csproj @@ -3,9 +3,6 @@ <PropertyGroup> <TargetFramework>net5.0</TargetFramework> <IsPackable>false</IsPackable> - <TreatWarningsAsErrors>true</TreatWarningsAsErrors> - <Nullable>enable</Nullable> - <AnalysisMode>AllEnabledByDefault</AnalysisMode> <CodeAnalysisRuleSet>../jellyfin-tests.ruleset</CodeAnalysisRuleSet> </PropertyGroup> @@ -18,7 +15,7 @@ <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.10.0" /> <PackageReference Include="xunit" Version="2.4.1" /> <PackageReference Include="xunit.runner.visualstudio" Version="2.4.3" /> - <PackageReference Include="coverlet.collector" Version="3.0.3" /> + <PackageReference Include="coverlet.collector" Version="3.1.0" /> <PackageReference Include="Moq" Version="4.16.0" /> </ItemGroup> diff --git a/tests/Jellyfin.XbmcMetadata.Tests/Jellyfin.XbmcMetadata.Tests.csproj b/tests/Jellyfin.XbmcMetadata.Tests/Jellyfin.XbmcMetadata.Tests.csproj index 0a04a5c54..78837bba6 100644 --- a/tests/Jellyfin.XbmcMetadata.Tests/Jellyfin.XbmcMetadata.Tests.csproj +++ b/tests/Jellyfin.XbmcMetadata.Tests/Jellyfin.XbmcMetadata.Tests.csproj @@ -3,9 +3,6 @@ <PropertyGroup> <TargetFramework>net5.0</TargetFramework> <IsPackable>false</IsPackable> - <TreatWarningsAsErrors>true</TreatWarningsAsErrors> - <Nullable>enable</Nullable> - <AnalysisMode>AllEnabledByDefault</AnalysisMode> <CodeAnalysisRuleSet>../jellyfin-tests.ruleset</CodeAnalysisRuleSet> </PropertyGroup> @@ -20,7 +17,7 @@ <PackageReference Include="Moq" Version="4.16.1" /> <PackageReference Include="xunit" Version="2.4.1" /> <PackageReference Include="xunit.runner.visualstudio" Version="2.4.3" /> - <PackageReference Include="coverlet.collector" Version="3.0.3" /> + <PackageReference Include="coverlet.collector" Version="3.1.0" /> </ItemGroup> <!-- Code Analyzers --> |
