mirror of
				https://github.com/jellyfin/jellyfin.git
				synced 2025-10-31 10:37:22 -04:00 
			
		
		
		
	Merge branch 'master' into keyframe_extraction_v1
This commit is contained in:
		
						commit
						30f3be1da0
					
				| @ -7,7 +7,7 @@ parameters: | ||||
|   default: "ubuntu-latest" | ||||
| - name: DotNetSdkVersion | ||||
|   type: string | ||||
|   default: 5.0.302 | ||||
|   default: 6.0.x | ||||
| 
 | ||||
| jobs: | ||||
|   - job: CompatibilityCheck | ||||
| @ -34,6 +34,7 @@ jobs: | ||||
|         inputs: | ||||
|           packageType: sdk | ||||
|           version: ${{ parameters.DotNetSdkVersion }} | ||||
|           includePreviewVersions: true | ||||
| 
 | ||||
|       - task: DotNetCoreCLI@2 | ||||
|         displayName: 'Install ABI CompatibilityChecker Tool' | ||||
|  | ||||
| @ -1,7 +1,7 @@ | ||||
| parameters: | ||||
|   LinuxImage: 'ubuntu-latest' | ||||
|   RestoreBuildProjects: 'Jellyfin.Server/Jellyfin.Server.csproj' | ||||
|   DotNetSdkVersion: 5.0.302 | ||||
|   DotNetSdkVersion: 6.0.x | ||||
| 
 | ||||
| jobs: | ||||
|   - job: Build | ||||
| @ -54,6 +54,7 @@ jobs: | ||||
|         inputs: | ||||
|           packageType: sdk | ||||
|           version: ${{ parameters.DotNetSdkVersion }} | ||||
|           includePreviewVersions: true | ||||
| 
 | ||||
|       - task: DotNetCoreCLI@2 | ||||
|         displayName: 'Publish Server' | ||||
|  | ||||
| @ -195,10 +195,11 @@ jobs: | ||||
| 
 | ||||
|   steps: | ||||
|   - task: UseDotNet@2 | ||||
|     displayName: 'Use .NET 5.0 sdk' | ||||
|     displayName: 'Use .NET 6.0 sdk' | ||||
|     inputs: | ||||
|       packageType: 'sdk' | ||||
|       version: '5.0.x' | ||||
|       version: '6.0.x' | ||||
|       includePreviewVersions: true | ||||
| 
 | ||||
|   - task: DotNetCoreCLI@2 | ||||
|     displayName: 'Build Stable Nuget packages' | ||||
|  | ||||
| @ -10,7 +10,7 @@ parameters: | ||||
|   default: "tests/**/*Tests.csproj" | ||||
| - name: DotNetSdkVersion | ||||
|   type: string | ||||
|   default: 5.0.302 | ||||
|   default: 6.0.x | ||||
| 
 | ||||
| jobs: | ||||
|   - job: Test | ||||
| @ -41,6 +41,7 @@ jobs: | ||||
|         inputs: | ||||
|           packageType: sdk | ||||
|           version: ${{ parameters.DotNetSdkVersion }} | ||||
|           includePreviewVersions: true | ||||
| 
 | ||||
|       - task: SonarCloudPrepare@1 | ||||
|         displayName: 'Prepare analysis on SonarCloud' | ||||
| @ -94,5 +95,5 @@ jobs: | ||||
|         displayName: 'Publish OpenAPI Artifact' | ||||
|         condition: and(succeeded(), eq(variables['Agent.OS'], 'Linux')) | ||||
|         inputs: | ||||
|           targetPath: "tests/Jellyfin.Server.Integration.Tests/bin/Release/net5.0/openapi.json" | ||||
|           targetPath: "tests/Jellyfin.Server.Integration.Tests/bin/Release/net6.0/openapi.json" | ||||
|           artifactName: 'OpenAPI Spec' | ||||
|  | ||||
| @ -5,8 +5,6 @@ variables: | ||||
|   value: 'tests/**/*Tests.csproj' | ||||
| - name: RestoreBuildProjects | ||||
|   value: 'Jellyfin.Server/Jellyfin.Server.csproj' | ||||
| - name: DotNetSdkVersion | ||||
|   value: 5.0.302 | ||||
| 
 | ||||
| pr: | ||||
|   autoCancel: true | ||||
|  | ||||
							
								
								
									
										4
									
								
								.github/workflows/codeql-analysis.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								.github/workflows/codeql-analysis.yml
									
									
									
									
										vendored
									
									
								
							| @ -24,7 +24,9 @@ jobs: | ||||
|     - name: Setup .NET Core | ||||
|       uses: actions/setup-dotnet@v1 | ||||
|       with: | ||||
|         dotnet-version: '5.0.x' | ||||
|         dotnet-version: '6.0.x' | ||||
|         include-prerelease: true | ||||
|          | ||||
|     - name: Initialize CodeQL | ||||
|       uses: github/codeql-action/init@v1 | ||||
|       with: | ||||
|  | ||||
| @ -2,7 +2,7 @@ | ||||
| ##################################### | ||||
| # Requires binfm_misc registration | ||||
| # https://github.com/multiarch/qemu-user-static#binfmt_misc-register | ||||
| ARG DOTNET_VERSION=5.0 | ||||
| ARG DOTNET_VERSION=6.0 | ||||
| 
 | ||||
| FROM node:lts-alpine as web-builder | ||||
| ARG JELLYFIN_WEB_VERSION=master | ||||
|  | ||||
| @ -2,7 +2,7 @@ | ||||
| ##################################### | ||||
| # Requires binfm_misc registration | ||||
| # https://github.com/multiarch/qemu-user-static#binfmt_misc-register | ||||
| ARG DOTNET_VERSION=5.0 | ||||
| ARG DOTNET_VERSION=6.0 | ||||
| 
 | ||||
| 
 | ||||
| FROM node:lts-alpine as web-builder | ||||
|  | ||||
| @ -2,7 +2,7 @@ | ||||
| ##################################### | ||||
| # Requires binfm_misc registration | ||||
| # https://github.com/multiarch/qemu-user-static#binfmt_misc-register | ||||
| ARG DOTNET_VERSION=5.0 | ||||
| ARG DOTNET_VERSION=6.0 | ||||
| 
 | ||||
| 
 | ||||
| FROM node:lts-alpine as web-builder | ||||
|  | ||||
| @ -10,7 +10,7 @@ | ||||
|   </ItemGroup> | ||||
| 
 | ||||
|   <PropertyGroup> | ||||
|     <TargetFramework>net5.0</TargetFramework> | ||||
|     <TargetFramework>net6.0</TargetFramework> | ||||
|     <GenerateAssemblyInfo>false</GenerateAssemblyInfo> | ||||
|     <GenerateDocumentationFile>true</GenerateDocumentationFile> | ||||
|     <AnalysisMode>AllDisabledByDefault</AnalysisMode> | ||||
|  | ||||
| @ -2,6 +2,7 @@ | ||||
| 
 | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Globalization; | ||||
| using System.IO; | ||||
| using System.Linq; | ||||
| 
 | ||||
| @ -76,7 +77,7 @@ namespace DvdLib.Ifo | ||||
| 
 | ||||
|         private void ReadVTS(ushort vtsNum, IReadOnlyList<FileInfo> allFiles) | ||||
|         { | ||||
|             var filename = string.Format("VTS_{0:00}_0.IFO", vtsNum); | ||||
|             var filename = string.Format(CultureInfo.InvariantCulture, "VTS_{0:00}_0.IFO", vtsNum); | ||||
| 
 | ||||
|             var vtsPath = allFiles.FirstOrDefault(i => string.Equals(i.Name, filename, StringComparison.OrdinalIgnoreCase)) ?? | ||||
|                 allFiles.FirstOrDefault(i => string.Equals(i.Name, Path.ChangeExtension(filename, ".bup"), StringComparison.OrdinalIgnoreCase)); | ||||
|  | ||||
| @ -366,7 +366,7 @@ namespace Emby.Dlna | ||||
|                         Directory.CreateDirectory(systemProfilesPath); | ||||
| 
 | ||||
|                         // use FileShare.None as this bypasses dotnet bug dotnet/runtime#42790 . | ||||
|                         using (var fileStream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.None, IODefaults.FileStreamBufferSize, AsyncFile.UseAsyncIO)) | ||||
|                         using (var fileStream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.None, IODefaults.FileStreamBufferSize, FileOptions.Asynchronous)) | ||||
|                         { | ||||
|                             await stream.CopyToAsync(fileStream).ConfigureAwait(false); | ||||
|                         } | ||||
| @ -486,18 +486,22 @@ namespace Emby.Dlna | ||||
|         } | ||||
| 
 | ||||
|         /// <inheritdoc /> | ||||
|         public ImageStream GetIcon(string filename) | ||||
|         public ImageStream? GetIcon(string filename) | ||||
|         { | ||||
|             var format = filename.EndsWith(".png", StringComparison.OrdinalIgnoreCase) | ||||
|                 ? ImageFormat.Png | ||||
|                 : ImageFormat.Jpg; | ||||
| 
 | ||||
|             var resource = GetType().Namespace + ".Images." + filename.ToLowerInvariant(); | ||||
| 
 | ||||
|             return new ImageStream | ||||
|             var stream = _assembly.GetManifestResourceStream(resource); | ||||
|             if (stream == null) | ||||
|             { | ||||
|                 Format = format, | ||||
|                 Stream = _assembly.GetManifestResourceStream(resource) | ||||
|                 return null; | ||||
|             } | ||||
| 
 | ||||
|             return new ImageStream(stream) | ||||
|             { | ||||
|                 Format = format | ||||
|             }; | ||||
|         } | ||||
| 
 | ||||
|  | ||||
| @ -17,7 +17,7 @@ | ||||
|   </ItemGroup> | ||||
| 
 | ||||
|   <PropertyGroup> | ||||
|     <TargetFramework>net5.0</TargetFramework> | ||||
|     <TargetFramework>net6.0</TargetFramework> | ||||
|     <GenerateAssemblyInfo>false</GenerateAssemblyInfo> | ||||
|     <GenerateDocumentationFile>true</GenerateDocumentationFile> | ||||
|     <AnalysisMode>AllDisabledByDefault</AnalysisMode> | ||||
|  | ||||
| @ -250,8 +250,7 @@ namespace Emby.Dlna.Server | ||||
| 
 | ||||
|             url = _serverAddress.TrimEnd('/') + "/dlna/" + _serverUdn + "/" + url.TrimStart('/'); | ||||
| 
 | ||||
|             // TODO: @bond remove null-coalescing operator when https://github.com/dotnet/runtime/pull/52442 is merged/released | ||||
|             return SecurityElement.Escape(url) ?? string.Empty; | ||||
|             return SecurityElement.Escape(url); | ||||
|         } | ||||
| 
 | ||||
|         private IEnumerable<DeviceIcon> GetIcons() | ||||
|  | ||||
| @ -23,14 +23,14 @@ namespace Emby.Dlna.Service | ||||
|             return EventManager.CancelEventSubscription(subscriptionId); | ||||
|         } | ||||
| 
 | ||||
|         public EventSubscriptionResponse RenewEventSubscription(string subscriptionId, string notificationType, string timeoutString, string callbackUrl) | ||||
|         public EventSubscriptionResponse RenewEventSubscription(string subscriptionId, string notificationType, string requestedTimeoutString, string callbackUrl) | ||||
|         { | ||||
|             return EventManager.RenewEventSubscription(subscriptionId, notificationType, timeoutString, callbackUrl); | ||||
|             return EventManager.RenewEventSubscription(subscriptionId, notificationType, requestedTimeoutString, callbackUrl); | ||||
|         } | ||||
| 
 | ||||
