Compare commits
13 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 7bbdfc0d49 | |||
| 3c3ebe8344 | |||
| 8c4d23435e | |||
| 9e4befa52e | |||
| b3efae71c0 | |||
| 70f4f2e8c2 | |||
| cd2f2ca178 | |||
| 8095d39954 | |||
| e1ac30ba17 | |||
| 3b94cfa837 | |||
| 2fe13f54ea | |||
| eb6a6d319b | |||
| b74c9cae1b |
@@ -36,7 +36,7 @@
|
|||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<Authors>Jellyfin Contributors</Authors>
|
<Authors>Jellyfin Contributors</Authors>
|
||||||
<PackageId>Jellyfin.Naming</PackageId>
|
<PackageId>Jellyfin.Naming</PackageId>
|
||||||
<VersionPrefix>10.9.10</VersionPrefix>
|
<VersionPrefix>10.9.11</VersionPrefix>
|
||||||
<RepositoryUrl>https://github.com/jellyfin/jellyfin</RepositoryUrl>
|
<RepositoryUrl>https://github.com/jellyfin/jellyfin</RepositoryUrl>
|
||||||
<PackageLicenseExpression>GPL-3.0-only</PackageLicenseExpression>
|
<PackageLicenseExpression>GPL-3.0-only</PackageLicenseExpression>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<Authors>Jellyfin Contributors</Authors>
|
<Authors>Jellyfin Contributors</Authors>
|
||||||
<PackageId>Jellyfin.Data</PackageId>
|
<PackageId>Jellyfin.Data</PackageId>
|
||||||
<VersionPrefix>10.9.10</VersionPrefix>
|
<VersionPrefix>10.9.11</VersionPrefix>
|
||||||
<RepositoryUrl>https://github.com/jellyfin/jellyfin</RepositoryUrl>
|
<RepositoryUrl>https://github.com/jellyfin/jellyfin</RepositoryUrl>
|
||||||
<PackageLicenseExpression>GPL-3.0-only</PackageLicenseExpression>
|
<PackageLicenseExpression>GPL-3.0-only</PackageLicenseExpression>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<Authors>Jellyfin Contributors</Authors>
|
<Authors>Jellyfin Contributors</Authors>
|
||||||
<PackageId>Jellyfin.Common</PackageId>
|
<PackageId>Jellyfin.Common</PackageId>
|
||||||
<VersionPrefix>10.9.10</VersionPrefix>
|
<VersionPrefix>10.9.11</VersionPrefix>
|
||||||
<RepositoryUrl>https://github.com/jellyfin/jellyfin</RepositoryUrl>
|
<RepositoryUrl>https://github.com/jellyfin/jellyfin</RepositoryUrl>
|
||||||
<PackageLicenseExpression>GPL-3.0-only</PackageLicenseExpression>
|
<PackageLicenseExpression>GPL-3.0-only</PackageLicenseExpression>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|||||||
@@ -1180,28 +1180,29 @@ namespace MediaBrowser.Controller.Entities
|
|||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
|
|
||||||
private string GetMediaSourceName(BaseItem item)
|
internal string GetMediaSourceName(BaseItem item)
|
||||||
{
|
{
|
||||||
var terms = new List<string>();
|
var terms = new List<string>();
|
||||||
|
|
||||||
var path = item.Path;
|
var path = item.Path;
|
||||||
if (item.IsFileProtocol && !string.IsNullOrEmpty(path))
|
if (item.IsFileProtocol && !string.IsNullOrEmpty(path))
|
||||||
{
|
{
|
||||||
|
var displayName = System.IO.Path.GetFileNameWithoutExtension(path);
|
||||||
if (HasLocalAlternateVersions)
|
if (HasLocalAlternateVersions)
|
||||||
{
|
{
|
||||||
var displayName = System.IO.Path.GetFileNameWithoutExtension(path)
|
var containingFolderName = System.IO.Path.GetFileName(ContainingFolderPath);
|
||||||
.Replace(System.IO.Path.GetFileName(ContainingFolderPath), string.Empty, StringComparison.OrdinalIgnoreCase)
|
if (displayName.Length > containingFolderName.Length && displayName.StartsWith(containingFolderName, StringComparison.OrdinalIgnoreCase))
|
||||||
.TrimStart(new char[] { ' ', '-' });
|
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(displayName))
|
|
||||||
{
|
{
|
||||||
terms.Add(displayName);
|
var name = displayName.AsSpan(containingFolderName.Length).TrimStart([' ', '-']);
|
||||||
|
if (!name.IsWhiteSpace())
|
||||||
|
{
|
||||||
|
terms.Add(name.ToString());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (terms.Count == 0)
|
if (terms.Count == 0)
|
||||||
{
|
{
|
||||||
var displayName = System.IO.Path.GetFileNameWithoutExtension(path);
|
|
||||||
terms.Add(displayName);
|
terms.Add(displayName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -180,10 +180,7 @@ namespace MediaBrowser.Controller.Entities.TV
|
|||||||
}
|
}
|
||||||
|
|
||||||
public string FindSeriesPresentationUniqueKey()
|
public string FindSeriesPresentationUniqueKey()
|
||||||
{
|
=> Series?.PresentationUniqueKey;
|
||||||
var series = Series;
|
|
||||||
return series is null ? null : series.PresentationUniqueKey;
|
|
||||||
}
|
|
||||||
|
|
||||||
public string FindSeasonName()
|
public string FindSeasonName()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -430,8 +430,6 @@ namespace MediaBrowser.Controller.Entities
|
|||||||
InternalItemsQuery query,
|
InternalItemsQuery query,
|
||||||
ILibraryManager libraryManager)
|
ILibraryManager libraryManager)
|
||||||
{
|
{
|
||||||
var user = query.User;
|
|
||||||
|
|
||||||
// This must be the last filter
|
// This must be the last filter
|
||||||
if (!query.AdjacentTo.IsNullOrEmpty())
|
if (!query.AdjacentTo.IsNullOrEmpty())
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<Authors>Jellyfin Contributors</Authors>
|
<Authors>Jellyfin Contributors</Authors>
|
||||||
<PackageId>Jellyfin.Controller</PackageId>
|
<PackageId>Jellyfin.Controller</PackageId>
|
||||||
<VersionPrefix>10.9.10</VersionPrefix>
|
<VersionPrefix>10.9.11</VersionPrefix>
|
||||||
<RepositoryUrl>https://github.com/jellyfin/jellyfin</RepositoryUrl>
|
<RepositoryUrl>https://github.com/jellyfin/jellyfin</RepositoryUrl>
|
||||||
<PackageLicenseExpression>GPL-3.0-only</PackageLicenseExpression>
|
<PackageLicenseExpression>GPL-3.0-only</PackageLicenseExpression>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|||||||
@@ -2005,7 +2005,26 @@ namespace MediaBrowser.Controller.MediaEncoding
|
|||||||
}
|
}
|
||||||
|
|
||||||
var profile = state.GetRequestedProfiles(targetVideoCodec).FirstOrDefault() ?? string.Empty;
|
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.
|
// We only transcode to HEVC 8-bit for now, force Main Profile.
|
||||||
if (profile.Contains("main10", StringComparison.OrdinalIgnoreCase)
|
if (profile.Contains("main10", StringComparison.OrdinalIgnoreCase)
|
||||||
|
|||||||
@@ -284,7 +284,7 @@ namespace MediaBrowser.MediaEncoding.Attachments
|
|||||||
|
|
||||||
if (extractableAttachmentIds.Count > 0)
|
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)
|
catch (Exception ex)
|
||||||
@@ -323,7 +323,7 @@ namespace MediaBrowser.MediaEncoding.Attachments
|
|||||||
|
|
||||||
processArgs += string.Format(
|
processArgs += string.Format(
|
||||||
CultureInfo.InvariantCulture,
|
CultureInfo.InvariantCulture,
|
||||||
" -i \"{0}\" -t 0 -f null null",
|
" -i {0} -t 0 -f null null",
|
||||||
inputFile);
|
inputFile);
|
||||||
|
|
||||||
int exitCode;
|
int exitCode;
|
||||||
|
|||||||
@@ -625,7 +625,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
|||||||
{
|
{
|
||||||
try
|
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)
|
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()
|
private string GetImageResolutionParameter()
|
||||||
@@ -663,7 +663,17 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
|||||||
return imageResolutionParameter;
|
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);
|
ArgumentException.ThrowIfNullOrEmpty(inputPath);
|
||||||
|
|
||||||
@@ -722,7 +732,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
|||||||
|
|
||||||
var vf = string.Join(',', filters);
|
var vf = string.Join(',', filters);
|
||||||
var mapArg = imageStreamIndex.HasValue ? (" -map 0:" + imageStreamIndex.Value.ToString(CultureInfo.InvariantCulture)) : string.Empty;
|
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)
|
if (offset.HasValue)
|
||||||
{
|
{
|
||||||
@@ -1197,7 +1207,8 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Generate concat configuration entries for each file and write to file
|
// 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)
|
foreach (var path in files)
|
||||||
{
|
{
|
||||||
var mediaInfoResult = GetMediaInfo(
|
var mediaInfoResult = GetMediaInfo(
|
||||||
|
|||||||
@@ -501,11 +501,11 @@ namespace MediaBrowser.MediaEncoding.Subtitles
|
|||||||
List<MediaStream> subtitleStreams,
|
List<MediaStream> subtitleStreams,
|
||||||
CancellationToken cancellationToken)
|
CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var inputPath = mediaSource.Path;
|
var inputPath = _mediaEncoder.GetInputArgument(mediaSource.Path, mediaSource);
|
||||||
var outputPaths = new List<string>();
|
var outputPaths = new List<string>();
|
||||||
var args = string.Format(
|
var args = string.Format(
|
||||||
CultureInfo.InvariantCulture,
|
CultureInfo.InvariantCulture,
|
||||||
"-i \"{0}\" -copyts",
|
"-i {0} -copyts",
|
||||||
inputPath);
|
inputPath);
|
||||||
|
|
||||||
foreach (var subtitleStream in subtitleStreams)
|
foreach (var subtitleStream in subtitleStreams)
|
||||||
@@ -676,7 +676,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles
|
|||||||
|
|
||||||
var processArgs = string.Format(
|
var processArgs = string.Format(
|
||||||
CultureInfo.InvariantCulture,
|
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,
|
inputPath,
|
||||||
subtitleStreamIndex,
|
subtitleStreamIndex,
|
||||||
outputCodec,
|
outputCodec,
|
||||||
|
|||||||
@@ -858,7 +858,7 @@ namespace MediaBrowser.Model.Dlna
|
|||||||
{
|
{
|
||||||
audioStream = directAudioStream;
|
audioStream = directAudioStream;
|
||||||
playlistItem.AudioStreamIndex = audioStream.Index;
|
playlistItem.AudioStreamIndex = audioStream.Index;
|
||||||
playlistItem.AudioCodecs = new[] { audioStream.Codec };
|
playlistItem.AudioCodecs = audioCodecs = new[] { audioStream.Codec };
|
||||||
|
|
||||||
// Copy matching audio codec options
|
// Copy matching audio codec options
|
||||||
playlistItem.AudioSampleRate = audioStream.SampleRate;
|
playlistItem.AudioSampleRate = audioStream.SampleRate;
|
||||||
@@ -897,15 +897,14 @@ namespace MediaBrowser.Model.Dlna
|
|||||||
|
|
||||||
var appliedVideoConditions = options.Profile.CodecProfiles
|
var appliedVideoConditions = options.Profile.CodecProfiles
|
||||||
.Where(i => i.Type == CodecType.Video &&
|
.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)))
|
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 codec profiles for backward compatibility - first codec profile has higher priority
|
||||||
.Reverse();
|
.Reverse();
|
||||||
|
|
||||||
foreach (var i in appliedVideoConditions)
|
foreach (var i in appliedVideoConditions)
|
||||||
{
|
{
|
||||||
var transcodingVideoCodecs = ContainerProfile.SplitValue(videoCodec);
|
foreach (var transcodingVideoCodec in videoCodecs)
|
||||||
foreach (var transcodingVideoCodec in transcodingVideoCodecs)
|
|
||||||
{
|
{
|
||||||
if (i.ContainsAnyCodec(transcodingVideoCodec, container))
|
if (i.ContainsAnyCodec(transcodingVideoCodec, container))
|
||||||
{
|
{
|
||||||
@@ -930,15 +929,14 @@ namespace MediaBrowser.Model.Dlna
|
|||||||
|
|
||||||
var appliedAudioConditions = options.Profile.CodecProfiles
|
var appliedAudioConditions = options.Profile.CodecProfiles
|
||||||
.Where(i => i.Type == CodecType.VideoAudio &&
|
.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)))
|
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 codec profiles for backward compatibility - first codec profile has higher priority
|
||||||
.Reverse();
|
.Reverse();
|
||||||
|
|
||||||
foreach (var codecProfile in appliedAudioConditions)
|
foreach (var codecProfile in appliedAudioConditions)
|
||||||
{
|
{
|
||||||
var transcodingAudioCodecs = ContainerProfile.SplitValue(audioCodec);
|
foreach (var transcodingAudioCodec in audioCodecs)
|
||||||
foreach (var transcodingAudioCodec in transcodingAudioCodecs)
|
|
||||||
{
|
{
|
||||||
if (codecProfile.ContainsAnyCodec(transcodingAudioCodec, container))
|
if (codecProfile.ContainsAnyCodec(transcodingAudioCodec, container))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<Authors>Jellyfin Contributors</Authors>
|
<Authors>Jellyfin Contributors</Authors>
|
||||||
<PackageId>Jellyfin.Model</PackageId>
|
<PackageId>Jellyfin.Model</PackageId>
|
||||||
<VersionPrefix>10.9.10</VersionPrefix>
|
<VersionPrefix>10.9.11</VersionPrefix>
|
||||||
<RepositoryUrl>https://github.com/jellyfin/jellyfin</RepositoryUrl>
|
<RepositoryUrl>https://github.com/jellyfin/jellyfin</RepositoryUrl>
|
||||||
<PackageLicenseExpression>GPL-3.0-only</PackageLicenseExpression>
|
<PackageLicenseExpression>GPL-3.0-only</PackageLicenseExpression>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|||||||
+2
-2
@@ -1,4 +1,4 @@
|
|||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
|
||||||
[assembly: AssemblyVersion("10.9.10")]
|
[assembly: AssemblyVersion("10.9.11")]
|
||||||
[assembly: AssemblyFileVersion("10.9.10")]
|
[assembly: AssemblyFileVersion("10.9.11")]
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -15,7 +15,7 @@
|
|||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<Authors>Jellyfin Contributors</Authors>
|
<Authors>Jellyfin Contributors</Authors>
|
||||||
<PackageId>Jellyfin.Extensions</PackageId>
|
<PackageId>Jellyfin.Extensions</PackageId>
|
||||||
<VersionPrefix>10.9.10</VersionPrefix>
|
<VersionPrefix>10.9.11</VersionPrefix>
|
||||||
<RepositoryUrl>https://github.com/jellyfin/jellyfin</RepositoryUrl>
|
<RepositoryUrl>https://github.com/jellyfin/jellyfin</RepositoryUrl>
|
||||||
<PackageLicenseExpression>GPL-3.0-only</PackageLicenseExpression>
|
<PackageLicenseExpression>GPL-3.0-only</PackageLicenseExpression>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|||||||
@@ -1,4 +1,7 @@
|
|||||||
using MediaBrowser.Controller.Entities;
|
using MediaBrowser.Controller.Entities;
|
||||||
|
using MediaBrowser.Controller.Library;
|
||||||
|
using MediaBrowser.Model.MediaInfo;
|
||||||
|
using Moq;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
namespace Jellyfin.Controller.Tests.Entities;
|
namespace Jellyfin.Controller.Tests.Entities;
|
||||||
@@ -14,4 +17,30 @@ public class BaseItemTests
|
|||||||
[InlineData("1test 2", "0000000001test 0000000002")]
|
[InlineData("1test 2", "0000000001test 0000000002")]
|
||||||
public void BaseItem_ModifySortChunks_Valid(string input, string expected)
|
public void BaseItem_ModifySortChunks_Valid(string input, string expected)
|
||||||
=> Assert.Equal(expected, BaseItem.ModifySortChunks(input));
|
=> 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));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user