mirror of
https://github.com/jellyfin/jellyfin
synced 2024-07-25 03:44:34 +00:00
commit
2f426dfc97
|
@ -7,7 +7,7 @@ parameters:
|
|||
default: "ubuntu-latest"
|
||||
- name: DotNetSdkVersion
|
||||
type: string
|
||||
default: 3.1.100
|
||||
default: 5.0.100
|
||||
|
||||
jobs:
|
||||
- job: CompatibilityCheck
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
parameters:
|
||||
LinuxImage: 'ubuntu-latest'
|
||||
RestoreBuildProjects: 'Jellyfin.Server/Jellyfin.Server.csproj'
|
||||
DotNetSdkVersion: 3.1.100
|
||||
DotNetSdkVersion: 5.0.100
|
||||
|
||||
jobs:
|
||||
- job: Build
|
||||
|
|
|
@ -10,7 +10,7 @@ parameters:
|
|||
default: "tests/**/*Tests.csproj"
|
||||
- name: DotNetSdkVersion
|
||||
type: string
|
||||
default: 3.1.100
|
||||
default: 5.0.100
|
||||
|
||||
jobs:
|
||||
- job: Test
|
||||
|
@ -94,5 +94,5 @@ jobs:
|
|||
displayName: 'Publish OpenAPI Artifact'
|
||||
condition: and(succeeded(), eq(variables['Agent.OS'], 'Linux'))
|
||||
inputs:
|
||||
targetPath: "tests/Jellyfin.Api.Tests/bin/Release/netcoreapp3.1/openapi.json"
|
||||
targetPath: "tests/Jellyfin.Api.Tests/bin/Release/net5.0/openapi.json"
|
||||
artifactName: 'OpenAPI Spec'
|
||||
|
|
|
@ -6,7 +6,7 @@ variables:
|
|||
- name: RestoreBuildProjects
|
||||
value: 'Jellyfin.Server/Jellyfin.Server.csproj'
|
||||
- name: DotNetSdkVersion
|
||||
value: 3.1.100
|
||||
value: 5.0.100
|
||||
|
||||
pr:
|
||||
autoCancel: true
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
ARG DOTNET_VERSION=3.1
|
||||
ARG DOTNET_VERSION=5.0
|
||||
|
||||
FROM node:alpine as web-builder
|
||||
ARG JELLYFIN_WEB_VERSION=master
|
||||
|
@ -8,7 +8,7 @@ RUN apk add curl git zlib zlib-dev autoconf g++ make libpng-dev gifsicle alpine-
|
|||
&& yarn install \
|
||||
&& mv dist /dist
|
||||
|
||||
FROM mcr.microsoft.com/dotnet/core/sdk:${DOTNET_VERSION}-buster as builder
|
||||
FROM mcr.microsoft.com/dotnet/sdk:${DOTNET_VERSION}-buster as builder
|
||||
WORKDIR /repo
|
||||
COPY . .
|
||||
ENV DOTNET_CLI_TELEMETRY_OPTOUT=1
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
#####################################
|
||||
# Requires binfm_misc registration
|
||||
# https://github.com/multiarch/qemu-user-static#binfmt_misc-register
|
||||
ARG DOTNET_VERSION=3.1
|
||||
ARG DOTNET_VERSION=5.0
|
||||
|
||||
|
||||
FROM node:alpine as web-builder
|
||||
|
@ -14,7 +14,7 @@ RUN apk add curl git zlib zlib-dev autoconf g++ make libpng-dev gifsicle alpine-
|
|||
&& mv dist /dist
|
||||
|
||||
|
||||
FROM mcr.microsoft.com/dotnet/core/sdk:${DOTNET_VERSION} as builder
|
||||
FROM mcr.microsoft.com/dotnet/sdk:${DOTNET_VERSION} as builder
|
||||
WORKDIR /repo
|
||||
COPY . .
|
||||
ENV DOTNET_CLI_TELEMETRY_OPTOUT=1
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
#####################################
|
||||
# Requires binfm_misc registration
|
||||
# https://github.com/multiarch/qemu-user-static#binfmt_misc-register
|
||||
ARG DOTNET_VERSION=3.1
|
||||
ARG DOTNET_VERSION=5.0
|
||||
|
||||
|
||||
FROM node:alpine as web-builder
|
||||
|
@ -14,7 +14,7 @@ RUN apk add curl git zlib zlib-dev autoconf g++ make libpng-dev gifsicle alpine-
|
|||
&& mv dist /dist
|
||||
|
||||
|
||||
FROM mcr.microsoft.com/dotnet/core/sdk:${DOTNET_VERSION} as builder
|
||||
FROM mcr.microsoft.com/dotnet/sdk:${DOTNET_VERSION} as builder
|
||||
WORKDIR /repo
|
||||
COPY . .
|
||||
ENV DOTNET_CLI_TELEMETRY_OPTOUT=1
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
</ItemGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.1</TargetFramework>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
</ItemGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.1</TargetFramework>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.1</TargetFramework>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.1</TargetFramework>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.1</TargetFramework>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
|
|
|
@ -83,7 +83,7 @@ namespace Emby.Notifications
|
|||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
private async void OnAppHostHasPendingRestartChanged(object sender, EventArgs e)
|
||||
private async void OnAppHostHasPendingRestartChanged(object? sender, EventArgs e)
|
||||
{
|
||||
var type = NotificationType.ServerRestartRequired.ToString();
|
||||
|
||||
|
@ -99,7 +99,7 @@ namespace Emby.Notifications
|
|||
await SendNotification(notification, null).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private async void OnActivityManagerEntryCreated(object sender, GenericEventArgs<ActivityLogEntry> e)
|
||||
private async void OnActivityManagerEntryCreated(object? sender, GenericEventArgs<ActivityLogEntry> e)
|
||||
{
|
||||
var entry = e.Argument;
|
||||
|
||||
|
@ -132,7 +132,7 @@ namespace Emby.Notifications
|
|||
return _config.GetConfiguration<NotificationOptions>("notifications");
|
||||
}
|
||||
|
||||
private async void OnAppHostHasUpdateAvailableChanged(object sender, EventArgs e)
|
||||
private async void OnAppHostHasUpdateAvailableChanged(object? sender, EventArgs e)
|
||||
{
|
||||
if (!_appHost.HasUpdateAvailable)
|
||||
{
|
||||
|
@ -151,7 +151,7 @@ namespace Emby.Notifications
|
|||
await SendNotification(notification, null).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private void OnLibraryManagerItemAdded(object sender, ItemChangeEventArgs e)
|
||||
private void OnLibraryManagerItemAdded(object? sender, ItemChangeEventArgs e)
|
||||
{
|
||||
if (!FilterItem(e.Item))
|
||||
{
|
||||
|
@ -197,7 +197,7 @@ namespace Emby.Notifications
|
|||
return item.SourceType == SourceType.Library;
|
||||
}
|
||||
|
||||
private async void LibraryUpdateTimerCallback(object state)
|
||||
private async void LibraryUpdateTimerCallback(object? state)
|
||||
{
|
||||
List<BaseItem> items;
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
</ItemGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.1</TargetFramework>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using MediaBrowser.Common.Extensions;
|
||||
using MediaBrowser.Model.Serialization;
|
||||
|
||||
namespace Emby.Server.Implementations.AppBase
|
||||
|
@ -35,7 +36,7 @@ namespace Emby.Server.Implementations.AppBase
|
|||
}
|
||||
catch (Exception)
|
||||
{
|
||||
configuration = Activator.CreateInstance(type);
|
||||
configuration = Activator.CreateInstance(type) ?? throw new ArgumentException($"Provided path ({type}) is not valid.", nameof(type));
|
||||
}
|
||||
|
||||
using var stream = new MemoryStream(buffer?.Length ?? 0);
|
||||
|
@ -48,8 +49,9 @@ namespace Emby.Server.Implementations.AppBase
|
|||
// If the file didn't exist before, or if something has changed, re-save
|
||||
if (buffer == null || !newBytes.AsSpan(0, newBytesLen).SequenceEqual(buffer))
|
||||
{
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(path));
|
||||
var directory = Path.GetDirectoryName(path) ?? throw new ArgumentException($"Provided path ({path}) is not valid.", nameof(path));
|
||||
|
||||
Directory.CreateDirectory(directory);
|
||||
// Save it after load in case we got new items
|
||||
using (var fs = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.Read))
|
||||
{
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Security.Cryptography;
|
||||
using MediaBrowser.Common.Extensions;
|
||||
using MediaBrowser.Model.Cryptography;
|
||||
using static MediaBrowser.Common.Cryptography.Constants;
|
||||
|
||||
|
@ -80,7 +81,7 @@ namespace Emby.Server.Implementations.Cryptography
|
|||
throw new CryptographicException($"Requested hash method is not supported: {hashMethod}");
|
||||
}
|
||||
|
||||
using var h = HashAlgorithm.Create(hashMethod);
|
||||
using var h = HashAlgorithm.Create(hashMethod) ?? throw new ResourceNotFoundException($"Unknown hash method: {hashMethod}.");
|
||||
if (salt.Length == 0)
|
||||
{
|
||||
return h.ComputeHash(bytes);
|
||||
|
|
|
@ -32,13 +32,13 @@
|
|||
<PackageReference Include="Microsoft.AspNetCore.ResponseCompression" Version="2.2.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Server.Kestrel" Version="2.2.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.WebSockets" Version="2.2.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="3.1.9" />
|
||||
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="3.1.9" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="3.1.9" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="3.1.9" />
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="5.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="5.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="5.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="5.0.0" />
|
||||
<PackageReference Include="Mono.Nat" Version="3.0.0" />
|
||||
<PackageReference Include="prometheus-net.DotNetRuntime" Version="3.4.0" />
|
||||
<PackageReference Include="ServiceStack.Text.Core" Version="5.9.2" />
|
||||
<PackageReference Include="ServiceStack.Text.Core" Version="5.10.0" />
|
||||
<PackageReference Include="sharpcompress" Version="0.26.0" />
|
||||
<PackageReference Include="SQLitePCL.pretty.netstandard" Version="2.1.0" />
|
||||
<PackageReference Include="DotNet.Glob" Version="3.1.0" />
|
||||
|
@ -49,10 +49,12 @@
|
|||
</ItemGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.1</TargetFramework>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||
<TreatWarningsAsErrors Condition=" '$(Configuration)' == 'Release'">true</TreatWarningsAsErrors>
|
||||
<!-- https://github.com/microsoft/ApplicationInsights-dotnet/issues/2047 -->
|
||||
<NoWarn>AD0001</NoWarn>
|
||||
</PropertyGroup>
|
||||
|
||||
<!-- Code Analyzers-->
|
||||
|
|
|
@ -8,6 +8,7 @@ using System.Linq;
|
|||
using System.Net.WebSockets;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using MediaBrowser.Common.Extensions;
|
||||
using MediaBrowser.Controller.Net;
|
||||
using MediaBrowser.Controller.Session;
|
||||
using MediaBrowser.Model.Net;
|
||||
|
@ -55,9 +56,9 @@ namespace Emby.Server.Implementations.Session
|
|||
connection.Closed += OnConnectionClosed;
|
||||
}
|
||||
|
||||
private void OnConnectionClosed(object sender, EventArgs e)
|
||||
private void OnConnectionClosed(object? sender, EventArgs e)
|
||||
{
|
||||
var connection = (IWebSocketConnection)sender;
|
||||
var connection = sender as IWebSocketConnection ?? throw new ArgumentException($"{nameof(sender)} is not of type {nameof(IWebSocketConnection)}", nameof(sender));
|
||||
_logger.LogDebug("Removing websocket from session {Session}", _session.Id);
|
||||
_sockets.Remove(connection);
|
||||
connection.Closed -= OnConnectionClosed;
|
||||
|
|
|
@ -14,6 +14,7 @@ using Jellyfin.Api.Helpers;
|
|||
using Jellyfin.Api.Models.PlaybackDtos;
|
||||
using Jellyfin.Api.Models.StreamingDtos;
|
||||
using MediaBrowser.Common.Configuration;
|
||||
using MediaBrowser.Common.Extensions;
|
||||
using MediaBrowser.Controller.Configuration;
|
||||
using MediaBrowser.Controller.Devices;
|
||||
using MediaBrowser.Controller.Dlna;
|
||||
|
@ -1347,7 +1348,9 @@ namespace Jellyfin.Api.Controllers
|
|||
|
||||
var mapArgs = state.IsOutputVideo ? _encodingHelper.GetMapArgs(state) : string.Empty;
|
||||
|
||||
var outputTsArg = Path.Combine(Path.GetDirectoryName(outputPath), Path.GetFileNameWithoutExtension(outputPath)) + "%d" + GetSegmentFileExtension(state.Request.SegmentContainer);
|
||||
var directory = Path.GetDirectoryName(outputPath) ?? throw new ArgumentException($"Provided path ({outputPath}) is not valid.", nameof(outputPath));
|
||||
|
||||
var outputTsArg = Path.Combine(directory, Path.GetFileNameWithoutExtension(outputPath)) + "%d" + GetSegmentFileExtension(state.Request.SegmentContainer);
|
||||
|
||||
var segmentFormat = GetSegmentFileExtension(state.Request.SegmentContainer).TrimStart('.');
|
||||
if (string.Equals(segmentFormat, "ts", StringComparison.OrdinalIgnoreCase))
|
||||
|
@ -1565,8 +1568,7 @@ namespace Jellyfin.Api.Controllers
|
|||
|
||||
private string GetSegmentPath(StreamState state, string playlist, int index)
|
||||
{
|
||||
var folder = Path.GetDirectoryName(playlist);
|
||||
|
||||
var folder = Path.GetDirectoryName(playlist) ?? throw new ArgumentException($"Provided path ({playlist}) is not valid.", nameof(playlist));
|
||||
var filename = Path.GetFileNameWithoutExtension(playlist);
|
||||
|
||||
return Path.Combine(folder, filename + index.ToString(CultureInfo.InvariantCulture) + GetSegmentFileExtension(state.Request.SegmentContainer));
|
||||
|
|
|
@ -5,6 +5,7 @@ using System.IO;
|
|||
using System.Linq;
|
||||
using Jellyfin.Api.Constants;
|
||||
using Jellyfin.Api.Models.EnvironmentDtos;
|
||||
using MediaBrowser.Common.Extensions;
|
||||
using MediaBrowser.Model.IO;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
@ -103,6 +104,11 @@ namespace Jellyfin.Api.Controllers
|
|||
|
||||
if (validatePathDto.ValidateWritable)
|
||||
{
|
||||
if (validatePathDto.Path == null)
|
||||
{
|
||||
throw new ResourceNotFoundException(nameof(validatePathDto.Path));
|
||||
}
|
||||
|
||||
var file = Path.Combine(validatePathDto.Path, Guid.NewGuid().ToString());
|
||||
try
|
||||
{
|
||||
|
|
|
@ -176,7 +176,7 @@ namespace Jellyfin.Api.Controllers
|
|||
return _dtoService.GetBaseItemDto(item, dtoOptions);
|
||||
}
|
||||
|
||||
private T GetItemFromSlugName<T>(ILibraryManager libraryManager, string name, DtoOptions dtoOptions)
|
||||
private T? GetItemFromSlugName<T>(ILibraryManager libraryManager, string name, DtoOptions dtoOptions)
|
||||
where T : BaseItem, new()
|
||||
{
|
||||
var result = libraryManager.GetItemList(new InternalItemsQuery
|
||||
|
|
|
@ -8,6 +8,7 @@ using Jellyfin.Api.Attributes;
|
|||
using Jellyfin.Api.Constants;
|
||||
using Jellyfin.Api.Helpers;
|
||||
using MediaBrowser.Common.Configuration;
|
||||
using MediaBrowser.Common.Extensions;
|
||||
using MediaBrowser.Controller.Configuration;
|
||||
using MediaBrowser.Controller.MediaEncoding;
|
||||
using MediaBrowser.Model.IO;
|
||||
|
@ -134,7 +135,8 @@ namespace Jellyfin.Api.Controllers
|
|||
var playlistPath = _fileSystem.GetFilePaths(transcodeFolderPath)
|
||||
.FirstOrDefault(i =>
|
||||
string.Equals(Path.GetExtension(i), ".m3u8", StringComparison.OrdinalIgnoreCase)
|
||||
&& i.IndexOf(normalizedPlaylistId, StringComparison.OrdinalIgnoreCase) != -1);
|
||||
&& i.IndexOf(normalizedPlaylistId, StringComparison.OrdinalIgnoreCase) != -1)
|
||||
?? throw new ResourceNotFoundException($"Provided path ({transcodeFolderPath}) is not valid.");
|
||||
|
||||
return GetFileResult(file, playlistPath);
|
||||
}
|
||||
|
|
|
@ -161,7 +161,7 @@ namespace Jellyfin.Api.Controllers
|
|||
/// <param name="theme">Theme to search.</param>
|
||||
/// <param name="name">File name to search for.</param>
|
||||
/// <returns>A <see cref="FileStreamResult"/> containing the image contents on success, or a <see cref="NotFoundResult"/> if the image could not be found.</returns>
|
||||
private ActionResult GetImageFile(string basePath, string? theme, string? name)
|
||||
private ActionResult GetImageFile(string basePath, string theme, string? name)
|
||||
{
|
||||
var themeFolder = Path.Combine(basePath, theme);
|
||||
if (Directory.Exists(themeFolder))
|
||||
|
|
|
@ -5,6 +5,7 @@ using System.Diagnostics.CodeAnalysis;
|
|||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net.Mime;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Jellyfin.Api.Attributes;
|
||||
|
@ -1268,7 +1269,7 @@ namespace Jellyfin.Api.Controllers
|
|||
Response.Headers.Add(key, value);
|
||||
}
|
||||
|
||||
Response.ContentType = imageContentType;
|
||||
Response.ContentType = imageContentType ?? MediaTypeNames.Text.Plain;
|
||||
Response.Headers.Add(HeaderNames.Age, Convert.ToInt64((DateTime.UtcNow - dateImageModified).TotalSeconds).ToString(CultureInfo.InvariantCulture));
|
||||
Response.Headers.Add(HeaderNames.Vary, HeaderNames.Accept);
|
||||
|
||||
|
|
|
@ -334,10 +334,16 @@ namespace Jellyfin.Api.Controllers
|
|||
private async Task DownloadImage(string providerName, string url, Guid urlHash, string pointerCachePath)
|
||||
{
|
||||
using var result = await _providerManager.GetSearchImage(providerName, url, CancellationToken.None).ConfigureAwait(false);
|
||||
if (result.Content.Headers.ContentType?.MediaType == null)
|
||||
{
|
||||
throw new ResourceNotFoundException(nameof(result.Content.Headers.ContentType));
|
||||
}
|
||||
|
||||
var ext = result.Content.Headers.ContentType.MediaType.Split('/')[^1];
|
||||
var fullCachePath = GetFullCachePath(urlHash + "." + ext);
|
||||
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(fullCachePath));
|
||||
var directory = Path.GetDirectoryName(fullCachePath) ?? throw new ResourceNotFoundException($"Provided path ({fullCachePath}) is not valid.");
|
||||
Directory.CreateDirectory(directory);
|
||||
using (var stream = result.Content)
|
||||
{
|
||||
await using var fileStream = new FileStream(
|
||||
|
@ -351,7 +357,9 @@ namespace Jellyfin.Api.Controllers
|
|||
await stream.CopyToAsync(fileStream).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(pointerCachePath));
|
||||
var pointerCacheDirectory = Path.GetDirectoryName(pointerCachePath) ?? throw new ArgumentException($"Provided path ({pointerCachePath}) is not valid.", nameof(pointerCachePath));
|
||||
|
||||
Directory.CreateDirectory(pointerCacheDirectory);
|
||||
await System.IO.File.WriteAllTextAsync(pointerCachePath, fullCachePath).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
|
|
|
@ -456,7 +456,7 @@ namespace Jellyfin.Api.Controllers
|
|||
: null;
|
||||
|
||||
var dtoOptions = new DtoOptions().AddClientFields(Request);
|
||||
BaseItem parent = item.GetParent();
|
||||
BaseItem? parent = item.GetParent();
|
||||
|
||||
while (parent != null)
|
||||
{
|
||||
|
@ -467,7 +467,7 @@ namespace Jellyfin.Api.Controllers
|
|||
|
||||
baseItemDtos.Add(_dtoService.GetBaseItemDto(parent, dtoOptions, user));
|
||||
|
||||
parent = parent.GetParent();
|
||||
parent = parent?.GetParent();
|
||||
}
|
||||
|
||||
return baseItemDtos;
|
||||
|
@ -893,7 +893,7 @@ namespace Jellyfin.Api.Controllers
|
|||
return _libraryManager.GetItemsResult(query).TotalRecordCount;
|
||||
}
|
||||
|
||||
private BaseItem TranslateParentItem(BaseItem item, User user)
|
||||
private BaseItem? TranslateParentItem(BaseItem item, User user)
|
||||
{
|
||||
return item.GetParent() is AggregateFolder
|
||||
? _libraryManager.GetUserRootFolder().GetChildren(user, true)
|
||||
|
|
|
@ -1073,7 +1073,7 @@ namespace Jellyfin.Api.Controllers
|
|||
var client = _httpClientFactory.CreateClient(NamedClient.Default);
|
||||
// https://json.schedulesdirect.org/20141201/available/countries
|
||||
// Can't dispose the response as it's required up the call chain.
|
||||
var response = await client.GetAsync("https://json.schedulesdirect.org/20141201/available/countries")
|
||||
var response = await client.GetAsync(new Uri("https://json.schedulesdirect.org/20141201/available/countries"))
|
||||
.ConfigureAwait(false);
|
||||
|
||||
return File(await response.Content.ReadAsStreamAsync().ConfigureAwait(false), MediaTypeNames.Application.Json);
|
||||
|
|
|
@ -139,7 +139,7 @@ namespace Jellyfin.Api.Controllers
|
|||
{
|
||||
var dtoOptions = new DtoOptions().AddClientFields(Request);
|
||||
|
||||
MusicGenre item;
|
||||
MusicGenre? item;
|
||||
|
||||
if (genreName.IndexOf(BaseItem.SlugChar, StringComparison.OrdinalIgnoreCase) != -1)
|
||||
{
|
||||
|
@ -160,7 +160,7 @@ namespace Jellyfin.Api.Controllers
|
|||
return _dtoService.GetBaseItemDto(item, dtoOptions);
|
||||
}
|
||||
|
||||
private T GetItemFromSlugName<T>(ILibraryManager libraryManager, string name, DtoOptions dtoOptions)
|
||||
private T? GetItemFromSlugName<T>(ILibraryManager libraryManager, string name, DtoOptions dtoOptions)
|
||||
where T : BaseItem, new()
|
||||
{
|
||||
var result = libraryManager.GetItemList(new InternalItemsQuery
|
||||
|
|
|
@ -54,6 +54,11 @@ namespace Jellyfin.Api.Controllers
|
|||
string.IsNullOrEmpty(assemblyGuid) ? default : Guid.Parse(assemblyGuid))
|
||||
.FirstOrDefault();
|
||||
|
||||
if (result == null)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
|
@ -157,9 +157,9 @@ namespace Jellyfin.Api.Controllers
|
|||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
[ProducesImageFile]
|
||||
public async Task<ActionResult> GetRemoteImage([FromQuery, Required] string imageUrl)
|
||||
public async Task<ActionResult> GetRemoteImage([FromQuery, Required] Uri imageUrl)
|
||||
{
|
||||
var urlHash = imageUrl.GetMD5();
|
||||
var urlHash = imageUrl.ToString().GetMD5();
|
||||
var pointerCachePath = GetFullCachePath(urlHash.ToString());
|
||||
|
||||
string? contentPath = null;
|
||||
|
@ -245,17 +245,25 @@ namespace Jellyfin.Api.Controllers
|
|||
/// <param name="urlHash">The URL hash.</param>
|
||||
/// <param name="pointerCachePath">The pointer cache path.</param>
|
||||
/// <returns>Task.</returns>
|
||||
private async Task DownloadImage(string url, Guid urlHash, string pointerCachePath)
|
||||
private async Task DownloadImage(Uri url, Guid urlHash, string pointerCachePath)
|
||||
{
|
||||
var httpClient = _httpClientFactory.CreateClient(NamedClient.Default);
|
||||
using var response = await httpClient.GetAsync(url).ConfigureAwait(false);
|
||||
if (response.Content.Headers.ContentType?.MediaType == null)
|
||||
{
|
||||
throw new ResourceNotFoundException(nameof(response.Content.Headers.ContentType));
|
||||
}
|
||||
|
||||
var ext = response.Content.Headers.ContentType.MediaType.Split('/')[^1];
|
||||
var fullCachePath = GetFullCachePath(urlHash + "." + ext);
|
||||
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(fullCachePath));
|
||||
var fullCacheDirectory = Path.GetDirectoryName(fullCachePath) ?? throw new ResourceNotFoundException($"Provided path ({fullCachePath}) is not valid.");
|
||||
Directory.CreateDirectory(fullCacheDirectory);
|
||||
await using var fileStream = new FileStream(fullCachePath, FileMode.Create, FileAccess.Write, FileShare.Read, IODefaults.FileStreamBufferSize, true);
|
||||
await response.Content.CopyToAsync(fileStream).ConfigureAwait(false);
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(pointerCachePath));
|
||||
|
||||
var pointerCacheDirectory = Path.GetDirectoryName(pointerCachePath) ?? throw new ArgumentException($"Provided path ({pointerCachePath}) is not valid.", nameof(pointerCachePath));
|
||||
Directory.CreateDirectory(pointerCacheDirectory);
|
||||
await System.IO.File.WriteAllTextAsync(pointerCachePath, fullCachePath, CancellationToken.None)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
|
|
|
@ -260,7 +260,7 @@ namespace Jellyfin.Api.Controllers
|
|||
}
|
||||
}
|
||||
|
||||
private T GetParentWithImage<T>(BaseItem item, ImageType type)
|
||||
private T? GetParentWithImage<T>(BaseItem item, ImageType type)
|
||||
where T : BaseItem
|
||||
{
|
||||
return item.GetParents().OfType<T>().FirstOrDefault(i => i.HasImage(type));
|
||||
|
|
|
@ -11,6 +11,7 @@ using Jellyfin.Api.Helpers;
|
|||
using Jellyfin.Api.Models.PlaybackDtos;
|
||||
using Jellyfin.Api.Models.StreamingDtos;
|
||||
using MediaBrowser.Common.Configuration;
|
||||
using MediaBrowser.Common.Extensions;
|
||||
using MediaBrowser.Controller.Configuration;
|
||||
using MediaBrowser.Controller.Devices;
|
||||
using MediaBrowser.Controller.Dlna;
|
||||
|
@ -361,7 +362,8 @@ namespace Jellyfin.Api.Controllers
|
|||
var threads = _encodingHelper.GetNumberOfThreads(state, _encodingOptions, videoCodec);
|
||||
var inputModifier = _encodingHelper.GetInputModifier(state, _encodingOptions);
|
||||
var format = !string.IsNullOrWhiteSpace(state.Request.SegmentContainer) ? "." + state.Request.SegmentContainer : ".ts";
|
||||
var outputTsArg = Path.Combine(Path.GetDirectoryName(outputPath), Path.GetFileNameWithoutExtension(outputPath)) + "%d" + format;
|
||||
var directory = Path.GetDirectoryName(outputPath) ?? throw new ArgumentException($"Provided path ({outputPath}) is not valid.", nameof(outputPath));
|
||||
var outputTsArg = Path.Combine(directory, Path.GetFileNameWithoutExtension(outputPath)) + "%d" + format;
|
||||
|
||||
var segmentFormat = format.TrimStart('.');
|
||||
if (string.Equals(segmentFormat, "ts", StringComparison.OrdinalIgnoreCase))
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
using System.Net.Http;
|
||||
using System;
|
||||
using System.Net.Http;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Jellyfin.Api.Models.StreamingDtos;
|
||||
using MediaBrowser.Common.Configuration;
|
||||
using MediaBrowser.Common.Extensions;
|
||||
using MediaBrowser.Common.Net;
|
||||
using MediaBrowser.Controller.Configuration;
|
||||
using MediaBrowser.Controller.Devices;
|
||||
|
@ -98,6 +100,11 @@ namespace Jellyfin.Api.Helpers
|
|||
TranscodingJobType transcodingJobType,
|
||||
StreamingRequestDto streamingRequest)
|
||||
{
|
||||
if (_httpContextAccessor.HttpContext == null)
|
||||
{
|
||||
throw new ResourceNotFoundException(nameof(_httpContextAccessor.HttpContext));
|
||||
}
|
||||
|
||||
bool isHeadRequest = _httpContextAccessor.HttpContext.Request.Method == System.Net.WebRequestMethods.Http.Head;
|
||||
var cancellationTokenSource = new CancellationTokenSource();
|
||||
|
||||
|
|
|
@ -113,7 +113,7 @@ namespace Jellyfin.Api.Helpers
|
|||
StreamingRequestDto streamingRequest,
|
||||
bool enableAdaptiveBitrateStreaming)
|
||||
{
|
||||
var isHeadRequest = _httpContextAccessor.HttpContext.Request.Method == WebRequestMethods.Http.Head;
|
||||
var isHeadRequest = _httpContextAccessor.HttpContext?.Request.Method == WebRequestMethods.Http.Head;
|
||||
var cancellationTokenSource = new CancellationTokenSource();
|
||||
return await GetMasterPlaylistInternal(
|
||||
streamingRequest,
|
||||
|
@ -130,6 +130,11 @@ namespace Jellyfin.Api.Helpers
|
|||
TranscodingJobType transcodingJobType,
|
||||
CancellationTokenSource cancellationTokenSource)
|
||||
{
|
||||
if (_httpContextAccessor.HttpContext == null)
|
||||
{
|
||||
throw new ResourceNotFoundException(nameof(_httpContextAccessor.HttpContext));
|
||||
}
|
||||
|
||||
using var state = await StreamingHelpers.GetStreamingState(
|
||||
streamingRequest,
|
||||
_httpContextAccessor.HttpContext.Request,
|
||||
|
@ -487,14 +492,14 @@ namespace Jellyfin.Api.Helpers
|
|||
|
||||
if (string.Equals(codec, "h264", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
string profile = state.GetRequestedProfiles("h264").FirstOrDefault();
|
||||
string? profile = state.GetRequestedProfiles("h264").FirstOrDefault();
|
||||
return HlsCodecStringHelpers.GetH264String(profile, level);
|
||||
}
|
||||
|
||||
if (string.Equals(codec, "h265", StringComparison.OrdinalIgnoreCase)
|
||||
|| string.Equals(codec, "hevc", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
string profile = state.GetRequestedProfiles("h265").FirstOrDefault();
|
||||
string? profile = state.GetRequestedProfiles("h265").FirstOrDefault();
|
||||
|
||||
return HlsCodecStringHelpers.GetH265String(profile, level);
|
||||
}
|
||||
|
|
|
@ -37,8 +37,8 @@ namespace Jellyfin.Api.Helpers
|
|||
}
|
||||
|
||||
// Can't dispose the response as it's required up the call chain.
|
||||
var response = await httpClient.GetAsync(state.MediaPath).ConfigureAwait(false);
|
||||
var contentType = response.Content.Headers.ContentType.ToString();
|
||||
var response = await httpClient.GetAsync(new Uri(state.MediaPath)).ConfigureAwait(false);
|
||||
var contentType = response.Content.Headers.ContentType?.ToString();
|
||||
|
||||
httpContext.Response.Headers[HeaderNames.AcceptRanges] = "none";
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@ namespace Jellyfin.Api.Helpers
|
|||
/// </summary>
|
||||
/// <param name="profile">AAC profile.</param>
|
||||
/// <returns>AAC codec string.</returns>
|
||||
public static string GetAACString(string profile)
|
||||
public static string GetAACString(string? profile)
|
||||
{
|
||||
StringBuilder result = new StringBuilder("mp4a", 9);
|
||||
|
||||
|
@ -46,7 +46,7 @@ namespace Jellyfin.Api.Helpers
|
|||
/// <param name="profile">H.264 profile.</param>
|
||||
/// <param name="level">H.264 level.</param>
|
||||
/// <returns>H.264 string.</returns>
|
||||
public static string GetH264String(string profile, int level)
|
||||
public static string GetH264String(string? profile, int level)
|
||||
{
|
||||
StringBuilder result = new StringBuilder("avc1", 11);
|
||||
|
||||
|
@ -80,7 +80,7 @@ namespace Jellyfin.Api.Helpers
|
|||
/// <param name="profile">H.265 profile.</param>
|
||||
/// <param name="level">H.265 level.</param>
|
||||
/// <returns>H.265 string.</returns>
|
||||
public static string GetH265String(string profile, int level)
|
||||
public static string GetH265String(string? profile, int level)
|
||||
{
|
||||
// The h265 syntax is a bit of a mystery at the time this comment was written.
|
||||
// This is what I've found through various sources:
|
||||
|
|
|
@ -45,6 +45,11 @@ namespace Jellyfin.Api.Helpers
|
|||
while (!reader.EndOfStream)
|
||||
{
|
||||
var line = await reader.ReadLineAsync().ConfigureAwait(false);
|
||||
if (line == null)
|
||||
{
|
||||
// Nothing currently in buffer.
|
||||
break;
|
||||
}
|
||||
|
||||
if (line.IndexOf("#EXTINF:", StringComparison.OrdinalIgnoreCase) != -1)
|
||||
{
|
||||
|
|
|
@ -5,6 +5,7 @@ using System.Runtime.InteropServices;
|
|||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Jellyfin.Api.Models.PlaybackDtos;
|
||||
using MediaBrowser.Common.Extensions;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Model.IO;
|
||||
|
||||
|
@ -90,6 +91,11 @@ namespace Jellyfin.Api.Helpers
|
|||
allowAsyncFileRead = true;
|
||||
}
|
||||
|
||||
if (_path == null)
|
||||
{
|
||||
throw new ResourceNotFoundException(nameof(_path));
|
||||
}
|
||||
|
||||
await using var inputStream = new FileStream(_path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, IODefaults.FileStreamBufferSize, fileOptions);
|
||||
|
||||
var eofCount = 0;
|
||||
|
|
|
@ -83,6 +83,10 @@ namespace Jellyfin.Api.Helpers
|
|||
}
|
||||
|
||||
streamingRequest.StreamOptions = ParseStreamOptions(httpRequest.Query);
|
||||
if (httpRequest.Path.Value == null)
|
||||
{
|
||||
throw new ResourceNotFoundException(nameof(httpRequest.Path));
|
||||
}
|
||||
|
||||
var url = httpRequest.Path.Value.Split('.')[^1];
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@ using Jellyfin.Api.Models.PlaybackDtos;
|
|||
using Jellyfin.Api.Models.StreamingDtos;
|
||||
using Jellyfin.Data.Enums;
|
||||
using MediaBrowser.Common.Configuration;
|
||||
using MediaBrowser.Common.Extensions;
|
||||
using MediaBrowser.Controller.Configuration;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.MediaEncoding;
|
||||
|
@ -102,7 +103,7 @@ namespace Jellyfin.Api.Helpers
|
|||
/// </summary>
|
||||
/// <param name="playSessionId">Playback session id.</param>
|
||||
/// <returns>The transcoding job.</returns>
|
||||
public TranscodingJobDto GetTranscodingJob(string playSessionId)
|
||||
public TranscodingJobDto? GetTranscodingJob(string playSessionId)
|
||||
{
|
||||
lock (_activeTranscodingJobs)
|
||||
{
|
||||
|
@ -116,7 +117,7 @@ namespace Jellyfin.Api.Helpers
|
|||
/// <param name="path">Path to the transcoding file.</param>
|
||||
/// <param name="type">The <see cref="TranscodingJobType"/>.</param>
|
||||
/// <returns>The transcoding job.</returns>
|
||||
public TranscodingJobDto GetTranscodingJob(string path, TranscodingJobType type)
|
||||
public TranscodingJobDto? GetTranscodingJob(string path, TranscodingJobType type)
|
||||
{
|
||||
lock (_activeTranscodingJobs)
|
||||
{
|
||||
|
@ -193,10 +194,9 @@ namespace Jellyfin.Api.Helpers
|
|||
/// Called when [transcode kill timer stopped].
|
||||
/// </summary>
|
||||
/// <param name="state">The state.</param>
|
||||
private async void OnTranscodeKillTimerStopped(object state)
|
||||
private async void OnTranscodeKillTimerStopped(object? state)
|
||||
{
|
||||
var job = (TranscodingJobDto)state;
|
||||
|
||||
var job = state as TranscodingJobDto ?? throw new ArgumentException($"{nameof(state)} is not of type {nameof(TranscodingJobDto)}", nameof(state));
|
||||
if (!job.HasExited && job.Type != TranscodingJobType.Progressive)
|
||||
{
|
||||
var timeSinceLastPing = (DateTime.UtcNow - job.LastPingDate).TotalMilliseconds;
|
||||
|
@ -489,7 +489,8 @@ namespace Jellyfin.Api.Helpers
|
|||
CancellationTokenSource cancellationTokenSource,
|
||||
string? workingDirectory = null)
|
||||
{
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(outputPath));
|
||||
var directory = Path.GetDirectoryName(outputPath) ?? throw new ArgumentException($"Provided path ({outputPath}) is not valid.", nameof(outputPath));
|
||||
Directory.CreateDirectory(directory);
|
||||
|
||||
await AcquireResources(state, cancellationTokenSource).ConfigureAwait(false);
|
||||
|
||||
|
@ -523,7 +524,7 @@ namespace Jellyfin.Api.Helpers
|
|||
RedirectStandardInput = true,
|
||||
FileName = _mediaEncoder.EncoderPath,
|
||||
Arguments = commandLineArguments,
|
||||
WorkingDirectory = string.IsNullOrWhiteSpace(workingDirectory) ? null : workingDirectory,
|
||||
WorkingDirectory = string.IsNullOrWhiteSpace(workingDirectory) ? string.Empty : workingDirectory,
|
||||
ErrorDialog = false
|
||||
},
|
||||
EnableRaisingEvents = true
|
||||
|
@ -827,7 +828,7 @@ namespace Jellyfin.Api.Helpers
|
|||
{
|
||||
lock (_transcodingLocks)
|
||||
{
|
||||
if (!_transcodingLocks.TryGetValue(outputPath, out SemaphoreSlim result))
|
||||
if (!_transcodingLocks.TryGetValue(outputPath, out SemaphoreSlim? result))
|
||||
{
|
||||
result = new SemaphoreSlim(1, 1);
|
||||
_transcodingLocks[outputPath] = result;
|
||||
|
@ -837,7 +838,7 @@ namespace Jellyfin.Api.Helpers
|
|||
}
|
||||
}
|
||||
|
||||
private void OnPlaybackProgress(object sender, PlaybackProgressEventArgs e)
|
||||
private void OnPlaybackProgress(object? sender, PlaybackProgressEventArgs e)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(e.PlaySessionId))
|
||||
{
|
||||
|
|
|
@ -6,17 +6,19 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.1</TargetFramework>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
<Nullable>enable</Nullable>
|
||||
<!-- https://github.com/microsoft/ApplicationInsights-dotnet/issues/2047 -->
|
||||
<NoWarn>AD0001</NoWarn>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.Authentication" Version="2.2.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Authorization" Version="3.1.9" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Authorization" Version="5.0.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc" Version="2.2.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Http" Version="3.1.9" />
|
||||
<PackageReference Include="Microsoft.Extensions.Http" Version="5.0.0" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="5.6.3" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore.ReDoc" Version="5.6.3" />
|
||||
</ItemGroup>
|
||||
|
|
|
@ -196,7 +196,7 @@ namespace Jellyfin.Api.Models.PlaybackDtos
|
|||
/// Start kill timer.
|
||||
/// </summary>
|
||||
/// <param name="callback">Callback action.</param>
|
||||
public void StartKillTimer(Action<object> callback)
|
||||
public void StartKillTimer(Action<object?> callback)
|
||||
{
|
||||
StartKillTimer(callback, PingTimeout);
|
||||
}
|
||||
|
@ -206,7 +206,7 @@ namespace Jellyfin.Api.Models.PlaybackDtos
|
|||
/// </summary>
|
||||
/// <param name="callback">Callback action.</param>
|
||||
/// <param name="intervalMs">Callback interval.</param>
|
||||
public void StartKillTimer(Action<object> callback, int intervalMs)
|
||||
public void StartKillTimer(Action<object?> callback, int intervalMs)
|
||||
{
|
||||
if (HasExited)
|
||||
{
|
||||
|
|
|
@ -101,7 +101,7 @@ namespace Jellyfin.Api.Models.PlaybackDtos
|
|||
return _config.GetConfiguration<EncodingOptions>("encoding");
|
||||
}
|
||||
|
||||
private async void TimerCallback(object state)
|
||||
private async void TimerCallback(object? state)
|
||||
{
|
||||
if (_job.HasExited)
|
||||
{
|
||||
|
|
|
@ -56,7 +56,7 @@ namespace Jellyfin.Api.WebSocketListeners
|
|||
base.Dispose(dispose);
|
||||
}
|
||||
|
||||
private void OnEntryCreated(object sender, GenericEventArgs<ActivityLogEntry> e)
|
||||
private void OnEntryCreated(object? sender, GenericEventArgs<ActivityLogEntry> e)
|
||||
{
|
||||
SendData(true);
|
||||
}
|
||||
|
|
|
@ -64,19 +64,19 @@ namespace Jellyfin.Api.WebSocketListeners
|
|||
base.Dispose(dispose);
|
||||
}
|
||||
|
||||
private void OnTaskCompleted(object sender, TaskCompletionEventArgs e)
|
||||
private void OnTaskCompleted(object? sender, TaskCompletionEventArgs e)
|
||||
{
|
||||
SendData(true);
|
||||
e.Task.TaskProgress -= OnTaskProgress;
|
||||
}
|
||||
|
||||
private void OnTaskExecuting(object sender, GenericEventArgs<IScheduledTaskWorker> e)
|
||||
private void OnTaskExecuting(object? sender, GenericEventArgs<IScheduledTaskWorker> e)
|
||||
{
|
||||
SendData(true);
|
||||
e.Argument.TaskProgress += OnTaskProgress;
|
||||
}
|
||||
|
||||
private void OnTaskProgress(object sender, GenericEventArgs<double> e)
|
||||
private void OnTaskProgress(object? sender, GenericEventArgs<double> e)
|
||||
{
|
||||
SendData(false);
|
||||
}
|
||||
|
|
|
@ -66,37 +66,37 @@ namespace Jellyfin.Api.WebSocketListeners
|
|||
base.Dispose(dispose);
|
||||
}
|
||||
|
||||
private async void OnSessionManagerSessionActivity(object sender, SessionEventArgs e)
|
||||
private async void OnSessionManagerSessionActivity(object? sender, SessionEventArgs e)
|
||||
{
|
||||
await SendData(false).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private async void OnSessionManagerCapabilitiesChanged(object sender, SessionEventArgs e)
|
||||
private async void OnSessionManagerCapabilitiesChanged(object? sender, SessionEventArgs e)
|
||||
{
|
||||
await SendData(true).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private async void OnSessionManagerPlaybackProgress(object sender, PlaybackProgressEventArgs e)
|
||||
private async void OnSessionManagerPlaybackProgress(object? sender, PlaybackProgressEventArgs e)
|
||||
{
|
||||
await SendData(!e.IsAutomated).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private async void OnSessionManagerPlaybackStopped(object sender, PlaybackStopEventArgs e)
|
||||
private async void OnSessionManagerPlaybackStopped(object? sender, PlaybackStopEventArgs e)
|
||||
{
|
||||
await SendData(true).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private async void OnSessionManagerPlaybackStart(object sender, PlaybackProgressEventArgs e)
|
||||
private async void OnSessionManagerPlaybackStart(object? sender, PlaybackProgressEventArgs e)
|
||||
{
|
||||
await SendData(true).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private async void OnSessionManagerSessionEnded(object sender, SessionEventArgs e)
|
||||
private async void OnSessionManagerSessionEnded(object? sender, SessionEventArgs e)
|
||||
{
|
||||
await SendData(true).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private async void OnSessionManagerSessionStarted(object sender, SessionEventArgs e)
|
||||
private async void OnSessionManagerSessionStarted(object? sender, SessionEventArgs e)
|
||||
{
|
||||
await SendData(true).ConfigureAwait(false);
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>netstandard2.0;netstandard2.1</TargetFrameworks>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
|
@ -41,8 +41,8 @@
|
|||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="3.1.9" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="3.1.9" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="5.0.0" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="5.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.1</TargetFramework>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
|
|
|
@ -4,6 +4,7 @@ using System.Globalization;
|
|||
using System.IO;
|
||||
using BlurHashSharp.SkiaSharp;
|
||||
using MediaBrowser.Common.Configuration;
|
||||
using MediaBrowser.Common.Extensions;
|
||||
using MediaBrowser.Controller.Drawing;
|
||||
using MediaBrowser.Controller.Extensions;
|
||||
using MediaBrowser.Model.Drawing;
|
||||
|
@ -227,8 +228,8 @@ namespace Jellyfin.Drawing.Skia
|
|||
}
|
||||
|
||||
var tempPath = Path.Combine(_appPaths.TempDirectory, Guid.NewGuid() + Path.GetExtension(path));
|
||||
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(tempPath));
|
||||
var directory = Path.GetDirectoryName(tempPath) ?? throw new ResourceNotFoundException($"Provided path ({tempPath}) is not valid.");
|
||||
Directory.CreateDirectory(directory);
|
||||
File.Copy(path, tempPath, true);
|
||||
|
||||
return tempPath;
|
||||
|
@ -493,7 +494,8 @@ namespace Jellyfin.Drawing.Skia
|
|||
// If all we're doing is resizing then we can stop now
|
||||
if (!hasBackgroundColor && !hasForegroundColor && blur == 0 && !hasIndicator)
|
||||
{
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(outputPath));
|
||||
var outputDirectory = Path.GetDirectoryName(outputPath) ?? throw new ArgumentException($"Provided path ({outputPath}) is not valid.", nameof(outputPath));
|
||||
Directory.CreateDirectory(outputDirectory);
|
||||
using var outputStream = new SKFileWStream(outputPath);
|
||||
using var pixmap = new SKPixmap(new SKImageInfo(width, height), resizedBitmap.GetPixels());
|
||||
resizedBitmap.Encode(outputStream, skiaOutputFormat, quality);
|
||||
|
@ -540,7 +542,8 @@ namespace Jellyfin.Drawing.Skia
|
|||
DrawIndicator(canvas, width, height, options);
|
||||
}
|
||||
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(outputPath));
|
||||
var directory = Path.GetDirectoryName(outputPath) ?? throw new ArgumentException($"Provided path ({outputPath}) is not valid.", nameof(outputPath));
|
||||
Directory.CreateDirectory(directory);
|
||||
using (var outputStream = new SKFileWStream(outputPath))
|
||||
{
|
||||
using (var pixmap = new SKPixmap(new SKImageInfo(width, height), saveBitmap.GetPixels()))
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
|
@ -24,12 +24,12 @@
|
|||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="System.Linq.Async" Version="4.1.1" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="3.1.9">
|
||||
<PackageReference Include="System.Linq.Async" Version="5.0.0" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="5.0.0">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="3.1.9">
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="5.0.0">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
|
|
|
@ -57,7 +57,8 @@ namespace Jellyfin.Server.Implementations.Users
|
|||
SerializablePasswordReset spr;
|
||||
await using (var str = File.OpenRead(resetFile))
|
||||
{
|
||||
spr = await JsonSerializer.DeserializeAsync<SerializablePasswordReset>(str).ConfigureAwait(false);
|
||||
spr = await JsonSerializer.DeserializeAsync<SerializablePasswordReset>(str).ConfigureAwait(false)
|
||||
?? throw new ResourceNotFoundException($"Provided path ({resetFile}) is not valid.");
|
||||
}
|
||||
|
||||
if (spr.ExpirationDate < DateTime.UtcNow)
|
||||
|
|
|
@ -26,22 +26,22 @@ namespace Jellyfin.Server.Filters
|
|||
if (attribute is ProducesFileAttribute producesFileAttribute)
|
||||
{
|
||||
// Get operation response values.
|
||||
var (_, value) = operation.Responses
|
||||
var response = operation.Responses
|
||||
.FirstOrDefault(o => o.Key.Equals(SuccessCode, StringComparison.Ordinal));
|
||||
|
||||
// Operation doesn't have a response.
|
||||
if (value == null)
|
||||
if (response.Value == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Clear existing responses.
|
||||
value.Content.Clear();
|
||||
response.Value.Content.Clear();
|
||||
|
||||
// Add all content-types as file.
|
||||
foreach (var contentType in producesFileAttribute.GetContentTypes())
|
||||
{
|
||||
value.Content.Add(contentType, _openApiMediaType);
|
||||
response.Value.Content.Add(contentType, _openApiMediaType);
|
||||
}
|
||||
|
||||
break;
|
||||
|
|
|
@ -30,7 +30,8 @@ namespace Jellyfin.Server.Formatters
|
|||
/// <returns>Write stream task.</returns>
|
||||
public override Task WriteResponseBodyAsync(OutputFormatterWriteContext context, Encoding selectedEncoding)
|
||||
{
|
||||
return context.HttpContext.Response.WriteAsync(context.Object?.ToString());
|
||||
var stringResponse = context.Object?.ToString();
|
||||
return stringResponse == null ? Task.CompletedTask : context.HttpContext.Response.WriteAsync(stringResponse);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,7 +26,8 @@ namespace Jellyfin.Server.Formatters
|
|||
/// <inheritdoc />
|
||||
public override Task WriteResponseBodyAsync(OutputFormatterWriteContext context, Encoding selectedEncoding)
|
||||
{
|
||||
return context.HttpContext.Response.WriteAsync(context.Object?.ToString());
|
||||
var stringResponse = context.Object?.ToString();
|
||||
return stringResponse == null ? Task.CompletedTask : context.HttpContext.Response.WriteAsync(stringResponse);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
<PropertyGroup>
|
||||
<AssemblyName>jellyfin</AssemblyName>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
|
@ -38,10 +38,10 @@
|
|||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="CommandLineParser" Version="2.8.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="3.1.9" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="3.1.9" />
|
||||
<PackageReference Include="Microsoft.Extensions.Diagnostics.HealthChecks" Version="3.1.9" />
|
||||
<PackageReference Include="Microsoft.Extensions.Diagnostics.HealthChecks.EntityFrameworkCore" Version="3.1.9" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="5.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="5.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Diagnostics.HealthChecks" Version="5.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Diagnostics.HealthChecks.EntityFrameworkCore" Version="5.0.0" />
|
||||
<PackageReference Include="prometheus-net" Version="4.0.0" />
|
||||
<PackageReference Include="prometheus-net.AspNetCore" Version="4.0.0" />
|
||||
<PackageReference Include="Serilog.AspNetCore" Version="3.4.0" />
|
||||
|
|
|
@ -18,8 +18,8 @@
|
|||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="3.1.9" />
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="3.1.9" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="5.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="5.0.0" />
|
||||
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" PrivateAssets="All"/>
|
||||
<PackageReference Include="Microsoft.Net.Http.Headers" Version="2.2.8" />
|
||||
</ItemGroup>
|
||||
|
@ -29,7 +29,7 @@
|
|||
</ItemGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.1</TargetFramework>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
|
|
|
@ -14,8 +14,8 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="3.1.9" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="3.1.9" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="5.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="5.0.0" />
|
||||
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" PrivateAssets="All"/>
|
||||
</ItemGroup>
|
||||
|
||||
|
@ -29,7 +29,7 @@
|
|||
</ItemGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.1</TargetFramework>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||
<TreatWarningsAsErrors Condition=" '$(Configuration)' == 'Release' ">true</TreatWarningsAsErrors>
|
||||
|
|
|
@ -486,7 +486,7 @@ namespace MediaBrowser.LocalMetadata.Images
|
|||
return false;
|
||||
}
|
||||
|
||||
private FileSystemMetadata GetImage(IEnumerable<FileSystemMetadata> files, string name)
|
||||
private FileSystemMetadata? GetImage(IEnumerable<FileSystemMetadata> files, string name)
|
||||
{
|
||||
return files.FirstOrDefault(i => !i.IsDirectory && string.Equals(name, _fileSystem.GetFileNameWithoutExtension(i), StringComparison.OrdinalIgnoreCase) && i.Length > 0);
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
</ItemGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.1</TargetFramework>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
|
|
|
@ -683,7 +683,7 @@ namespace MediaBrowser.LocalMetadata.Parsers
|
|||
default:
|
||||
{
|
||||
string readerName = reader.Name;
|
||||
if (_validProviderIds!.TryGetValue(readerName, out string providerIdValue))
|
||||
if (_validProviderIds!.TryGetValue(readerName, out string? providerIdValue))
|
||||
{
|
||||
var id = reader.ReadElementContentAsString();
|
||||
if (!string.IsNullOrWhiteSpace(id))
|
||||
|
|
|
@ -5,6 +5,7 @@ using System.Linq;
|
|||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Xml;
|
||||
using MediaBrowser.Common.Extensions;
|
||||
using MediaBrowser.Controller.Configuration;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Entities.Movies;
|
||||
|
@ -127,7 +128,8 @@ namespace MediaBrowser.LocalMetadata.Savers
|
|||
|
||||
private void SaveToFile(Stream stream, string path)
|
||||
{
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(path));
|
||||
var directory = Path.GetDirectoryName(path) ?? throw new ArgumentException($"Provided path ({path}) is not valid.", nameof(path));
|
||||
Directory.CreateDirectory(directory);
|
||||
// On Windows, savint the file will fail if the file is hidden or readonly
|
||||
FileSystem.SetAttributes(path, false, false);
|
||||
|
||||
|
|
|
@ -178,7 +178,7 @@ namespace MediaBrowser.MediaEncoding.Attachments
|
|||
|
||||
process.Start();
|
||||
|
||||
var ranToCompletion = await process.WaitForExitAsync(cancellationToken).ConfigureAwait(false);
|
||||
var ranToCompletion = await ProcessExtensions.WaitForExitAsync(process, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
if (!ranToCompletion)
|
||||
{
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.1</TargetFramework>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
|
@ -25,7 +25,7 @@
|
|||
<ItemGroup>
|
||||
<PackageReference Include="BDInfo" Version="0.7.6.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.Http" Version="3.1.6" />
|
||||
<PackageReference Include="System.Text.Encoding.CodePages" Version="4.7.1" />
|
||||
<PackageReference Include="System.Text.Encoding.CodePages" Version="5.0.0" />
|
||||
<PackageReference Include="UTF.Unknown" Version="2.3.0" />
|
||||
</ItemGroup>
|
||||
|
||||
|
|
|
@ -758,7 +758,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles
|
|||
case MediaProtocol.Http:
|
||||
{
|
||||
using var response = await _httpClientFactory.CreateClient(NamedClient.Default)
|
||||
.GetAsync(path, cancellationToken)
|
||||
.GetAsync(new Uri(path), cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
return await response.Content.ReadAsStreamAsync().ConfigureAwait(false);
|
||||
}
|
||||
|
|
|
@ -48,7 +48,7 @@ namespace MediaBrowser.Model.Entities
|
|||
return null;
|
||||
}
|
||||
|
||||
instance.ProviderIds.TryGetValue(name, out string id);
|
||||
instance.ProviderIds.TryGetValue(name, out string? id);
|
||||
return id;
|
||||
}
|
||||
|
||||
|
|
|
@ -22,11 +22,6 @@ namespace MediaBrowser.Model.Extensions
|
|||
return str;
|
||||
}
|
||||
|
||||
#if NETSTANDARD2_0
|
||||
char[] a = str.ToCharArray();
|
||||
a[0] = char.ToUpperInvariant(a[0]);
|
||||
return new string(a);
|
||||
#else
|
||||
return string.Create(
|
||||
str.Length,
|
||||
str,
|
||||
|
@ -38,7 +33,6 @@ namespace MediaBrowser.Model.Extensions
|
|||
chars[i] = buf[i];
|
||||
}
|
||||
});
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>netstandard2.0;netstandard2.1</TargetFrameworks>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||
<TreatWarningsAsErrors Condition=" '$(Configuration)' == 'Release' ">true</TreatWarningsAsErrors>
|
||||
|
@ -32,11 +32,11 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" PrivateAssets="All"/>
|
||||
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" PrivateAssets="All" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Http.Abstractions" Version="2.2.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="3.1.9" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="5.0.0" />
|
||||
<PackageReference Include="System.Globalization" Version="4.3.0" />
|
||||
<PackageReference Include="System.Text.Json" Version="5.0.0-preview.8.20407.11" />
|
||||
<PackageReference Include="System.Text.Json" Version="5.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
|
@ -177,7 +177,7 @@ namespace MediaBrowser.Model.Net
|
|||
|
||||
var ext = Path.GetExtension(path);
|
||||
|
||||
if (_mimeTypeLookup.TryGetValue(ext, out string result))
|
||||
if (_mimeTypeLookup.TryGetValue(ext, out string? result))
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
@ -210,9 +210,9 @@ namespace MediaBrowser.Model.Net
|
|||
return enableStreamDefault ? "application/octet-stream" : null;
|
||||
}
|
||||
|
||||
public static string? ToExtension(string mimeType)
|
||||
public static string? ToExtension(string? mimeType)
|
||||
{
|
||||
if (mimeType.Length == 0)
|
||||
if (string.IsNullOrEmpty(mimeType))
|
||||
{
|
||||
throw new ArgumentException("String can't be empty.", nameof(mimeType));
|
||||
}
|
||||
|
@ -220,7 +220,7 @@ namespace MediaBrowser.Model.Net
|
|||
// handle text/html; charset=UTF-8
|
||||
mimeType = mimeType.Split(';')[0];
|
||||
|
||||
if (_extensionLookup.TryGetValue(mimeType, out string result))
|
||||
if (_extensionLookup.TryGetValue(mimeType, out string? result))
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -16,9 +16,9 @@
|
|||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="3.1.9" />
|
||||
<PackageReference Include="Microsoft.Extensions.Caching.Abstractions" Version="3.1.9" />
|
||||
<PackageReference Include="Microsoft.Extensions.Http" Version="3.1.9" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="5.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Caching.Abstractions" Version="5.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Http" Version="5.0.0" />
|
||||
<PackageReference Include="OptimizedPriorityQueue" Version="5.0.0" />
|
||||
<PackageReference Include="PlaylistsNET" Version="1.1.2" />
|
||||
<PackageReference Include="TMDbLib" Version="1.7.3-alpha" />
|
||||
|
@ -26,7 +26,7 @@
|
|||
</ItemGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.1</TargetFramework>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||
<TreatWarningsAsErrors Condition=" '$(Configuration)' == 'Release'">true</TreatWarningsAsErrors>
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
</ItemGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.1</TargetFramework>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
|
|
|
@ -81,7 +81,7 @@ These instructions will help you get set up with a local development environment
|
|||
|
||||
### Prerequisites
|
||||
|
||||
Before the project can be built, you must first install the [.NET Core 3.1 SDK](https://dotnet.microsoft.com/download) on your system.
|
||||
Before the project can be built, you must first install the [.NET 5.0 SDK](https://dotnet.microsoft.com/download) on your system.
|
||||
|
||||
Instructions to run this project from the command line are included here, but you will also need to install an IDE if you want to debug the server while it is running. Any IDE that supports .NET Core development will work, but two options are recent versions of [Visual Studio](https://visualstudio.microsoft.com/downloads/) (at least 2017) and [Visual Studio Code](https://code.visualstudio.com/Download).
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
</ItemGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.1</TargetFramework>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
</PropertyGroup>
|
||||
|
|
|
@ -16,7 +16,7 @@ RUN apt-get update \
|
|||
|
||||
# Install dotnet repository
|
||||
# https://dotnet.microsoft.com/download/linux-package-manager/debian9/sdk-current
|
||||
RUN wget https://download.visualstudio.microsoft.com/download/pr/fdd9ecec-56b4-40f4-b762-d7efe24fc3cd/ffef51844c92afa6714528e10609a30f/dotnet-sdk-3.1.403-linux-x64.tar.gz -O dotnet-sdk.tar.gz \
|
||||
RUN wget https://download.visualstudio.microsoft.com/download/pr/820db713-c9a5-466e-b72a-16f2f5ed00e2/628aa2a75f6aa270e77f4a83b3742fb8/dotnet-sdk-5.0.100-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
|
||||
|
|
|
@ -16,7 +16,7 @@ RUN apt-get update \
|
|||
|
||||
# Install dotnet repository
|
||||
# https://dotnet.microsoft.com/download/linux-package-manager/debian9/sdk-current
|
||||
RUN wget https://download.visualstudio.microsoft.com/download/pr/fdd9ecec-56b4-40f4-b762-d7efe24fc3cd/ffef51844c92afa6714528e10609a30f/dotnet-sdk-3.1.403-linux-x64.tar.gz -O dotnet-sdk.tar.gz \
|
||||
RUN wget https://download.visualstudio.microsoft.com/download/pr/820db713-c9a5-466e-b72a-16f2f5ed00e2/628aa2a75f6aa270e77f4a83b3742fb8/dotnet-sdk-5.0.100-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
|
||||
|
|
|
@ -16,7 +16,7 @@ RUN apt-get update \
|
|||
|
||||
# Install dotnet repository
|
||||
# https://dotnet.microsoft.com/download/linux-package-manager/debian9/sdk-current
|
||||
RUN wget https://download.visualstudio.microsoft.com/download/pr/fdd9ecec-56b4-40f4-b762-d7efe24fc3cd/ffef51844c92afa6714528e10609a30f/dotnet-sdk-3.1.403-linux-x64.tar.gz -O dotnet-sdk.tar.gz \
|
||||
RUN wget https://download.visualstudio.microsoft.com/download/pr/820db713-c9a5-466e-b72a-16f2f5ed00e2/628aa2a75f6aa270e77f4a83b3742fb8/dotnet-sdk-5.0.100-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
|
||||
|
|
|
@ -16,7 +16,7 @@ RUN apt-get update \
|
|||
|
||||
# Install dotnet repository
|
||||
# https://dotnet.microsoft.com/download/linux-package-manager/debian9/sdk-current
|
||||
RUN wget https://download.visualstudio.microsoft.com/download/pr/fdd9ecec-56b4-40f4-b762-d7efe24fc3cd/ffef51844c92afa6714528e10609a30f/dotnet-sdk-3.1.403-linux-x64.tar.gz -O dotnet-sdk.tar.gz \
|
||||
RUN wget https://download.visualstudio.microsoft.com/download/pr/820db713-c9a5-466e-b72a-16f2f5ed00e2/628aa2a75f6aa270e77f4a83b3742fb8/dotnet-sdk-5.0.100-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
|
||||
|
|
|
@ -16,7 +16,7 @@ RUN apt-get update \
|
|||
|
||||
# Install dotnet repository
|
||||
# https://dotnet.microsoft.com/download/linux-package-manager/debian9/sdk-current
|
||||
RUN wget https://download.visualstudio.microsoft.com/download/pr/fdd9ecec-56b4-40f4-b762-d7efe24fc3cd/ffef51844c92afa6714528e10609a30f/dotnet-sdk-3.1.403-linux-x64.tar.gz -O dotnet-sdk.tar.gz \
|
||||
RUN wget https://download.visualstudio.microsoft.com/download/pr/820db713-c9a5-466e-b72a-16f2f5ed00e2/628aa2a75f6aa270e77f4a83b3742fb8/dotnet-sdk-5.0.100-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
|
||||
|
|
|
@ -15,7 +15,7 @@ RUN apt-get update \
|
|||
|
||||
# Install dotnet repository
|
||||
# https://dotnet.microsoft.com/download/linux-package-manager/debian9/sdk-current
|
||||
RUN wget https://download.visualstudio.microsoft.com/download/pr/fdd9ecec-56b4-40f4-b762-d7efe24fc3cd/ffef51844c92afa6714528e10609a30f/dotnet-sdk-3.1.403-linux-x64.tar.gz -O dotnet-sdk.tar.gz \
|
||||
RUN wget https://download.visualstudio.microsoft.com/download/pr/820db713-c9a5-466e-b72a-16f2f5ed00e2/628aa2a75f6aa270e77f4a83b3742fb8/dotnet-sdk-5.0.100-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
|
||||
|
|
|
@ -16,7 +16,7 @@ RUN apt-get update \
|
|||
|
||||
# Install dotnet repository
|
||||
# https://dotnet.microsoft.com/download/linux-package-manager/debian9/sdk-current
|
||||
RUN wget https://download.visualstudio.microsoft.com/download/pr/fdd9ecec-56b4-40f4-b762-d7efe24fc3cd/ffef51844c92afa6714528e10609a30f/dotnet-sdk-3.1.403-linux-x64.tar.gz -O dotnet-sdk.tar.gz \
|
||||
RUN wget https://download.visualstudio.microsoft.com/download/pr/820db713-c9a5-466e-b72a-16f2f5ed00e2/628aa2a75f6aa270e77f4a83b3742fb8/dotnet-sdk-5.0.100-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
|
||||
|
|
|
@ -16,7 +16,7 @@ RUN apt-get update \
|
|||
|
||||
# Install dotnet repository
|
||||
# https://dotnet.microsoft.com/download/linux-package-manager/debian9/sdk-current
|
||||
RUN wget https://download.visualstudio.microsoft.com/download/pr/fdd9ecec-56b4-40f4-b762-d7efe24fc3cd/ffef51844c92afa6714528e10609a30f/dotnet-sdk-3.1.403-linux-x64.tar.gz -O dotnet-sdk.tar.gz \
|
||||
RUN wget https://download.visualstudio.microsoft.com/download/pr/820db713-c9a5-466e-b72a-16f2f5ed00e2/628aa2a75f6aa270e77f4a83b3742fb8/dotnet-sdk-5.0.100-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
|
||||
|
|
|
@ -16,7 +16,7 @@ RUN apt-get update \
|
|||
|
||||
# Install dotnet repository
|
||||
# https://dotnet.microsoft.com/download/linux-package-manager/debian9/sdk-current
|
||||
RUN wget https://download.visualstudio.microsoft.com/download/pr/fdd9ecec-56b4-40f4-b762-d7efe24fc3cd/ffef51844c92afa6714528e10609a30f/dotnet-sdk-3.1.403-linux-x64.tar.gz -O dotnet-sdk.tar.gz \
|
||||
RUN wget https://download.visualstudio.microsoft.com/download/pr/820db713-c9a5-466e-b72a-16f2f5ed00e2/628aa2a75f6aa270e77f4a83b3742fb8/dotnet-sdk-5.0.100-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
|
||||
|
|
|
@ -15,7 +15,7 @@ RUN apt-get update \
|
|||
|
||||
# Install dotnet repository
|
||||
# https://dotnet.microsoft.com/download/linux-package-manager/debian9/sdk-current
|
||||
RUN wget https://download.visualstudio.microsoft.com/download/pr/fdd9ecec-56b4-40f4-b762-d7efe24fc3cd/ffef51844c92afa6714528e10609a30f/dotnet-sdk-3.1.403-linux-x64.tar.gz -O dotnet-sdk.tar.gz \
|
||||
RUN wget https://download.visualstudio.microsoft.com/download/pr/820db713-c9a5-466e-b72a-16f2f5ed00e2/628aa2a75f6aa270e77f4a83b3742fb8/dotnet-sdk-5.0.100-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
|
||||
|
|
|
@ -81,7 +81,7 @@ namespace Jellyfin.Api.Tests.Auth
|
|||
var authenticateResult = await _sut.AuthenticateAsync();
|
||||
|
||||
Assert.False(authenticateResult.Succeeded);
|
||||
Assert.Equal(errorMessage, authenticateResult.Failure.Message);
|
||||
Assert.Equal(errorMessage, authenticateResult.Failure?.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
@ -100,7 +100,7 @@ namespace Jellyfin.Api.Tests.Auth
|
|||
var authorizationInfo = SetupUser();
|
||||
var authenticateResult = await _sut.AuthenticateAsync();
|
||||
|
||||
Assert.True(authenticateResult.Principal.HasClaim(ClaimTypes.Name, authorizationInfo.User.Username));
|
||||
Assert.True(authenticateResult.Principal?.HasClaim(ClaimTypes.Name, authorizationInfo.User.Username));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
|
@ -112,7 +112,7 @@ namespace Jellyfin.Api.Tests.Auth
|
|||
var authenticateResult = await _sut.AuthenticateAsync();
|
||||
|
||||
var expectedRole = authorizationInfo.User.HasPermission(PermissionKind.IsAdministrator) ? UserRoles.Administrator : UserRoles.User;
|
||||
Assert.True(authenticateResult.Principal.HasClaim(ClaimTypes.Role, expectedRole));
|
||||
Assert.True(authenticateResult.Principal?.HasClaim(ClaimTypes.Role, expectedRole));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
@ -121,7 +121,7 @@ namespace Jellyfin.Api.Tests.Auth
|
|||
SetupUser();
|
||||
var authenticatedResult = await _sut.AuthenticateAsync();
|
||||
|
||||
Assert.Equal(_scheme.Name, authenticatedResult.Ticket.AuthenticationScheme);
|
||||
Assert.Equal(_scheme.Name, authenticatedResult.Ticket?.AuthenticationScheme);
|
||||
}
|
||||
|
||||
private AuthorizationInfo SetupUser(bool isAdmin = false)
|
||||
|
|
|
@ -25,7 +25,7 @@ namespace Jellyfin.Api.Tests
|
|||
|
||||
// Assert
|
||||
response.EnsureSuccessStatusCode();
|
||||
Assert.Equal("application/json; charset=utf-8", response.Content.Headers.ContentType.ToString());
|
||||
Assert.Equal("application/json; charset=utf-8", response.Content.Headers.ContentType?.ToString());
|
||||
var responseBody = await response.Content.ReadAsStreamAsync();
|
||||
_ = await JsonSerializer.DeserializeAsync<BrandingOptions>(responseBody);
|
||||
}
|
||||
|
@ -43,7 +43,7 @@ namespace Jellyfin.Api.Tests
|
|||
|
||||
// Assert
|
||||
response.EnsureSuccessStatusCode();
|
||||
Assert.Equal("text/css; charset=utf-8", response.Content.Headers.ContentType.ToString());
|
||||
Assert.Equal("text/css; charset=utf-8", response.Content.Headers.ContentType?.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<IsPackable>false</IsPackable>
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
<Nullable>enable</Nullable>
|
||||
|
@ -16,8 +16,8 @@
|
|||
<PackageReference Include="AutoFixture" Version="4.14.0" />
|
||||
<PackageReference Include="AutoFixture.AutoMoq" Version="4.14.0" />
|
||||
<PackageReference Include="AutoFixture.Xunit2" Version="4.14.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="3.1.9" />
|
||||
<PackageReference Include="Microsoft.Extensions.Options" Version="3.1.9" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="5.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Options" Version="5.0.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.8.0" />
|
||||
<PackageReference Include="xunit" Version="2.4.1" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3" />
|
||||
|
|
|
@ -18,7 +18,7 @@ namespace Jellyfin.Api.Tests.ModelBinders
|
|||
public async Task BindModelAsync_CorrectlyBindsValidCommaDelimitedStringArrayQuery()
|
||||
{
|
||||
var queryParamName = "test";
|
||||
var queryParamValues = new[] { "lol", "xd" };
|
||||
IReadOnlyList<string> queryParamValues = new[] { "lol", "xd" };
|
||||
var queryParamString = "lol,xd";
|
||||
var queryParamType = typeof(string[]);
|
||||
|
||||
|
@ -36,14 +36,14 @@ namespace Jellyfin.Api.Tests.ModelBinders
|
|||
await modelBinder.BindModelAsync(bindingContextMock.Object);
|
||||
|
||||
Assert.True(bindingContextMock.Object.Result.IsModelSet);
|
||||
Assert.Equal((string[])bindingContextMock.Object.Result.Model, queryParamValues);
|
||||
Assert.Equal((IReadOnlyList<string>?)bindingContextMock.Object?.Result.Model, queryParamValues);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task BindModelAsync_CorrectlyBindsValidCommaDelimitedIntArrayQuery()
|
||||
{
|
||||
var queryParamName = "test";
|
||||
var queryParamValues = new[] { 42, 0 };
|
||||
IReadOnlyList<int> queryParamValues = new[] { 42, 0 };
|
||||
var queryParamString = "42,0";
|
||||
var queryParamType = typeof(int[]);
|
||||
|
||||
|
@ -61,14 +61,14 @@ namespace Jellyfin.Api.Tests.ModelBinders
|
|||
await modelBinder.BindModelAsync(bindingContextMock.Object);
|
||||
|
||||
Assert.True(bindingContextMock.Object.Result.IsModelSet);
|
||||
Assert.Equal((int[])bindingContextMock.Object.Result.Model, queryParamValues);
|
||||
Assert.Equal((IReadOnlyList<int>?)bindingContextMock.Object.Result.Model, queryParamValues);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task BindModelAsync_CorrectlyBindsValidCommaDelimitedEnumArrayQuery()
|
||||
{
|
||||
var queryParamName = "test";
|
||||
var queryParamValues = new[] { TestType.How, TestType.Much };
|
||||
IReadOnlyList<TestType> queryParamValues = new[] { TestType.How, TestType.Much };
|
||||
var queryParamString = "How,Much";
|
||||
var queryParamType = typeof(TestType[]);
|
||||
|
||||
|
@ -86,14 +86,14 @@ namespace Jellyfin.Api.Tests.ModelBinders
|
|||
await modelBinder.BindModelAsync(bindingContextMock.Object);
|
||||
|
||||
Assert.True(bindingContextMock.Object.Result.IsModelSet);
|
||||
Assert.Equal((TestType[])bindingContextMock.Object.Result.Model, queryParamValues);
|
||||
Assert.Equal((IReadOnlyList<TestType>?)bindingContextMock.Object.Result.Model, queryParamValues);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task BindModelAsync_CorrectlyBindsValidCommaDelimitedEnumArrayQueryWithDoubleCommas()
|
||||
{
|
||||
var queryParamName = "test";
|
||||
var queryParamValues = new[] { TestType.How, TestType.Much };
|
||||
IReadOnlyList<TestType> queryParamValues = new[] { TestType.How, TestType.Much };
|
||||
var queryParamString = "How,,Much";
|
||||
var queryParamType = typeof(TestType[]);
|
||||
|
||||
|
@ -111,14 +111,14 @@ namespace Jellyfin.Api.Tests.ModelBinders
|
|||
await modelBinder.BindModelAsync(bindingContextMock.Object);
|
||||
|
||||
Assert.True(bindingContextMock.Object.Result.IsModelSet);
|
||||
Assert.Equal((TestType[])bindingContextMock.Object.Result.Model, queryParamValues);
|
||||
Assert.Equal((IReadOnlyList<TestType>?)bindingContextMock.Object.Result.Model, queryParamValues);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task BindModelAsync_CorrectlyBindsValidEnumArrayQuery()
|
||||
{
|
||||
var queryParamName = "test";
|
||||
var queryParamValues = new[] { TestType.How, TestType.Much };
|
||||
IReadOnlyList<TestType> queryParamValues = new[] { TestType.How, TestType.Much };
|
||||
var queryParamString1 = "How";
|
||||
var queryParamString2 = "Much";
|
||||
var queryParamType = typeof(TestType[]);
|
||||
|
@ -141,14 +141,14 @@ namespace Jellyfin.Api.Tests.ModelBinders
|
|||
await modelBinder.BindModelAsync(bindingContextMock.Object);
|
||||
|
||||
Assert.True(bindingContextMock.Object.Result.IsModelSet);
|
||||
Assert.Equal((TestType[])bindingContextMock.Object.Result.Model, queryParamValues);
|
||||
Assert.Equal((IReadOnlyList<TestType>?)bindingContextMock.Object.Result.Model, queryParamValues);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task BindModelAsync_CorrectlyBindsEmptyEnumArrayQuery()
|
||||
{
|
||||
var queryParamName = "test";
|
||||
var queryParamValues = Array.Empty<TestType>();
|
||||
IReadOnlyList<TestType> queryParamValues = Array.Empty<TestType>();
|
||||
var queryParamType = typeof(TestType[]);
|
||||
|
||||
var modelBinder = new CommaDelimitedArrayModelBinder(new NullLogger<CommaDelimitedArrayModelBinder>());
|
||||
|
@ -169,7 +169,7 @@ namespace Jellyfin.Api.Tests.ModelBinders
|
|||
await modelBinder.BindModelAsync(bindingContextMock.Object);
|
||||
|
||||
Assert.True(bindingContextMock.Object.Result.IsModelSet);
|
||||
Assert.Equal((TestType[])bindingContextMock.Object.Result.Model, queryParamValues);
|
||||
Assert.Equal((IReadOnlyList<TestType>?)bindingContextMock.Object.Result.Model, queryParamValues);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
@ -177,7 +177,7 @@ namespace Jellyfin.Api.Tests.ModelBinders
|
|||
{
|
||||
var queryParamName = "test";
|
||||
var queryParamString = "🔥,😢";
|
||||
var queryParamType = typeof(TestType[]);
|
||||
var queryParamType = typeof(IReadOnlyList<TestType>);
|
||||
|
||||
var modelBinder = new CommaDelimitedArrayModelBinder(new NullLogger<CommaDelimitedArrayModelBinder>());
|
||||
var valueProvider = new QueryStringValueProvider(
|
||||
|
@ -192,7 +192,7 @@ namespace Jellyfin.Api.Tests.ModelBinders
|
|||
|
||||
await modelBinder.BindModelAsync(bindingContextMock.Object);
|
||||
Assert.True(bindingContextMock.Object.Result.IsModelSet);
|
||||
Assert.Empty((TestType[])bindingContextMock.Object.Result.Model);
|
||||
Assert.Empty((IReadOnlyList<TestType>?)bindingContextMock.Object.Result.Model);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
@ -201,7 +201,7 @@ namespace Jellyfin.Api.Tests.ModelBinders
|
|||
var queryParamName = "test";
|
||||
var queryParamString1 = "How";
|
||||
var queryParamString2 = "😱";
|
||||
var queryParamType = typeof(TestType[]);
|
||||
var queryParamType = typeof(IReadOnlyList<TestType>);
|
||||
|
||||
var modelBinder = new CommaDelimitedArrayModelBinder(new NullLogger<CommaDelimitedArrayModelBinder>());
|
||||
|
||||
|
@ -220,7 +220,7 @@ namespace Jellyfin.Api.Tests.ModelBinders
|
|||
|
||||
await modelBinder.BindModelAsync(bindingContextMock.Object);
|
||||
Assert.True(bindingContextMock.Object.Result.IsModelSet);
|
||||
Assert.Single((TestType[])bindingContextMock.Object.Result.Model);
|
||||
Assert.Single((IReadOnlyList<TestType>?)bindingContextMock.Object.Result.Model);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,7 +30,7 @@ namespace Jellyfin.Api.Tests
|
|||
|
||||
// Assert
|
||||
response.EnsureSuccessStatusCode();
|
||||
Assert.Equal("application/json; charset=utf-8", response.Content.Headers.ContentType.ToString());
|
||||
Assert.Equal("application/json; charset=utf-8", response.Content.Headers.ContentType?.ToString());
|
||||
|
||||
// Write out for publishing
|
||||
var responseBody = await response.Content.ReadAsStringAsync();
|
||||
|
|
|
@ -60,7 +60,7 @@ namespace Jellyfin.Api.Tests
|
|||
.Returns(user);
|
||||
|
||||
httpContextAccessorMock
|
||||
.Setup(h => h.HttpContext.Connection.RemoteIpAddress)
|
||||
.Setup(h => h.HttpContext!.Connection.RemoteIpAddress)
|
||||
.Returns(new IPAddress(0));
|
||||
|
||||
return new ClaimsPrincipal(identity);
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<IsPackable>false</IsPackable>
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
<Nullable>enable</Nullable>
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<IsPackable>false</IsPackable>
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
<Nullable>enable</Nullable>
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<IsPackable>false</IsPackable>
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
<Nullable>enable</Nullable>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<IsPackable>false</IsPackable>
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
<Nullable>enable</Nullable>
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<IsPackable>false</IsPackable>
|
||||
<Nullable>enable</Nullable>
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<IsPackable>false</IsPackable>
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
<Nullable>enable</Nullable>
|
||||
|
|
Loading…
Reference in a new issue