|         public EventSubscriptionResponse CreateEventSubscription(string notificationType, string timeoutString, string callbackUrl) | ||||
|         public EventSubscriptionResponse CreateEventSubscription(string notificationType, string requestedTimeoutString, string callbackUrl) | ||||
|         { | ||||
|             return EventManager.CreateEventSubscription(notificationType, timeoutString, callbackUrl); | ||||
|             return EventManager.CreateEventSubscription(notificationType, requestedTimeoutString, callbackUrl); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -6,7 +6,7 @@ | ||||
|   </PropertyGroup> | ||||
| 
 | ||||
|   <PropertyGroup> | ||||
|     <TargetFramework>net5.0</TargetFramework> | ||||
|     <TargetFramework>net6.0</TargetFramework> | ||||
|     <GenerateAssemblyInfo>false</GenerateAssemblyInfo> | ||||
|     <GenerateDocumentationFile>true</GenerateDocumentationFile> | ||||
|     <AnalysisMode>AllDisabledByDefault</AnalysisMode> | ||||
|  | ||||
| @ -102,7 +102,7 @@ namespace Emby.Drawing | ||||
|         { | ||||
|             var file = await ProcessImage(options).ConfigureAwait(false); | ||||
| 
 | ||||
|             using (var fileStream = new FileStream(file.Item1, FileMode.Open, FileAccess.Read, FileShare.Read, IODefaults.FileStreamBufferSize, AsyncFile.UseAsyncIO)) | ||||
|             using (var fileStream = new FileStream(file.Item1, FileMode.Open, FileAccess.Read, FileShare.Read, IODefaults.FileStreamBufferSize, FileOptions.Asynchronous)) | ||||
|             { | ||||
|                 await fileStream.CopyToAsync(toStream).ConfigureAwait(false); | ||||
|             } | ||||
|  | ||||
| @ -6,7 +6,7 @@ | ||||
|   </PropertyGroup> | ||||
| 
 | ||||
|   <PropertyGroup> | ||||
|     <TargetFramework>net5.0</TargetFramework> | ||||
|     <TargetFramework>net6.0</TargetFramework> | ||||
|     <GenerateAssemblyInfo>false</GenerateAssemblyInfo> | ||||
|     <GenerateDocumentationFile>true</GenerateDocumentationFile> | ||||
|     <PublishRepositoryUrl>true</PublishRepositoryUrl> | ||||
|  | ||||
| @ -6,7 +6,7 @@ | ||||
|   </PropertyGroup> | ||||
| 
 | ||||
|   <PropertyGroup> | ||||
|     <TargetFramework>net5.0</TargetFramework> | ||||
|     <TargetFramework>net6.0</TargetFramework> | ||||
|     <GenerateAssemblyInfo>false</GenerateAssemblyInfo> | ||||
|     <GenerateDocumentationFile>true</GenerateDocumentationFile> | ||||
|   </PropertyGroup> | ||||
|  | ||||
| @ -19,7 +19,7 @@ | ||||
|   </ItemGroup> | ||||
| 
 | ||||
|   <PropertyGroup> | ||||
|     <TargetFramework>net5.0</TargetFramework> | ||||
|     <TargetFramework>net6.0</TargetFramework> | ||||
|     <GenerateAssemblyInfo>false</GenerateAssemblyInfo> | ||||
|     <GenerateDocumentationFile>true</GenerateDocumentationFile> | ||||
|   </PropertyGroup> | ||||
|  | ||||
| @ -1150,7 +1150,7 @@ namespace Emby.Server.Implementations.Data | ||||
|                 return null; | ||||
|             } | ||||
| 
 | ||||
|             if (Enum.TryParse(imageType.ToString(), true, out ImageType type)) | ||||
|             if (Enum.TryParse(imageType, true, out ImageType type)) | ||||
|             { | ||||
|                 image.Type = type; | ||||
|             } | ||||
| @ -1571,7 +1571,6 @@ namespace Emby.Server.Implementations.Data | ||||
| 
 | ||||
|             if (reader.TryGetString(index++, out var audioString)) | ||||
|             { | ||||
|                 // TODO Span overload coming in the future https://github.com/dotnet/runtime/issues/1916 | ||||
|                 if (Enum.TryParse(audioString, true, out ProgramAudio audio)) | ||||
|                 { | ||||
|                     item.Audio = audio; | ||||
| @ -1610,18 +1609,16 @@ namespace Emby.Server.Implementations.Data | ||||
|             { | ||||
|                 if (reader.TryGetString(index++, out var lockedFields)) | ||||
|                 { | ||||
|                     IEnumerable<MetadataField> GetLockedFields(string s) | ||||
|                     List<MetadataField> fields = null; | ||||
|                     foreach (var i in lockedFields.AsSpan().Split('|')) | ||||
|                     { | ||||
|                         foreach (var i in s.Split('|', StringSplitOptions.RemoveEmptyEntries)) | ||||
|                         if (Enum.TryParse(i, true, out MetadataField parsedValue)) | ||||
|                         { | ||||
|                             if (Enum.TryParse(i, true, out MetadataField parsedValue)) | ||||
|                             { | ||||
|                                 yield return parsedValue; | ||||
|                             } | ||||
|                             (fields ??= new List<MetadataField>()).Add(parsedValue); | ||||
|                         } | ||||
|                     } | ||||
| 
 | ||||
|                     item.LockedFields = GetLockedFields(lockedFields).ToArray(); | ||||
|                     item.LockedFields = fields?.ToArray() ?? Array.Empty<MetadataField>(); | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
| @ -1647,18 +1644,16 @@ namespace Emby.Server.Implementations.Data | ||||
|                 { | ||||
|                     if (reader.TryGetString(index, out var trailerTypes)) | ||||
|                     { | ||||
|                         IEnumerable<TrailerType> GetTrailerTypes(string s) | ||||
|                         List<TrailerType> types = null; | ||||
|                         foreach (var i in trailerTypes.AsSpan().Split('|')) | ||||
|                         { | ||||
|                             foreach (var i in s.Split('|', StringSplitOptions.RemoveEmptyEntries)) | ||||
|                             if (Enum.TryParse(i, true, out TrailerType parsedValue)) | ||||
|                             { | ||||
|                                 if (Enum.TryParse(i, true, out TrailerType parsedValue)) | ||||
|                                 { | ||||
|                                     yield return parsedValue; | ||||
|                                 } | ||||
|                                 (types ??= new List<TrailerType>()).Add(parsedValue); | ||||
|                             } | ||||
|                         } | ||||
| 
 | ||||
|                         trailer.TrailerTypes = GetTrailerTypes(trailerTypes).ToArray(); | ||||
|                         trailer.TrailerTypes = types?.ToArray() ?? Array.Empty<TrailerType>(); | ||||
|                     } | ||||
|                 } | ||||
| 
 | ||||
|  | ||||
| @ -42,7 +42,7 @@ | ||||
|   </ItemGroup> | ||||
| 
 | ||||
|   <PropertyGroup> | ||||
|     <TargetFramework>net5.0</TargetFramework> | ||||
|     <TargetFramework>net6.0</TargetFramework> | ||||
|     <GenerateAssemblyInfo>false</GenerateAssemblyInfo> | ||||
|     <GenerateDocumentationFile>true</GenerateDocumentationFile> | ||||
|     <!-- https://github.com/microsoft/ApplicationInsights-dotnet/issues/2047 --> | ||||
|  | ||||
| @ -246,9 +246,9 @@ namespace Emby.Server.Implementations.IO | ||||
|                     { | ||||
|                         try | ||||
|                         { | ||||
|                             using (Stream thisFileStream = new FileStream(fileInfo.FullName, FileMode.Open, FileAccess.Read, FileShare.Read, 1)) | ||||
|                             using (var fileHandle = File.OpenHandle(fileInfo.FullName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) | ||||
|                             { | ||||
|                                 result.Length = thisFileStream.Length; | ||||
|                                 result.Length = RandomAccess.GetLength(fileHandle); | ||||
|                             } | ||||
|                         } | ||||
|                         catch (FileNotFoundException ex) | ||||
|  | ||||
| @ -1250,10 +1250,8 @@ namespace Emby.Server.Implementations.Library | ||||
|         private CollectionTypeOptions? GetCollectionType(string path) | ||||
|         { | ||||
|             var files = _fileSystem.GetFilePaths(path, new[] { ".collection" }, true, false); | ||||
|             foreach (var file in files) | ||||
|             foreach (ReadOnlySpan<char> file in files) | ||||
|             { | ||||
|                 // TODO: @bond use a ReadOnlySpan<char> here when Enum.TryParse supports it | ||||
|                 // https://github.com/dotnet/runtime/issues/20008 | ||||
|                 if (Enum.TryParse<CollectionTypeOptions>(Path.GetFileNameWithoutExtension(file), true, out var res)) | ||||
|                 { | ||||
|                     return res; | ||||
|  | ||||
| @ -10,9 +10,9 @@ using System.Linq; | ||||
| using System.Text.Json; | ||||
| using System.Threading; | ||||
| using System.Threading.Tasks; | ||||
| using Jellyfin.Extensions.Json; | ||||
| using MediaBrowser.Common.Configuration; | ||||
| using MediaBrowser.Common.Extensions; | ||||
| using Jellyfin.Extensions.Json; | ||||
| using MediaBrowser.Controller.MediaEncoding; | ||||
| using MediaBrowser.Model.Dlna; | ||||
| using MediaBrowser.Model.Dto; | ||||
|  | ||||
| @ -47,7 +47,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV | ||||
|             Directory.CreateDirectory(Path.GetDirectoryName(targetFile) ?? throw new ArgumentException("Path can't be a root directory.", nameof(targetFile))); | ||||
| 
 | ||||
|             // use FileShare.None as this bypasses dotnet bug dotnet/runtime#42790 . | ||||
|             using (var output = new FileStream(targetFile, FileMode.Create, FileAccess.Write, FileShare.None, IODefaults.FileStreamBufferSize, AsyncFile.UseAsyncIO)) | ||||
|             using (var output = new FileStream(targetFile, FileMode.Create, FileAccess.Write, FileShare.None, IODefaults.FileStreamBufferSize, FileOptions.Asynchronous)) | ||||
|             { | ||||
|                 onStarted(); | ||||
| 
 | ||||
| @ -80,7 +80,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV | ||||
|             Directory.CreateDirectory(Path.GetDirectoryName(targetFile) ?? throw new ArgumentException("Path can't be a root directory.", nameof(targetFile))); | ||||
| 
 | ||||
|             // use FileShare.None as this bypasses dotnet bug dotnet/runtime#42790 . | ||||
|             await using var output = new FileStream(targetFile, FileMode.Create, FileAccess.Write, FileShare.None, IODefaults.CopyToBufferSize, AsyncFile.UseAsyncIO); | ||||
|             await using var output = new FileStream(targetFile, FileMode.Create, FileAccess.Write, FileShare.None, IODefaults.CopyToBufferSize, FileOptions.Asynchronous); | ||||
| 
 | ||||
|             onStarted(); | ||||
| 
 | ||||
|  | ||||
| @ -94,7 +94,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV | ||||
|             Directory.CreateDirectory(Path.GetDirectoryName(logFilePath)); | ||||
| 
 | ||||
|             // FFMpeg writes debug/error info to stderr. This is useful when debugging so let's put it in the log directory. | ||||
|             _logFileStream = new FileStream(logFilePath, FileMode.Create, FileAccess.Write, FileShare.Read, IODefaults.FileStreamBufferSize, AsyncFile.UseAsyncIO); | ||||
|             _logFileStream = new FileStream(logFilePath, FileMode.Create, FileAccess.Write, FileShare.Read, IODefaults.FileStreamBufferSize, FileOptions.Asynchronous); | ||||
| 
 | ||||
|             await JsonSerializer.SerializeAsync(_logFileStream, mediaSource, _jsonOptions, cancellationToken).ConfigureAwait(false); | ||||
|             await _logFileStream.WriteAsync(Encoding.UTF8.GetBytes(Environment.NewLine + Environment.NewLine + commandLineLogMessage + Environment.NewLine + Environment.NewLine), cancellationToken).ConfigureAwait(false); | ||||
|  | ||||
| @ -82,7 +82,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings | ||||
| 
 | ||||
|             using var response = await _httpClientFactory.CreateClient(NamedClient.Default).GetAsync(path, cancellationToken).ConfigureAwait(false); | ||||
|             await using var stream = await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false); | ||||
|             await using (var fileStream = new FileStream(cacheFile, FileMode.CreateNew, FileAccess.Write, FileShare.None, IODefaults.CopyToBufferSize, AsyncFile.UseAsyncIO)) | ||||
|             await using (var fileStream = new FileStream(cacheFile, FileMode.CreateNew, FileAccess.Write, FileShare.None, IODefaults.CopyToBufferSize, FileOptions.Asynchronous)) | ||||
|             { | ||||
|                 await stream.CopyToAsync(fileStream, cancellationToken).ConfigureAwait(false); | ||||
|             } | ||||
|  | ||||
| @ -23,10 +23,6 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts | ||||
| { | ||||
|     public abstract class BaseTunerHost | ||||
|     { | ||||
|         protected readonly IServerConfigurationManager Config; | ||||
|         protected readonly ILogger<BaseTunerHost> Logger; | ||||
|         protected readonly IFileSystem FileSystem; | ||||
| 
 | ||||
|         private readonly IMemoryCache _memoryCache; | ||||
| 
 | ||||
|         protected BaseTunerHost(IServerConfigurationManager config, ILogger<BaseTunerHost> logger, IFileSystem fileSystem, IMemoryCache memoryCache) | ||||
| @ -37,12 +33,20 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts | ||||
|             FileSystem = fileSystem; | ||||
|         } | ||||
| 
 | ||||
|         protected IServerConfigurationManager Config { get; } | ||||
| 
 | ||||
|         protected ILogger<BaseTunerHost> Logger { get; } | ||||
| 
 | ||||
|         protected IFileSystem FileSystem { get; } | ||||
| 
 | ||||
|         public virtual bool IsSupported => true; | ||||
| 
 | ||||
|         protected abstract Task<List<ChannelInfo>> GetChannelsInternal(TunerHostInfo tuner, CancellationToken cancellationToken); | ||||
| 
 | ||||
|         public abstract string Type { get; } | ||||
| 
 | ||||
|         protected virtual string ChannelIdPrefix => Type + "_"; | ||||
| 
 | ||||
|         protected abstract Task<List<ChannelInfo>> GetChannelsInternal(TunerHostInfo tuner, CancellationToken cancellationToken); | ||||
| 
 | ||||
|         public async Task<List<ChannelInfo>> GetChannels(TunerHostInfo tuner, bool enableCache, CancellationToken cancellationToken) | ||||
|         { | ||||
|             var key = tuner.Id; | ||||
| @ -217,8 +221,6 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts | ||||
|             throw new LiveTvConflictException(); | ||||
|         } | ||||
| 
 | ||||
|         protected virtual string ChannelIdPrefix => Type + "_"; | ||||
| 
 | ||||
|         protected virtual bool IsValidChannelId(string channelId) | ||||
|         { | ||||
|             if (string.IsNullOrEmpty(channelId)) | ||||
|  | ||||
| @ -101,7 +101,8 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             if (localAddress.IsIPv4MappedToIPv6) { | ||||
|             if (localAddress.IsIPv4MappedToIPv6) | ||||
|             { | ||||
|                 localAddress = localAddress.MapToIPv4(); | ||||
|             } | ||||
| 
 | ||||
| @ -196,7 +197,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun | ||||
|                         cancellationToken, | ||||
|                         timeOutSource.Token)) | ||||
|                     { | ||||
|                         var resTask = udpClient.ReceiveAsync(); | ||||
|                         var resTask = udpClient.ReceiveAsync(linkedSource.Token).AsTask(); | ||||
|                         if (await Task.WhenAny(resTask, Task.Delay(30000, linkedSource.Token)).ConfigureAwait(false) != resTask) | ||||
|                         { | ||||
|                             resTask.Dispose(); | ||||
|  | ||||
| @ -20,14 +20,6 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts | ||||
|     { | ||||
|         private readonly IConfigurationManager _configurationManager; | ||||
| 
 | ||||
|         protected readonly IFileSystem FileSystem; | ||||
| 
 | ||||
|         protected readonly IStreamHelper StreamHelper; | ||||
| 
 | ||||
|         protected string TempFilePath; | ||||
|         protected readonly ILogger Logger; | ||||
|         protected readonly CancellationTokenSource LiveStreamCancellationTokenSource = new CancellationTokenSource(); | ||||
| 
 | ||||
|         public LiveStream( | ||||
|             MediaSourceInfo mediaSource, | ||||
|             TunerHostInfo tuner, | ||||
| @ -55,7 +47,15 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts | ||||
|             SetTempFilePath("ts"); | ||||
|         } | ||||
| 
 | ||||
|         protected virtual int EmptyReadLimit => 1000; | ||||
|         protected IFileSystem FileSystem { get; } | ||||
| 
 | ||||
|         protected IStreamHelper StreamHelper { get; } | ||||
| 
 | ||||
|         protected ILogger Logger { get; } | ||||
| 
 | ||||
|         protected CancellationTokenSource LiveStreamCancellationTokenSource { get; } = new CancellationTokenSource(); | ||||
| 
 | ||||
|         protected string TempFilePath { get; set; } | ||||
| 
 | ||||
|         public MediaSourceInfo OriginalMediaSource { get; set; } | ||||
| 
 | ||||
| @ -97,7 +97,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts | ||||
| 
 | ||||
|         public Stream GetStream() | ||||
|         { | ||||
|             var stream = GetInputStream(TempFilePath, AsyncFile.UseAsyncIO); | ||||
|             var stream = GetInputStream(TempFilePath); | ||||
|             bool seekFile = (DateTime.UtcNow - DateOpened).TotalSeconds > 10; | ||||
|             if (seekFile) | ||||
|             { | ||||
| @ -107,14 +107,14 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts | ||||
|             return stream; | ||||
|         } | ||||
| 
 | ||||
|         protected FileStream GetInputStream(string path, bool allowAsyncFileRead) | ||||
|         protected FileStream GetInputStream(string path) | ||||
|             => new FileStream( | ||||
|                 path, | ||||
|                 FileMode.Open, | ||||
|                 FileAccess.Read, | ||||
|                 FileShare.ReadWrite, | ||||
|                 IODefaults.FileStreamBufferSize, | ||||
|                 allowAsyncFileRead ? FileOptions.SequentialScan | FileOptions.Asynchronous : FileOptions.SequentialScan); | ||||
|                 FileOptions.SequentialScan | FileOptions.Asynchronous); | ||||
| 
 | ||||
|         protected async Task DeleteTempFiles(string path, int retryCount = 0) | ||||
|         { | ||||
|  | ||||
| @ -118,7 +118,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts | ||||
|                         Logger.LogInformation("Beginning {StreamType} stream to {FilePath}", GetType().Name, TempFilePath); | ||||
|                         using var message = response; | ||||
|                         await using var stream = await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false); | ||||
|                         await using var fileStream = new FileStream(TempFilePath, FileMode.Create, FileAccess.Write, FileShare.Read, IODefaults.FileStreamBufferSize, AsyncFile.UseAsyncIO); | ||||
|                         await using var fileStream = new FileStream(TempFilePath, FileMode.Create, FileAccess.Write, FileShare.Read, IODefaults.FileStreamBufferSize, FileOptions.Asynchronous); | ||||
|                         await StreamHelper.CopyToAsync( | ||||
|                             stream, | ||||
|                             fileStream, | ||||
|  | ||||
| @ -1,5 +1,5 @@ | ||||
| { | ||||
|     "Albums": "البومات", | ||||
|     "Albums": "ألبومات", | ||||
|     "AppDeviceValues": "تطبيق: {0}, جهاز: {1}", | ||||
|     "Application": "تطبيق", | ||||
|     "Artists": "الفنانين", | ||||
| @ -8,7 +8,7 @@ | ||||
|     "CameraImageUploadedFrom": "صورة كاميرا جديدة تم رفعها من {0}", | ||||
|     "Channels": "القنوات", | ||||
|     "ChapterNameValue": "الفصل {0}", | ||||
|     "Collections": "مجموعات", | ||||
|     "Collections": "التجميعات", | ||||
|     "DeviceOfflineWithName": "قُطِع الاتصال ب{0}", | ||||
|     "DeviceOnlineWithName": "{0} متصل", | ||||
|     "FailedLoginAttemptWithUserName": "عملية تسجيل الدخول فشلت من {0}", | ||||
|  | ||||
| @ -15,7 +15,7 @@ | ||||
|     "Favorites": "Favoriti", | ||||
|     "Folders": "Mape", | ||||
|     "Genres": "Žanrovi", | ||||
|     "HeaderAlbumArtists": "Izvođači na albumu", | ||||
|     "HeaderAlbumArtists": "Album od izvođača", | ||||
|     "HeaderContinueWatching": "Nastavi gledati", | ||||
|     "HeaderFavoriteAlbums": "Omiljeni albumi", | ||||
|     "HeaderFavoriteArtists": "Omiljeni izvođači", | ||||
|  | ||||
| @ -17,6 +17,15 @@ namespace Emby.Server.Implementations.Playlists | ||||
|             Name = "Playlists"; | ||||
|         } | ||||
| 
 | ||||
|         [JsonIgnore] | ||||
|         public override bool IsHidden => true; | ||||
| 
 | ||||
|         [JsonIgnore] | ||||
|         public override bool SupportsInheritedParentImages => false; | ||||
| 
 | ||||
|         [JsonIgnore] | ||||
|         public override string CollectionType => MediaBrowser.Model.Entities.CollectionType.Playlists; | ||||
| 
 | ||||
|         public override bool IsVisible(User user) | ||||
|         { | ||||
|             return base.IsVisible(user) && GetChildren(user, true).Any(); | ||||
| @ -27,15 +36,6 @@ namespace Emby.Server.Implementations.Playlists | ||||
|             return base.GetEligibleChildrenForRecursiveChildren(user).OfType<Playlist>(); | ||||
|         } | ||||
| 
 | ||||
|         [JsonIgnore] | ||||
|         public override bool IsHidden => true; | ||||
| 
 | ||||
|         [JsonIgnore] | ||||
|         public override bool SupportsInheritedParentImages => false; | ||||
| 
 | ||||
|         [JsonIgnore] | ||||
|         public override string CollectionType => MediaBrowser.Model.Entities.CollectionType.Playlists; | ||||
| 
 | ||||
|         protected override QueryResult<BaseItem> GetItemsInternal(InternalItemsQuery query) | ||||
|         { | ||||
|             if (query.User == null) | ||||
|  | ||||
| @ -8,10 +8,10 @@ using System.Reflection; | ||||
| using System.Text; | ||||
| using System.Text.Json; | ||||
| using System.Threading.Tasks; | ||||
| using MediaBrowser.Common; | ||||
| using MediaBrowser.Common.Extensions; | ||||
| using Jellyfin.Extensions.Json; | ||||
| using Jellyfin.Extensions.Json.Converters; | ||||
| using MediaBrowser.Common; | ||||
| using MediaBrowser.Common.Extensions; | ||||
| using MediaBrowser.Common.Net; | ||||
| using MediaBrowser.Common.Plugins; | ||||
| using MediaBrowser.Model.Configuration; | ||||
| @ -39,14 +39,6 @@ namespace Emby.Server.Implementations.Plugins | ||||
| 
 | ||||
|         private IHttpClientFactory? _httpClientFactory; | ||||
| 
 | ||||
|         private IHttpClientFactory HttpClientFactory | ||||
|         { | ||||
|             get | ||||
|             { | ||||
|                 return _httpClientFactory ?? (_httpClientFactory = _appHost.Resolve<IHttpClientFactory>()); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// Initializes a new instance of the <see cref="PluginManager"/> class. | ||||
|         /// </summary> | ||||
| @ -86,6 +78,14 @@ namespace Emby.Server.Implementations.Plugins | ||||
|             _plugins = Directory.Exists(_pluginsPath) ? DiscoverPlugins().ToList() : new List<LocalPlugin>(); | ||||
|         } | ||||
| 
 | ||||
|         private IHttpClientFactory HttpClientFactory | ||||
|         { | ||||
|             get | ||||
|             { | ||||
|                 return _httpClientFactory ??= _appHost.Resolve<IHttpClientFactory>(); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// Gets the Plugins. | ||||
|         /// </summary> | ||||
|  | ||||
| @ -18,7 +18,7 @@ namespace Emby.Server.Implementations.QuickConnect | ||||
|     /// <summary> | ||||
|     /// Quick connect implementation. | ||||
|     /// </summary> | ||||
|     public class QuickConnectManager : IQuickConnect, IDisposable | ||||
|     public class QuickConnectManager : IQuickConnect | ||||
|     { | ||||
|         /// <summary> | ||||
|         /// The length of user facing codes. | ||||
| @ -30,7 +30,6 @@ namespace Emby.Server.Implementations.QuickConnect | ||||
|         /// </summary> | ||||
|         private const int Timeout = 10; | ||||
| 
 | ||||
|         private readonly RNGCryptoServiceProvider _rng = new (); | ||||
|         private readonly ConcurrentDictionary<string, QuickConnectResult> _currentRequests = new (); | ||||
|         private readonly ConcurrentDictionary<string, (DateTime Timestamp, AuthenticationResult AuthenticationResult)> _authorizedSecrets = new (); | ||||
| 
 | ||||
| @ -140,7 +139,7 @@ namespace Emby.Server.Implementations.QuickConnect | ||||
|             uint scale = uint.MaxValue; | ||||
|             while (scale == uint.MaxValue) | ||||
|             { | ||||
|                 _rng.GetBytes(raw); | ||||
|                 RandomNumberGenerator.Fill(raw); | ||||
|                 scale = BitConverter.ToUInt32(raw); | ||||
|             } | ||||
| 
 | ||||
| @ -199,31 +198,10 @@ namespace Emby.Server.Implementations.QuickConnect | ||||
|             return result.AuthenticationResult; | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// Dispose. | ||||
|         /// </summary> | ||||
|         public void Dispose() | ||||
|         { | ||||
|             Dispose(true); | ||||
|             GC.SuppressFinalize(this); | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// Dispose. | ||||
|         /// </summary> | ||||
|         /// <param name="disposing">Dispose unmanaged resources.</param> | ||||
|         protected virtual void Dispose(bool disposing) | ||||
|         { | ||||
|             if (disposing) | ||||
|             { | ||||
|                 _rng.Dispose(); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         private string GenerateSecureRandom(int length = 32) | ||||
|         { | ||||
|             Span<byte> bytes = stackalloc byte[length]; | ||||
|             _rng.GetBytes(bytes); | ||||
|             RandomNumberGenerator.Fill(bytes); | ||||
| 
 | ||||
|             return Convert.ToHexString(bytes); | ||||
|         } | ||||
|  | ||||
| @ -32,18 +32,18 @@ namespace Jellyfin.Api.Auth.FirstTimeSetupOrDefaultPolicy | ||||
|         } | ||||
| 
 | ||||
|         /// <inheritdoc /> | ||||
|         protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, FirstTimeSetupOrDefaultRequirement firstTimeSetupOrDefaultRequirement) | ||||
|         protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, FirstTimeSetupOrDefaultRequirement requirement) | ||||
|         { | ||||
|             if (!_configurationManager.CommonConfiguration.IsStartupWizardCompleted) | ||||
|             { | ||||
|                 context.Succeed(firstTimeSetupOrDefaultRequirement); | ||||
|                 context.Succeed(requirement); | ||||
|                 return Task.CompletedTask; | ||||
|             } | ||||
| 
 | ||||
|             var validated = ValidateClaims(context.User); | ||||
|             if (validated) | ||||
|             { | ||||
|                 context.Succeed(firstTimeSetupOrDefaultRequirement); | ||||
|                 context.Succeed(requirement); | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|  | ||||
| @ -33,18 +33,18 @@ namespace Jellyfin.Api.Auth.FirstTimeSetupOrElevatedPolicy | ||||
|         } | ||||
| 
 | ||||
|         /// <inheritdoc /> | ||||
|         protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, FirstTimeSetupOrElevatedRequirement firstTimeSetupOrElevatedRequirement) | ||||
|         protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, FirstTimeSetupOrElevatedRequirement requirement) | ||||
|         { | ||||
|             if (!_configurationManager.CommonConfiguration.IsStartupWizardCompleted) | ||||
|             { | ||||
|                 context.Succeed(firstTimeSetupOrElevatedRequirement); | ||||
|                 context.Succeed(requirement); | ||||
|                 return Task.CompletedTask; | ||||
|             } | ||||
| 
 | ||||
|             var validated = ValidateClaims(context.User); | ||||
|             if (validated && context.User.IsInRole(UserRoles.Administrator)) | ||||
|             { | ||||
|                 context.Succeed(firstTimeSetupOrElevatedRequirement); | ||||
|                 context.Succeed(requirement); | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|  | ||||
| @ -106,7 +106,7 @@ namespace Jellyfin.Api.Controllers | ||||
|             await using var memoryStream = await GetMemoryStream(Request.Body).ConfigureAwait(false); | ||||
| 
 | ||||
|             // Handle image/png; charset=utf-8 | ||||
|             var mimeType = Request.ContentType.Split(';').FirstOrDefault(); | ||||
|             var mimeType = Request.ContentType?.Split(';').FirstOrDefault(); | ||||
|             var userDataPath = Path.Combine(_serverConfigurationManager.ApplicationPaths.UserConfigurationDirectoryPath, user.Username); | ||||
|             if (user.ProfileImage != null) | ||||
|             { | ||||
| @ -153,7 +153,7 @@ namespace Jellyfin.Api.Controllers | ||||
|             await using var memoryStream = await GetMemoryStream(Request.Body).ConfigureAwait(false); | ||||
| 
 | ||||
|             // Handle image/png; charset=utf-8 | ||||
|             var mimeType = Request.ContentType.Split(';').FirstOrDefault(); | ||||
|             var mimeType = Request.ContentType?.Split(';').FirstOrDefault(); | ||||
|             var userDataPath = Path.Combine(_serverConfigurationManager.ApplicationPaths.UserConfigurationDirectoryPath, user.Username); | ||||
|             if (user.ProfileImage != null) | ||||
|             { | ||||
| @ -341,7 +341,7 @@ namespace Jellyfin.Api.Controllers | ||||
|             await using var memoryStream = await GetMemoryStream(Request.Body).ConfigureAwait(false); | ||||
| 
 | ||||
|             // Handle image/png; charset=utf-8 | ||||
|             var mimeType = Request.ContentType.Split(';').FirstOrDefault(); | ||||
|             var mimeType = Request.ContentType?.Split(';').FirstOrDefault(); | ||||
|             await _providerManager.SaveImage(item, memoryStream, mimeType, imageType, null, CancellationToken.None).ConfigureAwait(false); | ||||
|             await item.UpdateToRepositoryAsync(ItemUpdateType.ImageUpdate, CancellationToken.None).ConfigureAwait(false); | ||||
| 
 | ||||
| @ -377,7 +377,7 @@ namespace Jellyfin.Api.Controllers | ||||
|             await using var memoryStream = await GetMemoryStream(Request.Body).ConfigureAwait(false); | ||||
| 
 | ||||
|             // Handle image/png; charset=utf-8 | ||||
|             var mimeType = Request.ContentType.Split(';').FirstOrDefault(); | ||||
|             var mimeType = Request.ContentType?.Split(';').FirstOrDefault(); | ||||
|             await _providerManager.SaveImage(item, memoryStream, mimeType, imageType, null, CancellationToken.None).ConfigureAwait(false); | ||||
|             await item.UpdateToRepositoryAsync(ItemUpdateType.ImageUpdate, CancellationToken.None).ConfigureAwait(false); | ||||
| 
 | ||||
| @ -2026,7 +2026,7 @@ namespace Jellyfin.Api.Controllers | ||||
|                 return NoContent(); | ||||
|             } | ||||
| 
 | ||||
|             return PhysicalFile(imagePath, imageContentType); | ||||
|             return PhysicalFile(imagePath, imageContentType ?? MediaTypeNames.Text.Plain); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -206,7 +206,7 @@ namespace Jellyfin.Api.Controllers | ||||
|             var fullCacheDirectory = Path.GetDirectoryName(fullCachePath) ?? throw new ResourceNotFoundException($"Provided path ({fullCachePath}) is not valid."); | ||||
|             Directory.CreateDirectory(fullCacheDirectory); | ||||
|             // use FileShare.None as this bypasses dotnet bug dotnet/runtime#42790 . | ||||
|             await using var fileStream = new FileStream(fullCachePath, FileMode.Create, FileAccess.Write, FileShare.None, IODefaults.FileStreamBufferSize, AsyncFile.UseAsyncIO); | ||||
|             await using var fileStream = new FileStream(fullCachePath, FileMode.Create, FileAccess.Write, FileShare.None, IODefaults.FileStreamBufferSize, FileOptions.Asynchronous); | ||||
|             await response.Content.CopyToAsync(fileStream).ConfigureAwait(false); | ||||
| 
 | ||||
|             var pointerCacheDirectory = Path.GetDirectoryName(pointerCachePath) ?? throw new ArgumentException($"Provided path ({pointerCachePath}) is not valid.", nameof(pointerCachePath)); | ||||
|  | ||||
| @ -201,7 +201,7 @@ namespace Jellyfin.Api.Controllers | ||||
| 
 | ||||
|             // For older files, assume fully static | ||||
|             var fileShare = file.LastWriteTimeUtc < DateTime.UtcNow.AddHours(-1) ? FileShare.Read : FileShare.ReadWrite; | ||||
|             FileStream stream = new FileStream(file.FullName, FileMode.Open, FileAccess.Read, fileShare, IODefaults.FileStreamBufferSize, AsyncFile.UseAsyncIO); | ||||
|             FileStream stream = new FileStream(file.FullName, FileMode.Open, FileAccess.Read, fileShare, IODefaults.FileStreamBufferSize, FileOptions.Asynchronous); | ||||
|             return File(stream, "text/plain; charset=utf-8"); | ||||
|         } | ||||
| 
 | ||||
|  | ||||
| @ -1,6 +1,7 @@ | ||||
| using System; | ||||
| using System.IO; | ||||
| using System.Net.Http; | ||||
| using System.Net.Mime; | ||||
| using System.Threading; | ||||
| using System.Threading.Tasks; | ||||
| using Jellyfin.Api.Models.PlaybackDtos; | ||||
| @ -40,7 +41,7 @@ namespace Jellyfin.Api.Helpers | ||||
| 
 | ||||
|             // Can't dispose the response as it's required up the call chain. | ||||
|             var response = await httpClient.GetAsync(new Uri(state.MediaPath), cancellationToken).ConfigureAwait(false); | ||||
|             var contentType = response.Content.Headers.ContentType?.ToString(); | ||||
|             var contentType = response.Content.Headers.ContentType?.ToString() ?? MediaTypeNames.Text.Plain; | ||||
| 
 | ||||
|             httpContext.Response.Headers[HeaderNames.AcceptRanges] = "none"; | ||||
| 
 | ||||
|  | ||||
| @ -38,7 +38,7 @@ namespace Jellyfin.Api.Helpers | ||||
|                         FileAccess.Read, | ||||
|                         FileShare.ReadWrite, | ||||
|                         IODefaults.FileStreamBufferSize, | ||||
|                         (AsyncFile.UseAsyncIO ? FileOptions.Asynchronous : FileOptions.None) | FileOptions.SequentialScan); | ||||
|                         FileOptions.Asynchronous | FileOptions.SequentialScan); | ||||
|                     await using (fileStream.ConfigureAwait(false)) | ||||
|                     { | ||||
|                         using var reader = new StreamReader(fileStream); | ||||
|  | ||||
| @ -17,7 +17,6 @@ namespace Jellyfin.Api.Helpers | ||||
|         private readonly TranscodingJobDto? _job; | ||||
|         private readonly TranscodingJobHelper? _transcodingJobHelper; | ||||
|         private readonly int _timeoutMs; | ||||
|         private readonly bool _allowAsyncFileRead; | ||||
|         private int _bytesWritten; | ||||
|         private bool _disposed; | ||||
| 
 | ||||
| @ -34,17 +33,7 @@ namespace Jellyfin.Api.Helpers | ||||
|             _transcodingJobHelper = transcodingJobHelper; | ||||
|             _timeoutMs = timeoutMs; | ||||
| 
 | ||||
|             var fileOptions = FileOptions.SequentialScan; | ||||
|             _allowAsyncFileRead = false; | ||||
| 
 | ||||
|             // use non-async filestream along with read due to https://github.com/dotnet/corefx/issues/6039 | ||||
|             if (AsyncFile.UseAsyncIO) | ||||
|             { | ||||
|                 fileOptions |= FileOptions.Asynchronous; | ||||
|                 _allowAsyncFileRead = true; | ||||
|             } | ||||
| 
 | ||||
|             _stream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, IODefaults.FileStreamBufferSize, fileOptions); | ||||
|             _stream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, IODefaults.FileStreamBufferSize, FileOptions.Asynchronous | FileOptions.SequentialScan); | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
| @ -57,7 +46,6 @@ namespace Jellyfin.Api.Helpers | ||||
|             _job = null; | ||||
|             _transcodingJobHelper = null; | ||||
|             _timeoutMs = timeoutMs; | ||||
|             _allowAsyncFileRead = AsyncFile.UseAsyncIO; | ||||
|             _stream = stream; | ||||
|         } | ||||
| 
 | ||||
| @ -103,15 +91,7 @@ namespace Jellyfin.Api.Helpers | ||||
|             while (remainingBytesToRead > 0) | ||||
|             { | ||||
|                 cancellationToken.ThrowIfCancellationRequested(); | ||||
|                 int bytesRead; | ||||
|                 if (_allowAsyncFileRead) | ||||
|                 { | ||||
|                     bytesRead = await _stream.ReadAsync(buffer, newOffset, remainingBytesToRead, cancellationToken).ConfigureAwait(false); | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     bytesRead = _stream.Read(buffer, newOffset, remainingBytesToRead); | ||||
|                 } | ||||
|                 int bytesRead = await _stream.ReadAsync(buffer, newOffset, remainingBytesToRead, cancellationToken).ConfigureAwait(false); | ||||
| 
 | ||||
|                 remainingBytesToRead -= bytesRead; | ||||
|                 newOffset += bytesRead; | ||||
|  | ||||
| @ -557,7 +557,7 @@ namespace Jellyfin.Api.Helpers | ||||
|                 $"{logFilePrefix}{DateTime.Now:yyyy-MM-dd_HH-mm-ss}_{state.Request.MediaSourceId}_{Guid.NewGuid().ToString()[..8]}.log"); | ||||
| 
 | ||||
|             // FFmpeg writes debug/error info to stderr. This is useful when debugging so let's put it in the log directory. | ||||
|             Stream logStream = new FileStream(logFilePath, FileMode.Create, FileAccess.Write, FileShare.Read, IODefaults.FileStreamBufferSize, AsyncFile.UseAsyncIO); | ||||
|             Stream logStream = new FileStream(logFilePath, FileMode.Create, FileAccess.Write, FileShare.Read, IODefaults.FileStreamBufferSize, FileOptions.Asynchronous); | ||||
| 
 | ||||
|             var commandLineLogMessageBytes = Encoding.UTF8.GetBytes(request.Path + Environment.NewLine + Environment.NewLine + JsonSerializer.Serialize(state.MediaSource) + Environment.NewLine + Environment.NewLine + commandLineLogMessage + Environment.NewLine + Environment.NewLine); | ||||
|             await logStream.WriteAsync(commandLineLogMessageBytes, 0, commandLineLogMessageBytes.Length, cancellationTokenSource.Token).ConfigureAwait(false); | ||||
|  | ||||
| @ -6,7 +6,7 @@ | ||||
|   </PropertyGroup> | ||||
| 
 | ||||
|   <PropertyGroup> | ||||
|     <TargetFramework>net5.0</TargetFramework> | ||||
|     <TargetFramework>net6.0</TargetFramework> | ||||
|     <GenerateDocumentationFile>true</GenerateDocumentationFile> | ||||
|     <!-- https://github.com/microsoft/ApplicationInsights-dotnet/issues/2047 --> | ||||
|     <NoWarn>AD0001</NoWarn> | ||||
|  | ||||
| @ -32,7 +32,8 @@ namespace Jellyfin.Api.ModelBinders | ||||
|             { | ||||
|                 try | ||||
|                 { | ||||
|                     var convertedValue = converter.ConvertFromString(valueProviderResult.FirstValue); | ||||
|                     // REVIEW: This shouldn't be null here | ||||
|                     var convertedValue = converter.ConvertFromString(valueProviderResult.FirstValue!); | ||||
|                     bindingContext.Result = ModelBindingResult.Success(convertedValue); | ||||
|                 } | ||||
|                 catch (FormatException e) | ||||
| @ -44,4 +45,4 @@ namespace Jellyfin.Api.ModelBinders | ||||
|             return Task.CompletedTask; | ||||
|         } | ||||
|     } | ||||
| } | ||||
| } | ||||
|  | ||||
| @ -1,7 +1,7 @@ | ||||
| <Project Sdk="Microsoft.NET.Sdk"> | ||||
| 
 | ||||
|   <PropertyGroup> | ||||
|     <TargetFramework>net5.0</TargetFramework> | ||||
|     <TargetFramework>net6.0</TargetFramework> | ||||
|     <GenerateAssemblyInfo>false</GenerateAssemblyInfo> | ||||
|     <GenerateDocumentationFile>true</GenerateDocumentationFile> | ||||
|     <PublishRepositoryUrl>true</PublishRepositoryUrl> | ||||
|  | ||||
| @ -6,7 +6,7 @@ | ||||
|   </PropertyGroup> | ||||
| 
 | ||||
|   <PropertyGroup> | ||||
|     <TargetFramework>net5.0</TargetFramework> | ||||
|     <TargetFramework>net6.0</TargetFramework> | ||||
|     <GenerateAssemblyInfo>false</GenerateAssemblyInfo> | ||||
|     <GenerateDocumentationFile>true</GenerateDocumentationFile> | ||||
|   </PropertyGroup> | ||||
| @ -28,11 +28,6 @@ | ||||
|     <ProjectReference Include="..\MediaBrowser.Common\MediaBrowser.Common.csproj" /> | ||||
|   </ItemGroup> | ||||
| 
 | ||||
|   <ItemGroup> | ||||
|     <!-- Needed for https://github.com/dotnet/roslyn-analyzers/issues/4382 which is in the SDK yet --> | ||||
|     <PackageReference Include="Microsoft.CodeAnalysis.NetAnalyzers" Version="5.0.3" PrivateAssets="All" /> | ||||
|   </ItemGroup> | ||||
| 
 | ||||
|   <!-- Code analysers--> | ||||
|   <ItemGroup Condition=" '$(Configuration)' == 'Debug' "> | ||||
|     <PackageReference Include="SerilogAnalyzer" Version="0.15.0" PrivateAssets="All" /> | ||||
|  | ||||
| @ -1,6 +1,6 @@ | ||||
| <Project Sdk="Microsoft.NET.Sdk"> | ||||
|   <PropertyGroup> | ||||
|     <TargetFramework>net5.0</TargetFramework> | ||||
|     <TargetFramework>net6.0</TargetFramework> | ||||
|     <GenerateAssemblyInfo>false</GenerateAssemblyInfo> | ||||
|     <GenerateDocumentationFile>true</GenerateDocumentationFile> | ||||
|   </PropertyGroup> | ||||
|  | ||||
| @ -1,7 +1,7 @@ | ||||
| <Project Sdk="Microsoft.NET.Sdk"> | ||||
| 
 | ||||
|   <PropertyGroup> | ||||
|     <TargetFramework>net5.0</TargetFramework> | ||||
|     <TargetFramework>net6.0</TargetFramework> | ||||
|     <GenerateAssemblyInfo>false</GenerateAssemblyInfo> | ||||
|     <GenerateDocumentationFile>true</GenerateDocumentationFile> | ||||
|   </PropertyGroup> | ||||
|  | ||||
| @ -23,7 +23,7 @@ namespace Jellyfin.Server.Configuration | ||||
|         } | ||||
| 
 | ||||
|         /// <inheritdoc /> | ||||
|         public Task<CorsPolicy> GetPolicyAsync(HttpContext context, string policyName) | ||||
|         public Task<CorsPolicy?> GetPolicyAsync(HttpContext context, string? policyName) | ||||
|         { | ||||
|             var corsHosts = _serverConfigurationManager.Configuration.CorsHosts; | ||||
|             var builder = new CorsPolicyBuilder() | ||||
| @ -43,7 +43,7 @@ namespace Jellyfin.Server.Configuration | ||||
|                     .AllowCredentials(); | ||||
|             } | ||||
| 
 | ||||
|             return Task.FromResult(builder.Build()); | ||||
|             return Task.FromResult<CorsPolicy?>(builder.Build()); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -55,8 +55,8 @@ namespace Jellyfin.Server.Infrastructure | ||||
|             // This may or may not be fixed in .NET 6, but looks like it will not https://github.com/dotnet/aspnetcore/issues/34371 | ||||
|             if ((fileInfo.Attributes & FileAttributes.ReparsePoint) == FileAttributes.ReparsePoint) | ||||
|             { | ||||
|                 using Stream thisFileStream = File.OpenRead(path); | ||||
|                 length = thisFileStream.Length; | ||||
|                 using var fileHandle = File.OpenHandle(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); | ||||
|                 length = RandomAccess.GetLength(fileHandle); | ||||
|             } | ||||
| 
 | ||||
|             return new FileMetadata | ||||
| @ -68,7 +68,7 @@ namespace Jellyfin.Server.Infrastructure | ||||
|         } | ||||
| 
 | ||||
|         /// <inheritdoc /> | ||||
|         protected override Task WriteFileAsync(ActionContext context, PhysicalFileResult result, RangeItemHeaderValue range, long rangeLength) | ||||
|         protected override Task WriteFileAsync(ActionContext context, PhysicalFileResult result, RangeItemHeaderValue? range, long rangeLength) | ||||
|         { | ||||
|             if (context == null) | ||||
|             { | ||||
| @ -132,7 +132,7 @@ namespace Jellyfin.Server.Infrastructure | ||||
|                 FileAccess.Read, | ||||
|                 FileShare.ReadWrite, | ||||
|                 bufferSize: BufferSize, | ||||
|                 options: (AsyncFile.UseAsyncIO ? FileOptions.Asynchronous : FileOptions.None) | FileOptions.SequentialScan); | ||||
|                 options: FileOptions.Asynchronous | FileOptions.SequentialScan); | ||||
| 
 | ||||
|             fileStream.Seek(offset, SeekOrigin.Begin); | ||||
|             await StreamCopyOperation | ||||
|  | ||||
| @ -8,7 +8,7 @@ | ||||
|   <PropertyGroup> | ||||
|     <AssemblyName>jellyfin</AssemblyName> | ||||
|     <OutputType>Exe</OutputType> | ||||
|     <TargetFramework>net5.0</TargetFramework> | ||||
|     <TargetFramework>net6.0</TargetFramework> | ||||
|     <ServerGarbageCollection>false</ServerGarbageCollection> | ||||
|     <GenerateAssemblyInfo>false</GenerateAssemblyInfo> | ||||
|     <GenerateDocumentationFile>true</GenerateDocumentationFile> | ||||
|  | ||||
| @ -27,7 +27,11 @@ namespace Jellyfin.Server.Middleware | ||||
|         /// <returns>The async task.</returns> | ||||
|         public async Task Invoke(HttpContext httpContext) | ||||
|         { | ||||
|             httpContext.Features.Set<IQueryFeature>(new UrlDecodeQueryFeature(httpContext.Features.Get<IQueryFeature>())); | ||||
|             var feature = httpContext.Features.Get<IQueryFeature>(); | ||||
|             if (feature != null) | ||||
|             { | ||||
|                 httpContext.Features.Set<IQueryFeature>(new UrlDecodeQueryFeature(feature)); | ||||
|             } | ||||
| 
 | ||||
|             await _next(httpContext).ConfigureAwait(false); | ||||
|         } | ||||
|  | ||||
| @ -52,20 +52,14 @@ namespace Jellyfin.Server.Middleware | ||||
|                     return; | ||||
|                 } | ||||
| 
 | ||||
|                 // Unencode and re-parse querystring. | ||||
|                 var unencodedKey = HttpUtility.UrlDecode(key); | ||||
| 
 | ||||
|                 if (string.Equals(unencodedKey, key, StringComparison.Ordinal)) | ||||
|                 if (!key.Contains('=')) | ||||
|                 { | ||||
|                     // Don't do anything if it's not encoded. | ||||
|                     _store = value; | ||||
|                     return; | ||||
|                 } | ||||
| 
 | ||||
|                 var pairs = new Dictionary<string, StringValues>(); | ||||
|                 var queryString = unencodedKey.SpanSplit('&'); | ||||
| 
 | ||||
|                 foreach (var pair in queryString) | ||||
|                 foreach (var pair in key.SpanSplit('&')) | ||||
|                 { | ||||
|                     var i = pair.IndexOf('='); | ||||
|                     if (i == -1) | ||||
|  | ||||
| @ -1,7 +1,6 @@ | ||||
| using System; | ||||
| using System.IO; | ||||
| using Emby.Server.Implementations.Data; | ||||
| using Emby.Server.Implementations.Serialization; | ||||
| using Jellyfin.Data.Entities; | ||||
| using Jellyfin.Data.Enums; | ||||
| using Jellyfin.Extensions.Json; | ||||
| @ -10,6 +9,7 @@ using Jellyfin.Server.Implementations.Users; | ||||
| using MediaBrowser.Controller; | ||||
| using MediaBrowser.Controller.Entities; | ||||
| using MediaBrowser.Model.Configuration; | ||||
| using MediaBrowser.Model.Serialization; | ||||
| using MediaBrowser.Model.Users; | ||||
| using Microsoft.Extensions.Logging; | ||||
| using SQLitePCL.pretty; | ||||
| @ -27,7 +27,7 @@ namespace Jellyfin.Server.Migrations.Routines | ||||
|         private readonly ILogger<MigrateUserDb> _logger; | ||||
|         private readonly IServerApplicationPaths _paths; | ||||
|         private readonly JellyfinDbProvider _provider; | ||||
|         private readonly MyXmlSerializer _xmlSerializer; | ||||
|         private readonly IXmlSerializer _xmlSerializer; | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// Initializes a new instance of the <see cref="MigrateUserDb"/> class. | ||||
| @ -40,7 +40,7 @@ namespace Jellyfin.Server.Migrations.Routines | ||||
|             ILogger<MigrateUserDb> logger, | ||||
|             IServerApplicationPaths paths, | ||||
|             JellyfinDbProvider provider, | ||||
|             MyXmlSerializer xmlSerializer) | ||||
|             IXmlSerializer xmlSerializer) | ||||
|         { | ||||
|             _logger = logger; | ||||
|             _paths = paths; | ||||
|  | ||||
| @ -547,7 +547,7 @@ namespace Jellyfin.Server | ||||
|                 ?? throw new InvalidOperationException($"Invalid resource path: '{ResourcePath}'"); | ||||
| 
 | ||||
|             // Copy the resource contents to the expected file path for the config file | ||||
|             await using Stream dst = new FileStream(configPath, FileMode.CreateNew, FileAccess.Write, FileShare.None, IODefaults.FileStreamBufferSize, AsyncFile.UseAsyncIO); | ||||
|             await using Stream dst = new FileStream(configPath, FileMode.CreateNew, FileAccess.Write, FileShare.None, IODefaults.FileStreamBufferSize, FileOptions.Asynchronous); | ||||
|             await resource.CopyToAsync(dst).ConfigureAwait(false); | ||||
|         } | ||||
| 
 | ||||
|  | ||||
| @ -29,7 +29,7 @@ | ||||
|   </ItemGroup> | ||||
| 
 | ||||
|   <PropertyGroup> | ||||
|     <TargetFramework>net5.0</TargetFramework> | ||||
|     <TargetFramework>net6.0</TargetFramework> | ||||
|     <GenerateAssemblyInfo>false</GenerateAssemblyInfo> | ||||
|     <GenerateDocumentationFile>true</GenerateDocumentationFile> | ||||
|     <PublishRepositoryUrl>true</PublishRepositoryUrl> | ||||
|  | ||||
| @ -74,6 +74,6 @@ namespace MediaBrowser.Controller.Dlna | ||||
|         /// </summary> | ||||
|         /// <param name="filename">The filename.</param> | ||||
|         /// <returns>DlnaIconResponse.</returns> | ||||
|         ImageStream GetIcon(string filename); | ||||
|         ImageStream? GetIcon(string filename); | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -58,7 +58,7 @@ namespace MediaBrowser.Controller.Drawing | ||||
|         /// <returns>Guid.</returns> | ||||
|         string GetImageCacheTag(BaseItem item, ItemImageInfo image); | ||||
| 
 | ||||
|         string GetImageCacheTag(BaseItem item, ChapterInfo info); | ||||
|         string GetImageCacheTag(BaseItem item, ChapterInfo chapter); | ||||
| 
 | ||||
|         string? GetImageCacheTag(User user); | ||||
| 
 | ||||
|  | ||||
| @ -8,11 +8,16 @@ namespace MediaBrowser.Controller.Drawing | ||||
| { | ||||
|     public class ImageStream : IDisposable | ||||
|     { | ||||
|         public ImageStream(Stream stream) | ||||
|         { | ||||
|             Stream = stream; | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// Gets or sets the stream. | ||||
|         /// Gets the stream. | ||||
|         /// </summary> | ||||
|         /// <value>The stream.</value> | ||||
|         public Stream? Stream { get; set; } | ||||
|         public Stream Stream { get; } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// Gets or sets the format. | ||||
|  | ||||
| @ -32,7 +32,7 @@ | ||||
|   </ItemGroup> | ||||
| 
 | ||||
|   <PropertyGroup> | ||||
|     <TargetFramework>net5.0</TargetFramework> | ||||
|     <TargetFramework>net6.0</TargetFramework> | ||||
|     <GenerateAssemblyInfo>false</GenerateAssemblyInfo> | ||||
|     <GenerateDocumentationFile>true</GenerateDocumentationFile> | ||||
|     <PublishRepositoryUrl>true</PublishRepositoryUrl> | ||||
|  | ||||
| @ -541,7 +541,12 @@ namespace MediaBrowser.Controller.MediaEncoding | ||||
|                 return MimeType; | ||||
|             } | ||||
| 
 | ||||
|             return MimeTypes.GetMimeType(outputPath, enableStreamDefault); | ||||
|             if (enableStreamDefault) | ||||
|             { | ||||
|                 return MimeTypes.GetMimeType(outputPath); | ||||
|             } | ||||
| 
 | ||||
|             return MimeTypes.GetMimeType(outputPath, null); | ||||
|         } | ||||
| 
 | ||||
|         public bool DeInterlace(string videoCodec, bool forceDeinterlaceIfSourceIsInterlaced) | ||||
|  | ||||
| @ -11,7 +11,7 @@ | ||||
|   </ItemGroup> | ||||
| 
 | ||||
|   <PropertyGroup> | ||||
|     <TargetFramework>net5.0</TargetFramework> | ||||
|     <TargetFramework>net6.0</TargetFramework> | ||||
|     <GenerateAssemblyInfo>false</GenerateAssemblyInfo> | ||||
|     <GenerateDocumentationFile>true</GenerateDocumentationFile> | ||||
|   </PropertyGroup> | ||||
|  | ||||
| @ -6,7 +6,7 @@ | ||||
|   </PropertyGroup> | ||||
| 
 | ||||
|   <PropertyGroup> | ||||
|     <TargetFramework>net5.0</TargetFramework> | ||||
|     <TargetFramework>net6.0</TargetFramework> | ||||
|     <GenerateAssemblyInfo>false</GenerateAssemblyInfo> | ||||
|     <GenerateDocumentationFile>true</GenerateDocumentationFile> | ||||
|   </PropertyGroup> | ||||
|  | ||||
| @ -38,7 +38,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles | ||||
|             subRip.LoadSubtitle(subtitle, lines, "untitled"); | ||||
|             if (subRip.ErrorCount > 0) | ||||
|             { | ||||
|                 _logger.LogError("{ErrorCount} errors encountered while parsing subtitle."); | ||||
|                 _logger.LogError("{ErrorCount} errors encountered while parsing subtitle", subRip.ErrorCount); | ||||
|             } | ||||
| 
 | ||||
|             var trackInfo = new SubtitleTrackInfo(); | ||||
|  | ||||
| @ -680,7 +680,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles | ||||
|             if (!string.Equals(text, newText, StringComparison.Ordinal)) | ||||
|             { | ||||
|                 // use FileShare.None as this bypasses dotnet bug dotnet/runtime#42790 . | ||||
|                 using (var fileStream = new FileStream(file, FileMode.Create, FileAccess.Write, FileShare.None, IODefaults.FileStreamBufferSize, AsyncFile.UseAsyncIO)) | ||||
|                 using (var fileStream = new FileStream(file, FileMode.Create, FileAccess.Write, FileShare.None, IODefaults.FileStreamBufferSize, FileOptions.Asynchronous)) | ||||
|                 using (var writer = new StreamWriter(fileStream, encoding)) | ||||
|                 { | ||||
|                     await writer.WriteAsync(newText.AsMemory(), cancellationToken).ConfigureAwait(false); | ||||
|  | ||||
| @ -8,20 +8,13 @@ namespace MediaBrowser.Model.IO | ||||
|     /// </summary> | ||||
|     public static class AsyncFile | ||||
|     { | ||||
|         /// <summary> | ||||
|         /// Gets a value indicating whether we should use async IO on this platform. | ||||
|         /// <see href="https://github.com/dotnet/runtime/issues/16354" />. | ||||
|         /// </summary> | ||||
|         /// <returns>Returns <c>false</c> on Windows; otherwise <c>true</c>.</returns> | ||||
|         public static bool UseAsyncIO => !OperatingSystem.IsWindows(); | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// Opens an existing file for reading. | ||||
|         /// </summary> | ||||
|         /// <param name="path">The file to be opened for reading.</param> | ||||
|         /// <returns>A read-only <see cref="FileStream" /> on the specified path.</returns> | ||||
|         public static FileStream OpenRead(string path) | ||||
|             => new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read, IODefaults.FileStreamBufferSize, UseAsyncIO); | ||||
|             => new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read, IODefaults.FileStreamBufferSize, FileOptions.Asynchronous); | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// Opens an existing file for writing. | ||||
| @ -29,6 +22,6 @@ namespace MediaBrowser.Model.IO | ||||
|         /// <param name="path">The file to be opened for writing.</param> | ||||
|         /// <returns>An unshared <see cref="FileStream" /> object on the specified path with Write access.</returns> | ||||
|         public static FileStream OpenWrite(string path) | ||||
|             => new FileStream(path, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None, IODefaults.FileStreamBufferSize, UseAsyncIO); | ||||
|             => new FileStream(path, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None, IODefaults.FileStreamBufferSize, FileOptions.Asynchronous); | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -14,7 +14,7 @@ | ||||
|   </PropertyGroup> | ||||
| 
 | ||||
|   <PropertyGroup> | ||||
|     <TargetFramework>net5.0</TargetFramework> | ||||
|     <TargetFramework>net6.0</TargetFramework> | ||||
|     <GenerateAssemblyInfo>false</GenerateAssemblyInfo> | ||||
|     <GenerateDocumentationFile>true</GenerateDocumentationFile> | ||||
|     <PublishRepositoryUrl>true</PublishRepositoryUrl> | ||||
|  | ||||
| @ -2,6 +2,7 @@ | ||||
| 
 | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Diagnostics.CodeAnalysis; | ||||
| using System.IO; | ||||
| using System.Linq; | ||||
| using Jellyfin.Extensions; | ||||
| @ -164,15 +165,16 @@ namespace MediaBrowser.Model.Net | ||||
|             return dict; | ||||
|         } | ||||
| 
 | ||||
|         public static string? GetMimeType(string path) => GetMimeType(path, true); | ||||
|         public static string GetMimeType(string path) => GetMimeType(path, "application/octet-stream"); | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// Gets the type of the MIME. | ||||
|         /// </summary> | ||||
|         /// <param name="filename">The filename to find the MIME type of.</param> | ||||
|         /// <param name="enableStreamDefault">Whether of not to return a default value if no fitting MIME type is found.</param> | ||||
|         /// <returns>The worrect MIME type for the given filename, or `null` if it wasn't found and <paramref name="enableStreamDefault"/> is false.</returns> | ||||
|         public static string? GetMimeType(string filename, bool enableStreamDefault) | ||||
|         /// <param name="defaultValue">The default value to return if no fitting MIME type is found.</param> | ||||
|         /// <returns>The correct MIME type for the given filename, or <paramref name="defaultValue"/> if it wasn't found.</returns> | ||||
|         [return: NotNullIfNotNullAttribute("defaultValue")] | ||||
|         public static string? GetMimeType(string filename, string? defaultValue = null) | ||||
|         { | ||||
|             if (filename.Length == 0) | ||||
|             { | ||||
| @ -211,7 +213,7 @@ namespace MediaBrowser.Model.Net | ||||
|                 return "application/octet-stream"; | ||||
|             } | ||||
| 
 | ||||
|             return enableStreamDefault ? "application/octet-stream" : null; | ||||
|             return defaultValue; | ||||
|         } | ||||
| 
 | ||||
|         public static string? ToExtension(string mimeType) | ||||
|  | ||||
| @ -264,7 +264,7 @@ namespace MediaBrowser.Providers.Manager | ||||
|                 _fileSystem.SetAttributes(path, false, false); | ||||
| 
 | ||||
|                 // use FileShare.None as this bypasses dotnet bug dotnet/runtime#42790 . | ||||
|                 await using (var fs = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.None, IODefaults.FileStreamBufferSize, AsyncFile.UseAsyncIO)) | ||||
|                 await using (var fs = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.None, IODefaults.FileStreamBufferSize, FileOptions.Asynchronous)) | ||||
|                 { | ||||
|                     await source.CopyToAsync(fs, cancellationToken).ConfigureAwait(false); | ||||
|                 } | ||||
|  | ||||
| @ -163,7 +163,7 @@ namespace MediaBrowser.Providers.Manager | ||||
|                                 { | ||||
|                                     var mimeType = MimeTypes.GetMimeType(response.Path); | ||||
| 
 | ||||
|                                     var stream = new FileStream(response.Path, FileMode.Open, FileAccess.Read, FileShare.Read, IODefaults.FileStreamBufferSize, AsyncFile.UseAsyncIO); | ||||
|                                     var stream = new FileStream(response.Path, FileMode.Open, FileAccess.Read, FileShare.Read, IODefaults.FileStreamBufferSize, FileOptions.Asynchronous); | ||||
| 
 | ||||
|                                     await _providerManager.SaveImage(item, stream, mimeType, imageType, null, cancellationToken).ConfigureAwait(false); | ||||
|                                 } | ||||
|  | ||||
| @ -26,7 +26,7 @@ | ||||
|   </ItemGroup> | ||||
| 
 | ||||
|   <PropertyGroup> | ||||
|     <TargetFramework>net5.0</TargetFramework> | ||||
|     <TargetFramework>net6.0</TargetFramework> | ||||
|     <GenerateAssemblyInfo>false</GenerateAssemblyInfo> | ||||
|     <GenerateDocumentationFile>true</GenerateDocumentationFile> | ||||
|     <CodeAnalysisRuleSet>../jellyfin.ruleset</CodeAnalysisRuleSet> | ||||
|  | ||||
| @ -173,7 +173,7 @@ namespace MediaBrowser.Providers.Plugins.AudioDb | ||||
|             using var response = await _httpClientFactory.CreateClient(NamedClient.Default).GetAsync(url, cancellationToken).ConfigureAwait(false); | ||||
|             await using var stream = await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false); | ||||
|             // use FileShare.None as this bypasses dotnet bug dotnet/runtime#42790 . | ||||
|             await using var xmlFileStream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.None, IODefaults.FileStreamBufferSize, AsyncFile.UseAsyncIO); | ||||
|             await using var xmlFileStream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.None, IODefaults.FileStreamBufferSize, FileOptions.Asynchronous); | ||||
|             await stream.CopyToAsync(xmlFileStream, cancellationToken).ConfigureAwait(false); | ||||
|         } | ||||
| 
 | ||||
|  | ||||
| @ -155,7 +155,7 @@ namespace MediaBrowser.Providers.Plugins.AudioDb | ||||
|             Directory.CreateDirectory(Path.GetDirectoryName(path)); | ||||
| 
 | ||||
|             // use FileShare.None as this bypasses dotnet bug dotnet/runtime#42790 . | ||||
|             await using var xmlFileStream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.None, IODefaults.FileStreamBufferSize, AsyncFile.UseAsyncIO); | ||||
|             await using var xmlFileStream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.None, IODefaults.FileStreamBufferSize, FileOptions.Asynchronous); | ||||
|             await stream.CopyToAsync(xmlFileStream, cancellationToken).ConfigureAwait(false); | ||||
|         } | ||||
| 
 | ||||
|  | ||||
| @ -18,7 +18,7 @@ namespace MediaBrowser.Providers.Plugins.Omdb | ||||
|             if (reader.TokenType == JsonTokenType.String) | ||||
|             { | ||||
|                 var str = reader.GetString(); | ||||
|                 if (str != null && str.Equals("N/A", StringComparison.OrdinalIgnoreCase)) | ||||
|                 if (str == null || str.Equals("N/A", StringComparison.OrdinalIgnoreCase)) | ||||
|                 { | ||||
|                     return null; | ||||
|                 } | ||||
|  | ||||
| @ -295,7 +295,7 @@ namespace MediaBrowser.Providers.Plugins.Omdb | ||||
|                     imdbParam)); | ||||
| 
 | ||||
|             var rootObject = await GetDeserializedOmdbResponse<RootObject>(_httpClientFactory.CreateClient(NamedClient.Default), url, cancellationToken).ConfigureAwait(false); | ||||
|             await using FileStream jsonFileStream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.None, IODefaults.FileStreamBufferSize, AsyncFile.UseAsyncIO); | ||||
|             await using FileStream jsonFileStream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.None, IODefaults.FileStreamBufferSize, FileOptions.Asynchronous); | ||||
|             await JsonSerializer.SerializeAsync(jsonFileStream, rootObject, _jsonOptions, cancellationToken).ConfigureAwait(false); | ||||
| 
 | ||||
