Compare commits

...

13 Commits

Author SHA1 Message Date
Jellyfin Release Bot
7bbdfc0d49 Bump version to 10.9.11 2024-09-07 18:10:49 -04:00
Bond-009
3c3ebe8344 Merge pull request #12575 from dmitrylyzo/fix-subtitleextract
Fix subtitle and attachment extraction when input path contains quotes
2024-09-07 22:07:05 +02:00
Dmitry Lyzo
8c4d23435e Fix attachment extraction when input path contains quotes 2024-09-04 00:53:57 +03:00
Dmitry Lyzo
9e4befa52e Fix subtitle extraction when input path contains quotes 2024-09-04 00:09:09 +03:00
Bond-009
b3efae71c0 Merge pull request #12562 from nyanmisaka/fix-profiles
Use filtered codecs to build appliedConditions
2024-09-03 09:20:27 +02:00
Bond-009
70f4f2e8c2 Merge pull request #12558 from Bond-009/altsourcename
Fix alt version name generation
2024-09-03 09:20:15 +02:00
Bond-009
cd2f2ca178 Merge pull request #12550 from Bond-009/formattingstreamwriter
Create and use FormattingStreamWriter
2024-09-03 09:19:32 +02:00
nyanmisaka
8095d39954 Use filtered codecs to build appliedConditions
Signed-off-by: nyanmisaka <nst799610810@gmail.com>
2024-09-01 21:44:23 +08:00
Bond_009
e1ac30ba17 Fix alt version name generation
Instead of replacing all occurrences of the containing folder name, just check the start of the string.
This matches what happens in VideoListResolver.IsEligibleForMultiVersion
Fixes #12555
2024-08-31 14:03:53 +02:00
Bond_009
3b94cfa837 Create and use FormattingStreamWriter
Prevents bugs causes by system cultures with different formatting
2024-08-30 17:19:02 +02:00
Niels van Velzen
2fe13f54ea Merge pull request #12531 from gnattu/dont-apply-chapter-image-settings-to-music
Don't apply chapter image settings to music
2024-08-29 09:43:43 +02:00
gnattu
eb6a6d319b Don't apply chapter image settings to music
Music Album covers are usually not 16:9 and should not use the chapter image resolutions in any case.

