mirror of
https://github.com/jellyfin/jellyfin.git
synced 2026-10-26 16:45:09 +00:00
Backport pull request #18059 from jellyfin/release-12.z
Fix transcoding settings migration failure caused by null EncoderPreset
Original-merge: 3e27c7ef7f
Merged-by: crobibero <cody@robibe.ro>
Backported-by: Cody Robibero <cody@robibe.ro>
This commit is contained in:
1 parent
169a3e5d34
commit
4e73688f7d
4 files changed
+199
-2
No files matched your search
@@ -242,6 +242,8 @@
|
||||
- [m0g3r](https://github.com/m0g3r)
|
||||
- [martin-77](https://github.com/martin-77)
|
||||
- [Oggeb1](https://github.com/Oggeb1)
|
||||
- [scr4bble](https://github.com/scr4bble)
|
||||
- [Mateus Bandeira](https://github.com/mateusbandeiraa)
|
||||
|
||||
# Emby Contributors
|
||||
|
||||
|
||||
@@ -79,8 +79,8 @@ public class MigrateEncodingOptions : IMigrationRoutine
|
||||
tonemappingRange = parsedTonemappingRange;
|
||||
}
|
||||
|
||||
var encoderPreset = EncoderPreset.superfast;
|
||||
if (Enum.TryParse<EncoderPreset>(oldConfig.TonemappingRange, true, out var parsedEncoderPreset))
|
||||
var encoderPreset = EncoderPreset.auto;
|
||||
if (Enum.TryParse<EncoderPreset>(oldConfig.EncoderPreset, true, out var parsedEncoderPreset))
|
||||
{
|
||||
encoderPreset = parsedEncoderPreset;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml;
|
||||
using System.Xml.Linq;
|
||||
using Jellyfin.Server.Migrations.Stages;
|
||||
using MediaBrowser.Common.Configuration;
|
||||
using MediaBrowser.Model.Configuration;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Jellyfin.Server.Migrations.Routines;
|
||||
|
||||
/// <summary>
|
||||
/// Replaces the nullable encoder preset written by older versions with the default preset.
|
||||
/// </summary>
|
||||
[JellyfinMigration("2026-09-15T10:43:05", nameof(FixNullEncoderPreset), Stage = JellyfinMigrationStageTypes.PreInitialisation)]
|
||||
internal class FixNullEncoderPreset : IAsyncMigrationRoutine
|
||||
{
|
||||
private static readonly XNamespace _xsiNamespace = "http://www.w3.org/2001/XMLSchema-instance";
|
||||
|
||||
private readonly IApplicationPaths _applicationPaths;
|
||||
private readonly ILogger<FixNullEncoderPreset> _logger;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="FixNullEncoderPreset"/> class.
|
||||
/// </summary>
|
||||
/// <param name="applicationPaths">The application paths.</param>
|
||||
/// <param name="logger">The logger.</param>
|
||||
public FixNullEncoderPreset(IApplicationPaths applicationPaths, ILogger<FixNullEncoderPreset> logger)
|
||||
{
|
||||
_applicationPaths = applicationPaths;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task PerformAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
var path = Path.Combine(_applicationPaths.ConfigurationDirectoryPath, "encoding.xml");
|
||||
if (!File.Exists(path))
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
XDocument document;
|
||||
try
|
||||
{
|
||||
document = XDocument.Load(path, LoadOptions.PreserveWhitespace);
|
||||
}
|
||||
catch (XmlException ex)
|
||||
{
|
||||
_logger.LogWarning(ex, "Could not parse encoding configuration; skipping null encoder preset migration");
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
var encoderPreset = document.Root?.Element(nameof(EncodingOptions.EncoderPreset));
|
||||
if (encoderPreset is null)
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
var nilAttribute = encoderPreset.Attribute(_xsiNamespace + "nil");
|
||||
if (!string.Equals(nilAttribute?.Value, "true", StringComparison.OrdinalIgnoreCase) && !string.IsNullOrEmpty(encoderPreset.Value))
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
nilAttribute?.Remove();
|
||||
encoderPreset.Value = nameof(EncoderPreset.auto);
|
||||
document.Save(path, SaveOptions.DisableFormatting);
|
||||
_logger.LogInformation("Replaced null encoder preset with auto in encoding configuration");
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml.Serialization;
|
||||
using Emby.Server.Implementations;
|
||||
using Jellyfin.Server.Migrations.PreStartupRoutines;
|
||||
using Jellyfin.Server.Migrations.Routines;
|
||||
using MediaBrowser.Common.Configuration;
|
||||
using MediaBrowser.Model.Configuration;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using Microsoft.Extensions.Logging.Abstractions;
|
||||
using Moq;
|
||||
using Xunit;
|
||||
|
||||
namespace Jellyfin.Server.Tests.Migrations;
|
||||
|
||||
public sealed class FixNullEncoderPresetTests : IDisposable
|
||||
{
|
||||
private readonly string _configurationDirectory;
|
||||
private readonly string _encodingConfigurationPath;
|
||||
private readonly FixNullEncoderPreset _migration;
|
||||
|
||||
public FixNullEncoderPresetTests()
|
||||
{
|
||||
_configurationDirectory = Directory.CreateTempSubdirectory("jellyfin-migration-test-").FullName;
|
||||
_encodingConfigurationPath = Path.Combine(_configurationDirectory, "encoding.xml");
|
||||
|
||||
var applicationPaths = new Mock<IApplicationPaths>();
|
||||
applicationPaths.SetupGet(paths => paths.ConfigurationDirectoryPath).Returns(_configurationDirectory);
|
||||
_migration = new FixNullEncoderPreset(applicationPaths.Object, NullLogger<FixNullEncoderPreset>.Instance);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task PerformAsync_ReplacesNullEncoderPresetWithAuto()
|
||||
{
|
||||
const string Configuration = """
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<EncodingOptions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<HardwareAccelerationType>qsv</HardwareAccelerationType>
|
||||
<EncoderPreset xsi:nil="true" />
|
||||
<EnableHardwareEncoding>true</EnableHardwareEncoding>
|
||||
</EncodingOptions>
|
||||
""";
|
||||
await File.WriteAllTextAsync(_encodingConfigurationPath, Configuration, TestContext.Current.CancellationToken);
|
||||
|
||||
await _migration.PerformAsync(TestContext.Current.CancellationToken);
|
||||
|
||||
var serializer = new XmlSerializer(typeof(EncodingOptions));
|
||||
using var reader = File.OpenRead(_encodingConfigurationPath);
|
||||
var encodingOptions = Assert.IsType<EncodingOptions>(serializer.Deserialize(reader));
|
||||
Assert.Equal(EncoderPreset.auto, encodingOptions.EncoderPreset);
|
||||
Assert.Equal(HardwareAccelerationType.qsv, encodingOptions.HardwareAccelerationType);
|
||||
Assert.True(encodingOptions.EnableHardwareEncoding);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task PerformAsync_LeavesValidEncoderPresetUnchanged()
|
||||
{
|
||||
const string Configuration = """
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<EncodingOptions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<EncoderPreset>fast</EncoderPreset>
|
||||
</EncodingOptions>
|
||||
""";
|
||||
await File.WriteAllTextAsync(_encodingConfigurationPath, Configuration, TestContext.Current.CancellationToken);
|
||||
|
||||
await _migration.PerformAsync(TestContext.Current.CancellationToken);
|
||||
|
||||
Assert.Equal(Configuration, await File.ReadAllTextAsync(_encodingConfigurationPath, TestContext.Current.CancellationToken));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task PerformAsync_LeavesMalformedConfigurationUnchanged()
|
||||
{
|
||||
const string Configuration = "<EncodingOptions><EncoderPreset xsi:nil=\"true\" />";
|
||||
await File.WriteAllTextAsync(_encodingConfigurationPath, Configuration, TestContext.Current.CancellationToken);
|
||||
|
||||
await _migration.PerformAsync(TestContext.Current.CancellationToken);
|
||||
|
||||
Assert.Equal(Configuration, await File.ReadAllTextAsync(_encodingConfigurationPath, TestContext.Current.CancellationToken));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task MigrateEncodingOptions_UsesAutoForNullEncoderPreset()
|
||||
{
|
||||
const string Configuration = """
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<EncodingOptions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<HardwareAccelerationType>qsv</HardwareAccelerationType>
|
||||
<TonemappingRange>tv</TonemappingRange>
|
||||
<EncoderPreset xsi:nil="true" />
|
||||
<EnableHardwareEncoding>true</EnableHardwareEncoding>
|
||||
</EncodingOptions>
|
||||
""";
|
||||
await File.WriteAllTextAsync(_encodingConfigurationPath, Configuration, TestContext.Current.CancellationToken);
|
||||
var applicationPaths = new ServerApplicationPaths(
|
||||
_configurationDirectory,
|
||||
_configurationDirectory,
|
||||
_configurationDirectory,
|
||||
_configurationDirectory,
|
||||
_configurationDirectory);
|
||||
|
||||
var migration = new MigrateEncodingOptions(applicationPaths, NullLoggerFactory.Instance);
|
||||
migration.Perform();
|
||||
|
||||
var serializer = new XmlSerializer(typeof(EncodingOptions));
|
||||
using var reader = File.OpenRead(_encodingConfigurationPath);
|
||||
var encodingOptions = Assert.IsType<EncodingOptions>(serializer.Deserialize(reader));
|
||||
Assert.Equal(EncoderPreset.auto, encodingOptions.EncoderPreset);
|
||||
Assert.Equal(HardwareAccelerationType.qsv, encodingOptions.HardwareAccelerationType);
|
||||
Assert.True(encodingOptions.EnableHardwareEncoding);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Directory.Delete(_configurationDirectory, true);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user