|             return path; | ||||
| @ -335,7 +335,7 @@ namespace MediaBrowser.Providers.Plugins.Omdb | ||||
|                     seasonId)); | ||||
| 
 | ||||
|             var rootObject = await GetDeserializedOmdbResponse<SeasonRootObject>(_httpClientFactory.CreateClient(NamedClient.Default), url, cancellationToken).ConfigureAwait(false); | ||||
|             await using FileStream jsonFileStream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.None, IODefaults.FileStreamBufferSize, AsyncFile.UseAsyncIO); | ||||
|             await using FileStream jsonFileStream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.None, IODefaults.FileStreamBufferSize, FileOptions.Asynchronous); | ||||
|             await JsonSerializer.SerializeAsync(jsonFileStream, rootObject, _jsonOptions, cancellationToken).ConfigureAwait(false); | ||||
| 
 | ||||
|             return path; | ||||
|  | ||||
| @ -146,7 +146,7 @@ namespace MediaBrowser.Providers.Studios | ||||
| 
 | ||||
|                 Directory.CreateDirectory(Path.GetDirectoryName(file)); | ||||
|                 await using var response = await httpClient.GetStreamAsync(url, cancellationToken).ConfigureAwait(false); | ||||
|                 await using var fileStream = new FileStream(file, FileMode.Create, FileAccess.Write, FileShare.None, IODefaults.FileStreamBufferSize, AsyncFile.UseAsyncIO); | ||||
|                 await using var fileStream = new FileStream(file, FileMode.Create, FileAccess.Write, FileShare.None, IODefaults.FileStreamBufferSize, FileOptions.Asynchronous); | ||||
|                 await response.CopyToAsync(fileStream, cancellationToken).ConfigureAwait(false); | ||||
|             } | ||||
| 
 | ||||