Signed-off-by: gnattu <gnattuoc@me.com>
2024-08-29 03:11:34 +08:00
Nyanmisaka
b74c9cae1b Fix CodecProfiles and video encoder profiles (#12521)
Co-authored-by: Dmitry Lyzo <56478732+dmitrylyzo@users.noreply.github.com>
2024-08-28 12:42:44 -06:00
18 changed files with 154 additions and 40 deletions

View File

@@ -36,7 +36,7 @@
<PropertyGroup>
<Authors>Jellyfin Contributors</Authors>
<PackageId>Jellyfin.Naming</PackageId>
<VersionPrefix>10.9.10</VersionPrefix>
<VersionPrefix>10.9.11</VersionPrefix>
<RepositoryUrl>https://github.com/jellyfin/jellyfin</RepositoryUrl>
<PackageLicenseExpression>GPL-3.0-only</PackageLicenseExpression>
</PropertyGroup>

View File

@@ -18,7 +18,7 @@
<PropertyGroup>
<Authors>Jellyfin Contributors</Authors>
<PackageId>Jellyfin.Data</PackageId>
<VersionPrefix>10.9.10</VersionPrefix>
<VersionPrefix>10.9.11</VersionPrefix>
<RepositoryUrl>https://github.com/jellyfin/jellyfin</RepositoryUrl>
<PackageLicenseExpression>GPL-3.0-only</PackageLicenseExpression>
</PropertyGroup>

View File

@@ -8,7 +8,7 @@
<PropertyGroup>
<Authors>Jellyfin Contributors</Authors>
<PackageId>Jellyfin.Common</PackageId>
<VersionPrefix>10.9.10</VersionPrefix>
<VersionPrefix>10.9.11</VersionPrefix>
<RepositoryUrl>https://github.com/jellyfin/jellyfin</RepositoryUrl>
<PackageLicenseExpression>GPL-3.0-only</PackageLicenseExpression>
</PropertyGroup>

View File

@@ -1180,28 +1180,29 @@ namespace MediaBrowser.Controller.Entities
return info;
}
private string GetMediaSourceName(BaseItem item)
internal string GetMediaSourceName(BaseItem item)
{
var terms = new List<string>();
var path = item.Path;
if (item.IsFileProtocol && !string.IsNullOrEmpty(path))
{
var displayName = System.IO.Path.GetFileNameWithoutExtension(path);
if (HasLocalAlternateVersions)
{
var displayName = System.IO.Path.GetFileNameWithoutExtension(path)
.Replace(System.IO.Path.GetFileName(ContainingFolderPath), string.Empty, StringComparison.OrdinalIgnoreCase)
.TrimStart(new char[] { ' ', '-' });
if (!string.IsNullOrEmpty(displayName))
var containingFolderName = System.IO.Path.GetFileName(ContainingFolderPath);
if (displayName.Length > containingFolderName.Length && displayName.StartsWith(containingFolderName, StringComparison.OrdinalIgnoreCase))
{
terms.Add(displayName);
var name = displayName.AsSpan(containingFolderName.Length).TrimStart([' ', '-']);
if (!name.IsWhiteSpace())
{
terms.Add(name.ToString());
}
}
}
if (terms.Count == 0)
{
var displayName = System.IO.Path.GetFileNameWithoutExtension(path);
terms.Add(displayName);
}
}

View File

@@ -180,10 +180,7 @@ namespace MediaBrowser.Controller.Entities.TV
}
public string FindSeriesPresentationUniqueKey()
{
var series = Series;
return series is null ? null : series.PresentationUniqueKey;
}
=> Series?.PresentationUniqueKey;
public string FindSeasonName()
{

View File

@@ -430,8 +430,6 @@ namespace MediaBrowser.Controller.Entities
InternalItemsQuery query,
ILibraryManager libraryManager)
{
var user = query.User;
// This must be the last filter
if (!query.AdjacentTo.IsNullOrEmpty())
{

View File

@@ -8,7 +8,7 @@
<PropertyGroup>
<Authors>Jellyfin Contributors</Authors>
<PackageId>Jellyfin.Controller</PackageId>
<VersionPrefix>10.9.10</VersionPrefix>
<VersionPrefix>10.9.11</VersionPrefix>
<RepositoryUrl>https://github.com/jellyfin/jellyfin</RepositoryUrl>
<PackageLicenseExpression>GPL-3.0-only</PackageLicenseExpression>
</PropertyGroup>

View File

@@ -2005,7 +2005,26 @@ namespace MediaBrowser.Controller.MediaEncoding
}
var profile = state.GetRequestedProfiles(targetVideoCodec).FirstOrDefault() ?? string.Empty;
profile = WhiteSpaceRegex().Replace(profile, string.Empty);
profile = WhiteSpaceRegex().Replace(profile, string.Empty).ToLowerInvariant();
var videoProfiles = Array.Empty<string>();
if (string.Equals("h264", targetVideoCodec, StringComparison.OrdinalIgnoreCase))
{
videoProfiles = _videoProfilesH264;
}
else if (string.Equals("hevc", targetVideoCodec, StringComparison.OrdinalIgnoreCase))
{
videoProfiles = _videoProfilesH265;
}
else if (string.Equals("av1", targetVideoCodec, StringComparison.OrdinalIgnoreCase))
{
videoProfiles = _videoProfilesAv1;
}
if (!videoProfiles.Contains(profile, StringComparison.OrdinalIgnoreCase))
{
profile = string.Empty;
}
// We only transcode to HEVC 8-bit for now, force Main Profile.
if (profile.Contains("main10", StringComparison.OrdinalIgnoreCase)

View File

@@ -284,7 +284,7 @@ namespace MediaBrowser.MediaEncoding.Attachments
if (extractableAttachmentIds.Count > 0)
{
await CacheAllAttachmentsInternal(mediaPath, inputFile, mediaSource, extractableAttachmentIds, cancellationToken).ConfigureAwait(false);
await CacheAllAttachmentsInternal(mediaPath, _mediaEncoder.GetInputArgument(inputFile, mediaSource), mediaSource, extractableAttachmentIds, cancellationToken).ConfigureAwait(false);
}
}
catch (Exception ex)
@@ -323,7 +323,7 @@ namespace MediaBrowser.MediaEncoding.Attachments
processArgs += string.Format(
CultureInfo.InvariantCulture,
" -i \"{0}\" -t 0 -f null null",
" -i {0} -t 0 -f null null",
inputFile);
int exitCode;

View File

@@ -625,7 +625,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
{
try
{
return await ExtractImageInternal(inputArgument, container, videoStream, imageStreamIndex, threedFormat, offset, true, targetFormat, cancellationToken).ConfigureAwait(false);
return await ExtractImageInternal(inputArgument, container, videoStream, imageStreamIndex, threedFormat, offset, true, targetFormat, false, cancellationToken).ConfigureAwait(false);
}
catch (ArgumentException)
{
@@ -637,7 +637,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
}
}
return await ExtractImageInternal(inputArgument, container, videoStream, imageStreamIndex, threedFormat, offset, false, targetFormat, cancellationToken).ConfigureAwait(false);
return await ExtractImageInternal(inputArgument, container, videoStream, imageStreamIndex, threedFormat, offset, false, targetFormat, isAudio, cancellationToken).ConfigureAwait(false);
}
private string GetImageResolutionParameter()
@@ -663,7 +663,17 @@ namespace MediaBrowser.MediaEncoding.Encoder
return imageResolutionParameter;
}
private async Task<string> ExtractImageInternal(string inputPath, string container, MediaStream videoStream, int? imageStreamIndex, Video3DFormat? threedFormat, TimeSpan? offset, bool useIFrame, ImageFormat? targetFormat, CancellationToken cancellationToken)
private async Task<string> ExtractImageInternal(
string inputPath,
string container,
MediaStream videoStream,
int? imageStreamIndex,
Video3DFormat? threedFormat,
TimeSpan? offset,
bool useIFrame,
ImageFormat? targetFormat,
bool isAudio,
CancellationToken cancellationToken)
{
ArgumentException.ThrowIfNullOrEmpty(inputPath);
@@ -722,7 +732,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
var vf = string.Join(',', filters);
var mapArg = imageStreamIndex.HasValue ? (" -map 0:" + imageStreamIndex.Value.ToString(CultureInfo.InvariantCulture)) : string.Empty;
var args = string.Format(CultureInfo.InvariantCulture, "-i {0}{3} -threads {4} -v quiet -vframes 1 -vf {2}{5} -f image2 \"{1}\"", inputPath, tempExtractPath, vf, mapArg, _threads, GetImageResolutionParameter());
var args = string.Format(CultureInfo.InvariantCulture, "-i {0}{3} -threads {4} -v quiet -vframes 1 -vf {2}{5} -f image2 \"{1}\"", inputPath, tempExtractPath, vf, mapArg, _threads, isAudio ? string.Empty : GetImageResolutionParameter());
if (offset.HasValue)
{
@@ -1197,7 +1207,8 @@ namespace MediaBrowser.MediaEncoding.Encoder
}
// Generate concat configuration entries for each file and write to file
using StreamWriter sw = new StreamWriter(concatFilePath);
Directory.CreateDirectory(Path.GetDirectoryName(concatFilePath));
using StreamWriter sw = new FormattingStreamWriter(concatFilePath, CultureInfo.InvariantCulture);
foreach (var path in files)
{
var mediaInfoResult = GetMediaInfo(

View File

@@ -501,11 +501,11 @@ namespace MediaBrowser.MediaEncoding.Subtitles
List<MediaStream> subtitleStreams,
CancellationToken cancellationToken)
{
var inputPath = mediaSource.Path;
var inputPath = _mediaEncoder.GetInputArgument(mediaSource.Path, mediaSource);
var outputPaths = new List<string>();
var args = string.Format(
CultureInfo.InvariantCulture,
"-i \"{0}\" -copyts",
"-i {0} -copyts",
inputPath);
foreach (var subtitleStream in subtitleStreams)
@@ -676,7 +676,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles
var processArgs = string.Format(
CultureInfo.InvariantCulture,
"-i \"{0}\" -copyts -map 0:{1} -an -vn -c:s {2} \"{3}\"",
"-i {0} -copyts -map 0:{1} -an -vn -c:s {2} \"{3}\"",
inputPath,
subtitleStreamIndex,
outputCodec,

View File

@@ -858,7 +858,7 @@ namespace MediaBrowser.Model.Dlna
{
audioStream = directAudioStream;
playlistItem.AudioStreamIndex = audioStream.Index;
playlistItem.AudioCodecs = new[] { audioStream.Codec };
playlistItem.AudioCodecs = audioCodecs = new[] { audioStream.Codec };
// Copy matching audio codec options
playlistItem.AudioSampleRate = audioStream.SampleRate;
@@ -897,15 +897,14 @@ namespace MediaBrowser.Model.Dlna
var appliedVideoConditions = options.Profile.CodecProfiles
.Where(i => i.Type == CodecType.Video &&
i.ContainsAnyCodec(videoStream?.Codec, container) &&
i.ContainsAnyCodec(videoCodecs, container) &&
i.ApplyConditions.All(applyCondition => ConditionProcessor.IsVideoConditionSatisfied(applyCondition, width, height, bitDepth, videoBitrate, videoProfile, videoRangeType, videoLevel, videoFramerate, packetLength, timestamp, isAnamorphic, isInterlaced, refFrames, numVideoStreams, numAudioStreams, videoCodecTag, isAvc)))
// Reverse codec profiles for backward compatibility - first codec profile has higher priority
.Reverse();
foreach (var i in appliedVideoConditions)
{
var transcodingVideoCodecs = ContainerProfile.SplitValue(videoCodec);
foreach (var transcodingVideoCodec in transcodingVideoCodecs)
foreach (var transcodingVideoCodec in videoCodecs)
{
if (i.ContainsAnyCodec(transcodingVideoCodec, container))
{
@@ -930,15 +929,14 @@ namespace MediaBrowser.Model.Dlna
var appliedAudioConditions = options.Profile.CodecProfiles
.Where(i => i.Type == CodecType.VideoAudio &&
i.ContainsAnyCodec(audioStream?.Codec, container) &&
i.ContainsAnyCodec(audioCodecs, container) &&
i.ApplyConditions.All(applyCondition => ConditionProcessor.IsVideoAudioConditionSatisfied(applyCondition, audioChannels, inputAudioBitrate, inputAudioSampleRate, inputAudioBitDepth, audioProfile, isSecondaryAudio)))
// Reverse codec profiles for backward compatibility - first codec profile has higher priority
.Reverse();
foreach (var codecProfile in appliedAudioConditions)
{
var transcodingAudioCodecs = ContainerProfile.SplitValue(audioCodec);
foreach (var transcodingAudioCodec in transcodingAudioCodecs)
foreach (var transcodingAudioCodec in audioCodecs)
{
if (codecProfile.ContainsAnyCodec(transcodingAudioCodec, container))
{

View File

@@ -8,7 +8,7 @@
<PropertyGroup>
<Authors>Jellyfin Contributors</Authors>
<PackageId>Jellyfin.Model</PackageId>
<VersionPrefix>10.9.10</VersionPrefix>
<VersionPrefix>10.9.11</VersionPrefix>
<RepositoryUrl>https://github.com/jellyfin/jellyfin</RepositoryUrl>
<PackageLicenseExpression>GPL-3.0-only</PackageLicenseExpression>
</PropertyGroup>

View File

@@ -1,4 +1,4 @@
using System.Reflection;
[assembly: AssemblyVersion("10.9.10")]
[assembly: AssemblyFileVersion("10.9.10")]
[assembly: AssemblyVersion("10.9.11")]
[assembly: AssemblyFileVersion("10.9.11")]

View File

@@ -0,0 +1,38 @@
using System;
using System.IO;
namespace Jellyfin.Extensions;
/// <summary>
/// A custom StreamWriter which supports setting a IFormatProvider.
/// </summary>
public class FormattingStreamWriter : StreamWriter
{
private readonly IFormatProvider _formatProvider;
/// <summary>
/// Initializes a new instance of the <see cref="FormattingStreamWriter"/> class.
/// </summary>
/// <param name="stream">The stream to write to.</param>
/// <param name="formatProvider">The format provider to use.</param>
public FormattingStreamWriter(Stream stream, IFormatProvider formatProvider)
: base(stream)
{
_formatProvider = formatProvider;
}
/// <summary>
/// Initializes a new instance of the <see cref="FormattingStreamWriter"/> class.
/// </summary>
/// <param name="path">The complete file path to write to.</param>
/// <param name="formatProvider">The format provider to use.</param>
public FormattingStreamWriter(string path, IFormatProvider formatProvider)
: base(path)
{
_formatProvider = formatProvider;
}
/// <inheritdoc />
public override IFormatProvider FormatProvider
=> _formatProvider;
}

View File

@@ -15,7 +15,7 @@
<PropertyGroup>
<Authors>Jellyfin Contributors</Authors>
<PackageId>Jellyfin.Extensions</PackageId>
<VersionPrefix>10.9.10</VersionPrefix>
<VersionPrefix>10.9.11</VersionPrefix>
<RepositoryUrl>https://github.com/jellyfin/jellyfin</RepositoryUrl>
<PackageLicenseExpression>GPL-3.0-only</PackageLicenseExpression>
</PropertyGroup>

View File

@@ -1,4 +1,7 @@
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
using MediaBrowser.Model.MediaInfo;
using Moq;
using Xunit;
namespace Jellyfin.Controller.Tests.Entities;
@@ -14,4 +17,30 @@ public class BaseItemTests
[InlineData("1test 2", "0000000001test 0000000002")]
public void BaseItem_ModifySortChunks_Valid(string input, string expected)
=> Assert.Equal(expected, BaseItem.ModifySortChunks(input));
[Theory]
[InlineData("/Movies/Ted/Ted.mp4", "/Movies/Ted/Ted - Unrated Edition.mp4", "Ted", "Unrated Edition")]
[InlineData("/Movies/Deadpool 2 (2018)/Deadpool 2 (2018).mkv", "/Movies/Deadpool 2 (2018)/Deadpool 2 (2018) - Super Duper Cut.mkv", "Deadpool 2 (2018)", "Super Duper Cut")]
public void GetMediaSourceName_Valid(string primaryPath, string altPath, string name, string altName)
{
var mediaSourceManager = new Mock<IMediaSourceManager>();
mediaSourceManager.Setup(x => x.GetPathProtocol(It.IsAny<string>()))
.Returns((string x) => MediaProtocol.File);
BaseItem.MediaSourceManager = mediaSourceManager.Object;
var video = new Video()
{
Path = primaryPath
};
var videoAlt = new Video()
{
Path = altPath,
};
video.LocalAlternateVersions = [videoAlt.Path];
Assert.Equal(name, video.GetMediaSourceName(video));
Assert.Equal(altName, video.GetMediaSourceName(videoAlt));
}
}

View File

@@ -0,0 +1,23 @@
using System.Globalization;
using System.IO;
using System.Text;
using System.Threading;
using Xunit;
namespace Jellyfin.Extensions.Tests;
public static class FormattingStreamWriterTests
{
[Fact]
public static void Shuffle_Valid_Correct()
{
Thread.CurrentThread.CurrentCulture = new CultureInfo("de-DE", false);
using (var ms = new MemoryStream())
using (var txt = new FormattingStreamWriter(ms, CultureInfo.InvariantCulture))
{
txt.Write("{0}", 3.14159);
txt.Close();
Assert.Equal("3.14159", Encoding.UTF8.GetString(ms.ToArray()));
}
}
}