|  | ||||
| @ -245,7 +245,7 @@ namespace MediaBrowser.Providers.Subtitles | ||||
|                     Directory.CreateDirectory(Path.GetDirectoryName(savePath)); | ||||
| 
 | ||||
|                     // use FileShare.None as this bypasses dotnet bug dotnet/runtime#42790 . | ||||
|                     using var fs = new FileStream(savePath, FileMode.Create, FileAccess.Write, FileShare.None, FileStreamBufferSize, AsyncFile.UseAsyncIO); | ||||
|                     using var fs = new FileStream(savePath, FileMode.Create, FileAccess.Write, FileShare.None, FileStreamBufferSize, FileOptions.Asynchronous); | ||||
|                     await stream.CopyToAsync(fs).ConfigureAwait(false); | ||||
| 
 | ||||
|                     return; | ||||
|  | ||||
| @ -15,7 +15,7 @@ | ||||
|   </ItemGroup> | ||||
| 
 | ||||
|   <PropertyGroup> | ||||
|     <TargetFramework>net5.0</TargetFramework> | ||||
|     <TargetFramework>net6.0</TargetFramework> | ||||
|     <GenerateAssemblyInfo>false</GenerateAssemblyInfo> | ||||
|     <GenerateDocumentationFile>true</GenerateDocumentationFile> | ||||
|   </PropertyGroup> | ||||
|  | ||||
| @ -1,5 +1,6 @@ | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Globalization; | ||||
| using System.Text; | ||||
| 
 | ||||
| namespace Rssdp.Infrastructure | ||||
| @ -45,11 +46,11 @@ namespace Rssdp.Infrastructure | ||||
| 
 | ||||
|             const string ArgFormat = "{0}: {1}\r\n"; | ||||
| 
 | ||||
|             builder.AppendFormat("{0}\r\n", header); | ||||
|             builder.AppendFormat(CultureInfo.InvariantCulture, "{0}\r\n", header); | ||||
| 
 | ||||
|             foreach (var pair in values) | ||||
|             { | ||||
|                 builder.AppendFormat(ArgFormat, pair.Key, pair.Value); | ||||
|                 builder.AppendFormat(CultureInfo.InvariantCulture, ArgFormat, pair.Key, pair.Value); | ||||
|             } | ||||
| 
 | ||||
|             builder.Append("\r\n"); | ||||
|  | ||||
| @ -11,7 +11,7 @@ | ||||
|   </ItemGroup> | ||||
| 
 | ||||
|   <PropertyGroup> | ||||
|     <TargetFramework>net5.0</TargetFramework> | ||||
|     <TargetFramework>net6.0</TargetFramework> | ||||
|     <GenerateAssemblyInfo>false</GenerateAssemblyInfo> | ||||
|     <AnalysisMode>AllDisabledByDefault</AnalysisMode> | ||||
|     <Nullable>disable</Nullable> | ||||
|  | ||||
| @ -1,6 +1,7 @@ | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Collections.ObjectModel; | ||||
| using System.Globalization; | ||||
| using Rssdp.Infrastructure; | ||||
| 
 | ||||
| namespace Rssdp | ||||
| @ -134,11 +135,13 @@ namespace Rssdp | ||||
|         { | ||||
|             get | ||||
|             { | ||||
|                 return String.Format("urn:{0}:{3}:{1}:{2}", | ||||
|                 this.DeviceTypeNamespace ?? String.Empty, | ||||
|                 this.DeviceType ?? String.Empty, | ||||
|                 this.DeviceVersion, | ||||
|                 this.DeviceClass ?? "device"); | ||||
|                 return String.Format( | ||||
|                     CultureInfo.InvariantCulture, | ||||
|                     "urn:{0}:{3}:{1}:{2}", | ||||
|                     this.DeviceTypeNamespace ?? String.Empty, | ||||
|                     this.DeviceType ?? String.Empty, | ||||
|                     this.DeviceVersion, | ||||
|                     this.DeviceClass ?? "device"); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|  | ||||
| @ -1,6 +1,7 @@ | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Collections.ObjectModel; | ||||
| using System.Globalization; | ||||
| using System.Linq; | ||||
| using System.Net; | ||||
| using System.Threading; | ||||
| @ -233,7 +234,7 @@ namespace Rssdp.Infrastructure | ||||
|         { | ||||
|             if (String.IsNullOrEmpty(searchTarget)) | ||||
|             { | ||||
|                 WriteTrace(String.Format("Invalid search request received From {0}, Target is null/empty.", remoteEndPoint.ToString())); | ||||
|                 WriteTrace(String.Format(CultureInfo.InvariantCulture, "Invalid search request received From {0}, Target is null/empty.", remoteEndPoint.ToString())); | ||||
|                 return; | ||||
|             } | ||||
| 
 | ||||
| @ -340,7 +341,7 @@ namespace Rssdp.Infrastructure | ||||
| 
 | ||||
|         private string GetUsn(string udn, string fullDeviceType) | ||||
|         { | ||||
|             return String.Format("{0}::{1}", udn, fullDeviceType); | ||||
|             return String.Format(CultureInfo.InvariantCulture, "{0}::{1}", udn, fullDeviceType); | ||||
|         } | ||||
| 
 | ||||
|         private async void SendSearchResponse( | ||||
| @ -363,7 +364,7 @@ namespace Rssdp.Infrastructure | ||||
|             values["DATE"] = DateTime.UtcNow.ToString("r"); | ||||
|             values["CACHE-CONTROL"] = "max-age = " + rootDevice.CacheLifetime.TotalSeconds; | ||||
|             values["ST"] = searchTarget; | ||||
|             values["SERVER"] = string.Format("{0}/{1} UPnP/1.0 RSSDP/{2}", _OSName, _OSVersion, ServerVersion); | ||||
|             values["SERVER"] = string.Format(CultureInfo.InvariantCulture, "{0}/{1} UPnP/1.0 RSSDP/{2}", _OSName, _OSVersion, ServerVersion); | ||||
|             values["USN"] = uniqueServiceName; | ||||
|             values["LOCATION"] = rootDevice.Location.ToString(); | ||||
| 
 | ||||
| @ -497,7 +498,7 @@ namespace Rssdp.Infrastructure | ||||
|             values["DATE"] = DateTime.UtcNow.ToString("r"); | ||||
|             values["CACHE-CONTROL"] = "max-age = " + rootDevice.CacheLifetime.TotalSeconds; | ||||
|             values["LOCATION"] = rootDevice.Location.ToString(); | ||||
|             values["SERVER"] = string.Format("{0}/{1} UPnP/1.0 RSSDP/{2}", _OSName, _OSVersion, ServerVersion); | ||||
|             values["SERVER"] = string.Format(CultureInfo.InvariantCulture, "{0}/{1} UPnP/1.0 RSSDP/{2}", _OSName, _OSVersion, ServerVersion); | ||||
|             values["NTS"] = "ssdp:alive"; | ||||
|             values["NT"] = notificationType; | ||||
|             values["USN"] = uniqueServiceName; | ||||
| @ -522,7 +523,7 @@ namespace Rssdp.Infrastructure | ||||
|             } | ||||
| 
 | ||||
|             tasks.Add(SendByeByeNotification(device, device.Udn, device.Udn, cancellationToken)); | ||||
|             tasks.Add(SendByeByeNotification(device, String.Format("urn:{0}", device.FullDeviceType), GetUsn(device.Udn, device.FullDeviceType), cancellationToken)); | ||||
|             tasks.Add(SendByeByeNotification(device, String.Format(CultureInfo.InvariantCulture, "urn:{0}", device.FullDeviceType), GetUsn(device.Udn, device.FullDeviceType), cancellationToken)); | ||||
| 
 | ||||
|             foreach (var childDevice in device.Devices) | ||||
|             { | ||||
| @ -542,7 +543,7 @@ namespace Rssdp.Infrastructure | ||||
|             // If needed later for non-server devices, these headers will need to be dynamic | ||||
|             values["HOST"] = "239.255.255.250:1900"; | ||||
|             values["DATE"] = DateTime.UtcNow.ToString("r"); | ||||
|             values["SERVER"] = string.Format("{0}/{1} UPnP/1.0 RSSDP/{2}", _OSName, _OSVersion, ServerVersion); | ||||
|             values["SERVER"] = string.Format(CultureInfo.InvariantCulture, "{0}/{1} UPnP/1.0 RSSDP/{2}", _OSName, _OSVersion, ServerVersion); | ||||
|             values["NTS"] = "ssdp:byebye"; | ||||
|             values["NT"] = notificationType; | ||||
|             values["USN"] = uniqueServiceName; | ||||
| @ -550,7 +551,7 @@ namespace Rssdp.Infrastructure | ||||
|             var message = BuildMessage(header, values); | ||||
| 
 | ||||
|             var sendCount = IsDisposed ? 1 : 3; | ||||
|             WriteTrace(String.Format("Sent byebye notification"), device); | ||||
|             WriteTrace(String.Format(CultureInfo.InvariantCulture, "Sent byebye notification"), device); | ||||
|             return _CommsServer.SendMulticastMessage(message, sendCount, _sendOnlyMatchedHost ? device.ToRootDevice().Address : null, cancellationToken); | ||||
|         } | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										2
									
								
								debian/control
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								debian/control
									
									
									
									
										vendored
									
									
								
							| @ -3,7 +3,7 @@ Section: misc | ||||
| Priority: optional | ||||
| Maintainer: Jellyfin Team <team@jellyfin.org> | ||||
| Build-Depends:  debhelper (>= 9), | ||||
|                 dotnet-sdk-5.0, | ||||
|                 dotnet-sdk-6.0, | ||||
|                 libc6-dev, | ||||
|                 libcurl4-openssl-dev, | ||||
|                 libfontconfig1-dev, | ||||
|  | ||||
| @ -2,7 +2,6 @@ FROM centos:7 | ||||
| # 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,12 +10,13 @@ ENV IS_DOCKER=YES | ||||
| # Prepare CentOS environment | ||||
| 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 | ||||
|   && yum install -yq @buildsys-build rpmdevtools yum-plugins-core libcurl-devel fontconfig-devel freetype-devel openssl-devel glibc-devel libicu-devel git wget | ||||
| 
 | ||||
| # Install DotNET SDK | ||||
| RUN rpm -Uvh https://packages.microsoft.com/config/rhel/7/packages-microsoft-prod.rpm \ | ||||
|   && rpmdev-setuptree \ | ||||
|   && yum install -yq dotnet-sdk-${SDK_VERSION} | ||||
| RUN wget -q https://download.visualstudio.microsoft.com/download/pr/5fcb98bb-21e1-47a5-bb8e-bb25f41a3e52/04811d5d05b7e694f040d2a13c1aae4c/dotnet-sdk-6.0.100-rc.1.21463.6-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 | ||||
| 
 | ||||
| # Create symlinks and directories | ||||
| RUN ln -sf ${SOURCE_DIR}/deployment/build.centos.amd64 /build.sh \ | ||||
|  | ||||
| @ -1,4 +1,4 @@ | ||||
| FROM mcr.microsoft.com/dotnet/sdk:5.0-buster-slim | ||||
| FROM mcr.microsoft.com/dotnet/sdk:6.0-bullseye-slim | ||||
| # Docker build arguments | ||||
| ARG SOURCE_DIR=/jellyfin | ||||
| ARG ARTIFACT_DIR=/dist | ||||
|  | ||||
| @ -1,4 +1,4 @@ | ||||
| FROM mcr.microsoft.com/dotnet/sdk:5.0-buster-slim | ||||
| FROM mcr.microsoft.com/dotnet/sdk:6.0-bullseye-slim | ||||
| # Docker build arguments | ||||
| ARG SOURCE_DIR=/jellyfin | ||||
| ARG ARTIFACT_DIR=/dist | ||||
| @ -18,16 +18,16 @@ RUN apt-get update -yqq \ | ||||
| RUN dpkg --add-architecture 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 \ | ||||
|   && TARGET_LIST="arm64" cross-gcc-gensource 9 \ | ||||
|   && cd cross-gcc-packages-amd64/cross-gcc-9-arm64 \ | ||||
|   && apt-get install -yqq --no-install-recommends \ | ||||
|     gcc-8-source libstdc++-8-dev-arm64-cross \ | ||||
|     gcc-9-source libstdc++-9-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 | ||||
|     libfreetype6-dev:arm64 libssl-dev:arm64 liblttng-ust0:arm64 libstdc++-9-dev:arm64 | ||||
| 
 | ||||
| # Link to build script | ||||
| RUN ln -sf ${SOURCE_DIR}/deployment/build.debian.arm64 /build.sh | ||||
|  | ||||
| @ -1,4 +1,4 @@ | ||||
| FROM mcr.microsoft.com/dotnet/sdk:5.0-buster-slim | ||||
| FROM mcr.microsoft.com/dotnet/sdk:6.0-bullseye-slim | ||||
| # Docker build arguments | ||||
| ARG SOURCE_DIR=/jellyfin | ||||
| ARG ARTIFACT_DIR=/dist | ||||
| @ -18,17 +18,17 @@ RUN apt-get update -yqq \ | ||||
| RUN dpkg --add-architecture 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 \ | ||||
|   && TARGET_LIST="armhf" cross-gcc-gensource 9 \ | ||||
|   && cd cross-gcc-packages-amd64/cross-gcc-9-armhf \ | ||||
|   && apt-get install -yqq --no-install-recommends\ | ||||
|     gcc-8-source libstdc++-8-dev-armhf-cross \ | ||||
|     gcc-9-source libstdc++-9-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 | ||||
|     liblttng-ust0:armhf libstdc++-9-dev:armhf | ||||
| 
 | ||||
| # Link to build script | ||||
| RUN ln -sf ${SOURCE_DIR}/deployment/build.debian.armhf /build.sh | ||||
|  | ||||
| @ -1,6 +1,4 @@ | ||||
| ARG DOTNET_VERSION=5.0 | ||||
| 
 | ||||
| FROM mcr.microsoft.com/dotnet/sdk:${DOTNET_VERSION}-buster-slim | ||||
| FROM mcr.microsoft.com/dotnet/sdk:6.0-bullseye-slim | ||||
| 
 | ||||
| ARG SOURCE_DIR=/src | ||||
| ARG ARTIFACT_DIR=/jellyfin | ||||
|  | ||||
| @ -1,6 +1,4 @@ | ||||
| ARG DOTNET_VERSION=5.0 | ||||
| 
 | ||||
| FROM mcr.microsoft.com/dotnet/sdk:${DOTNET_VERSION}-buster-slim | ||||
| FROM mcr.microsoft.com/dotnet/sdk:6.0-bullseye-slim | ||||
| 
 | ||||
| ARG SOURCE_DIR=/src | ||||
| ARG ARTIFACT_DIR=/jellyfin | ||||
|  | ||||
| @ -1,6 +1,4 @@ | ||||
| ARG DOTNET_VERSION=5.0 | ||||
| 
 | ||||
| FROM mcr.microsoft.com/dotnet/sdk:${DOTNET_VERSION}-buster-slim | ||||
| FROM mcr.microsoft.com/dotnet/sdk:6.0-bullseye-slim | ||||
| 
 | ||||
| ARG SOURCE_DIR=/src | ||||
| ARG ARTIFACT_DIR=/jellyfin | ||||
|  | ||||
| @ -2,7 +2,6 @@ FROM fedora:33 | ||||
| # 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,10 +9,14 @@ ENV IS_DOCKER=YES | ||||
| 
 | ||||
| # Prepare Fedora environment | ||||
| 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 | ||||
|   && dnf install -yq @buildsys-build rpmdevtools git dnf-plugins-core libcurl-devel fontconfig-devel freetype-devel openssl-devel glibc-devel libicu-devel systemd wget | ||||
| 
 | ||||
| # Install DotNET SDK | ||||
| RUN dnf install -yq dotnet-sdk-${SDK_VERSION} dotnet-runtime-${SDK_VERSION} | ||||
| RUN wget -q https://download.visualstudio.microsoft.com/download/pr/5fcb98bb-21e1-47a5-bb8e-bb25f41a3e52/04811d5d05b7e694f040d2a13c1aae4c/dotnet-sdk-6.0.100-rc.1.21463.6-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 | ||||
| 
 | ||||
| 
 | ||||
| # Create symlinks and directories | ||||
| RUN ln -sf ${SOURCE_DIR}/deployment/build.fedora.amd64 /build.sh \ | ||||
|  | ||||
| @ -1,4 +1,4 @@ | ||||
| FROM mcr.microsoft.com/dotnet/sdk:5.0-buster-slim | ||||
| FROM mcr.microsoft.com/dotnet/sdk:6.0-bullseye-slim | ||||
| # Docker build arguments | ||||
| ARG SOURCE_DIR=/jellyfin | ||||
| ARG ARTIFACT_DIR=/dist | ||||
|  | ||||
| @ -1,4 +1,4 @@ | ||||
| FROM mcr.microsoft.com/dotnet/sdk:5.0-buster-slim | ||||
| FROM mcr.microsoft.com/dotnet/sdk:6.0-bullseye-slim | ||||
| # Docker build arguments | ||||
| ARG SOURCE_DIR=/jellyfin | ||||
| ARG ARTIFACT_DIR=/dist | ||||
|  | ||||
| @ -1,4 +1,4 @@ | ||||
| FROM mcr.microsoft.com/dotnet/sdk:5.0-buster-slim | ||||
| FROM mcr.microsoft.com/dotnet/sdk:6.0-bullseye-slim | ||||
| # Docker build arguments | ||||
| ARG SOURCE_DIR=/jellyfin | ||||
| ARG ARTIFACT_DIR=/dist | ||||
|  | ||||
| @ -1,4 +1,4 @@ | ||||
| FROM mcr.microsoft.com/dotnet/sdk:5.0-buster-slim | ||||
| FROM mcr.microsoft.com/dotnet/sdk:6.0-bullseye-slim | ||||
| # Docker build arguments | ||||
| ARG SOURCE_DIR=/jellyfin | ||||
| ARG ARTIFACT_DIR=/dist | ||||
|  | ||||
| @ -1,4 +1,4 @@ | ||||
| FROM mcr.microsoft.com/dotnet/sdk:5.0-buster-slim | ||||
| FROM mcr.microsoft.com/dotnet/sdk:6.0-bullseye-slim | ||||
| # Docker build arguments | ||||
| ARG SOURCE_DIR=/jellyfin | ||||
| ARG ARTIFACT_DIR=/dist | ||||
|  | ||||
Some files were not shown because too many files have changed in this diff Show More
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user