aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Jellyfin.Extensions/Jellyfin.Extensions.csproj4
-rw-r--r--src/Jellyfin.Extensions/Json/Converters/JsonFlagEnumConverter.cs36
-rw-r--r--src/Jellyfin.Extensions/Json/Converters/JsonFlagEnumConverterFactory.cs24
-rw-r--r--src/Jellyfin.Extensions/Json/Converters/JsonNullableGuidConverter.cs7
-rw-r--r--src/Jellyfin.Extensions/Json/JsonDefaults.cs1
-rw-r--r--src/Jellyfin.Extensions/ReadOnlyListExtension.cs16
-rw-r--r--src/Jellyfin.Extensions/SplitStringExtensions.cs2
-rw-r--r--src/Jellyfin.Extensions/StringExtensions.cs42
-rw-r--r--src/Jellyfin.MediaEncoding.Hls/Jellyfin.MediaEncoding.Hls.csproj2
-rw-r--r--src/Jellyfin.MediaEncoding.Hls/Playlist/CreateMainPlaylistRequest.cs9
-rw-r--r--src/Jellyfin.MediaEncoding.Hls/Playlist/DynamicHlsPlaylistGenerator.cs3
-rw-r--r--src/Jellyfin.MediaEncoding.Keyframes/Jellyfin.MediaEncoding.Keyframes.csproj4
12 files changed, 139 insertions, 11 deletions
diff --git a/src/Jellyfin.Extensions/Jellyfin.Extensions.csproj b/src/Jellyfin.Extensions/Jellyfin.Extensions.csproj
index 37baff5ae..f99cb0406 100644
--- a/src/Jellyfin.Extensions/Jellyfin.Extensions.csproj
+++ b/src/Jellyfin.Extensions/Jellyfin.Extensions.csproj
@@ -13,7 +13,7 @@
<PropertyGroup>
<Authors>Jellyfin Contributors</Authors>
<PackageId>Jellyfin.Extensions</PackageId>
- <VersionPrefix>10.8.0</VersionPrefix>
+ <VersionPrefix>10.9.0</VersionPrefix>
<RepositoryUrl>https://github.com/jellyfin/jellyfin</RepositoryUrl>
<PackageLicenseExpression>GPL-3.0-only</PackageLicenseExpression>
</PropertyGroup>
@@ -34,7 +34,7 @@
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
<PackageReference Include="SerilogAnalyzer" Version="0.15.0" PrivateAssets="All" />
- <PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.376" PrivateAssets="All" />
+ <PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.435" PrivateAssets="All" />
<PackageReference Include="SmartAnalyzers.MultithreadingAnalyzer" Version="1.1.31" PrivateAssets="All" />
</ItemGroup>
diff --git a/src/Jellyfin.Extensions/Json/Converters/JsonFlagEnumConverter.cs b/src/Jellyfin.Extensions/Json/Converters/JsonFlagEnumConverter.cs
new file mode 100644
index 000000000..4fa91fa5e
--- /dev/null
+++ b/src/Jellyfin.Extensions/Json/Converters/JsonFlagEnumConverter.cs
@@ -0,0 +1,36 @@
+using System;
+using System.Text.Json;
+using System.Text.Json.Serialization;
+
+namespace Jellyfin.Extensions.Json.Converters;
+
+/// <summary>
+/// Enum flag to json array converter.
+/// </summary>
+/// <typeparam name="T">The type of enum.</typeparam>
+public class JsonFlagEnumConverter<T> : JsonConverter<T>
+ where T : struct, Enum
+{
+ private static readonly T[] _enumValues = Enum.GetValues<T>();
+
+ /// <inheritdoc />
+ public override T Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
+ {
+ throw new NotImplementedException();
+ }
+
+ /// <inheritdoc />
+ public override void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions options)
+ {
+ writer.WriteStartArray();
+ foreach (var enumValue in _enumValues)
+ {
+ if (value.HasFlag(enumValue))
+ {
+ writer.WriteStringValue(enumValue.ToString());
+ }
+ }
+
+ writer.WriteEndArray();
+ }
+}
diff --git a/src/Jellyfin.Extensions/Json/Converters/JsonFlagEnumConverterFactory.cs b/src/Jellyfin.Extensions/Json/Converters/JsonFlagEnumConverterFactory.cs
new file mode 100644
index 000000000..b74caf345
--- /dev/null
+++ b/src/Jellyfin.Extensions/Json/Converters/JsonFlagEnumConverterFactory.cs
@@ -0,0 +1,24 @@
+using System;
+using System.Reflection;
+using System.Text.Json;
+using System.Text.Json.Serialization;
+
+namespace Jellyfin.Extensions.Json.Converters;
+
+/// <summary>
+/// Json flag enum converter factory.
+/// </summary>
+public class JsonFlagEnumConverterFactory : JsonConverterFactory
+{
+ /// <inheritdoc />
+ public override bool CanConvert(Type typeToConvert)
+ {
+ return typeToConvert.IsEnum && typeToConvert.IsDefined(typeof(FlagsAttribute));
+ }
+
+ /// <inheritdoc />
+ public override JsonConverter? CreateConverter(Type typeToConvert, JsonSerializerOptions options)
+ {
+ return (JsonConverter?)Activator.CreateInstance(typeof(JsonFlagEnumConverter<>).MakeGenericType(typeToConvert));
+ }
+}
diff --git a/src/Jellyfin.Extensions/Json/Converters/JsonNullableGuidConverter.cs b/src/Jellyfin.Extensions/Json/Converters/JsonNullableGuidConverter.cs
index b477bcb66..656e3c3da 100644
--- a/src/Jellyfin.Extensions/Json/Converters/JsonNullableGuidConverter.cs
+++ b/src/Jellyfin.Extensions/Json/Converters/JsonNullableGuidConverter.cs
@@ -16,14 +16,15 @@ namespace Jellyfin.Extensions.Json.Converters
/// <inheritdoc />
public override void Write(Utf8JsonWriter writer, Guid? value, JsonSerializerOptions options)
{
- if (value == Guid.Empty)
+ // null got handled higher up the call stack
+ var val = value!.Value;
+ if (val.Equals(default))
{
writer.WriteNullValue();
}
else
{
- // null got handled higher up the call stack
- JsonGuidConverter.WriteInternal(writer, value!.Value);
+ JsonGuidConverter.WriteInternal(writer, val);
}
}
}
diff --git a/src/Jellyfin.Extensions/Json/JsonDefaults.cs b/src/Jellyfin.Extensions/Json/JsonDefaults.cs
index 2cd89dc3b..97cbee971 100644
--- a/src/Jellyfin.Extensions/Json/JsonDefaults.cs
+++ b/src/Jellyfin.Extensions/Json/JsonDefaults.cs
@@ -36,6 +36,7 @@ namespace Jellyfin.Extensions.Json
new JsonGuidConverter(),
new JsonNullableGuidConverter(),
new JsonVersionConverter(),
+ new JsonFlagEnumConverterFactory(),
new JsonStringEnumConverter(),
new JsonNullableStructConverterFactory(),
new JsonBoolNumberConverter(),
diff --git a/src/Jellyfin.Extensions/ReadOnlyListExtension.cs b/src/Jellyfin.Extensions/ReadOnlyListExtension.cs
index 7785cfb49..ba99bb534 100644
--- a/src/Jellyfin.Extensions/ReadOnlyListExtension.cs
+++ b/src/Jellyfin.Extensions/ReadOnlyListExtension.cs
@@ -57,5 +57,21 @@ namespace Jellyfin.Extensions
return -1;
}
+
+ /// <summary>
+ /// Get the first or default item from a list.
+ /// </summary>
+ /// <param name="source">The source list.</param>
+ /// <typeparam name="T">The type of item.</typeparam>
+ /// <returns>The first item or default if list is empty.</returns>
+ public static T? FirstOrDefault<T>(this IReadOnlyList<T>? source)
+ {
+ if (source is null || source.Count == 0)
+ {
+ return default;
+ }
+
+ return source[0];
+ }
}
}
diff --git a/src/Jellyfin.Extensions/SplitStringExtensions.cs b/src/Jellyfin.Extensions/SplitStringExtensions.cs
index 1d1c377f5..a4dc9fc6b 100644
--- a/src/Jellyfin.Extensions/SplitStringExtensions.cs
+++ b/src/Jellyfin.Extensions/SplitStringExtensions.cs
@@ -55,7 +55,7 @@ namespace Jellyfin.Extensions
public static Enumerator Split(this ReadOnlySpan<char> str, char separator) => new(str, separator);
/// <summary>
- /// Provides an enumerator for the substrings seperated by the separator.
+ /// Provides an enumerator for the substrings separated by the separator.
/// </summary>
[StructLayout(LayoutKind.Auto)]
public ref struct Enumerator
diff --git a/src/Jellyfin.Extensions/StringExtensions.cs b/src/Jellyfin.Extensions/StringExtensions.cs
index 3a7707253..59fb038a7 100644
--- a/src/Jellyfin.Extensions/StringExtensions.cs
+++ b/src/Jellyfin.Extensions/StringExtensions.cs
@@ -1,4 +1,8 @@
using System;
+using System.Diagnostics;
+using System.Globalization;
+using System.Text;
+using System.Text.RegularExpressions;
namespace Jellyfin.Extensions
{
@@ -7,6 +11,44 @@ namespace Jellyfin.Extensions
/// </summary>
public static class StringExtensions
{
+ // Matches non-conforming unicode chars
+ // https://mnaoumov.wordpress.com/2014/06/14/stripping-invalid-characters-from-utf-16-strings/
+ private static readonly Regex _nonConformingUnicode = new Regex("([\ud800-\udbff](?![\udc00-\udfff]))|((?<![\ud800-\udbff])[\udc00-\udfff])|(\ufffd)");
+
+ /// <summary>
+ /// Removes the diacritics character from the strings.
+ /// </summary>
+ /// <param name="text">The string to act on.</param>
+ /// <returns>The string without diacritics character.</returns>
+ public static string RemoveDiacritics(this string text)
+ {
+ string withDiactritics = _nonConformingUnicode
+ .Replace(text, string.Empty)
+ .Normalize(NormalizationForm.FormD);
+
+ var withoutDiactritics = new StringBuilder();
+ foreach (char c in withDiactritics)
+ {
+ UnicodeCategory uc = CharUnicodeInfo.GetUnicodeCategory(c);
+ if (uc != UnicodeCategory.NonSpacingMark)
+ {
+ withoutDiactritics.Append(c);
+ }
+ }
+
+ return withoutDiactritics.ToString().Normalize(NormalizationForm.FormC);
+ }
+
+ /// <summary>
+ /// Checks whether or not the specified string has diacritics in it.
+ /// </summary>
+ /// <param name="text">The string to check.</param>
+ /// <returns>True if the string has diacritics, false otherwise.</returns>
+ public static bool HasDiacritics(this string text)
+ {
+ return !string.Equals(text, text.RemoveDiacritics(), StringComparison.Ordinal);
+ }
+
/// <summary>
/// Counts the number of occurrences of [needle] in the string.
/// </summary>
diff --git a/src/Jellyfin.MediaEncoding.Hls/Jellyfin.MediaEncoding.Hls.csproj b/src/Jellyfin.MediaEncoding.Hls/Jellyfin.MediaEncoding.Hls.csproj
index 56f973a21..2ff7f9645 100644
--- a/src/Jellyfin.MediaEncoding.Hls/Jellyfin.MediaEncoding.Hls.csproj
+++ b/src/Jellyfin.MediaEncoding.Hls/Jellyfin.MediaEncoding.Hls.csproj
@@ -12,7 +12,7 @@
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
<PackageReference Include="SerilogAnalyzer" Version="0.15.0" PrivateAssets="All" />
- <PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.376" PrivateAssets="All" />
+ <PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.435" PrivateAssets="All" />
<PackageReference Include="SmartAnalyzers.MultithreadingAnalyzer" Version="1.1.31" PrivateAssets="All" />
</ItemGroup>
diff --git a/src/Jellyfin.MediaEncoding.Hls/Playlist/CreateMainPlaylistRequest.cs b/src/Jellyfin.MediaEncoding.Hls/Playlist/CreateMainPlaylistRequest.cs
index ac28ca26a..8572a5eae 100644
--- a/src/Jellyfin.MediaEncoding.Hls/Playlist/CreateMainPlaylistRequest.cs
+++ b/src/Jellyfin.MediaEncoding.Hls/Playlist/CreateMainPlaylistRequest.cs
@@ -14,7 +14,8 @@ public class CreateMainPlaylistRequest
/// <param name="segmentContainer">The desired segment container eg. "ts".</param>
/// <param name="endpointPrefix">The URI prefix for the relative URL in the playlist.</param>
/// <param name="queryString">The desired query string to append (must start with ?).</param>
- public CreateMainPlaylistRequest(string filePath, int desiredSegmentLengthMs, long totalRuntimeTicks, string segmentContainer, string endpointPrefix, string queryString)
+ /// <param name="isRemuxingVideo">Whether the video is being remuxed.</param>
+ public CreateMainPlaylistRequest(string filePath, int desiredSegmentLengthMs, long totalRuntimeTicks, string segmentContainer, string endpointPrefix, string queryString, bool isRemuxingVideo)
{
FilePath = filePath;
DesiredSegmentLengthMs = desiredSegmentLengthMs;
@@ -22,6 +23,7 @@ public class CreateMainPlaylistRequest
SegmentContainer = segmentContainer;
EndpointPrefix = endpointPrefix;
QueryString = queryString;
+ IsRemuxingVideo = isRemuxingVideo;
}
/// <summary>
@@ -53,4 +55,9 @@ public class CreateMainPlaylistRequest
/// Gets the query string.
/// </summary>
public string QueryString { get; }
+
+ /// <summary>
+ /// Gets a value indicating whether the video is being remuxed.
+ /// </summary>
+ public bool IsRemuxingVideo { get; }
}
diff --git a/src/Jellyfin.MediaEncoding.Hls/Playlist/DynamicHlsPlaylistGenerator.cs b/src/Jellyfin.MediaEncoding.Hls/Playlist/DynamicHlsPlaylistGenerator.cs
index 3382ba251..07a6d6050 100644
--- a/src/Jellyfin.MediaEncoding.Hls/Playlist/DynamicHlsPlaylistGenerator.cs
+++ b/src/Jellyfin.MediaEncoding.Hls/Playlist/DynamicHlsPlaylistGenerator.cs
@@ -34,7 +34,8 @@ public class DynamicHlsPlaylistGenerator : IDynamicHlsPlaylistGenerator
public string CreateMainPlaylist(CreateMainPlaylistRequest request)
{
IReadOnlyList<double> segments;
- if (TryExtractKeyframes(request.FilePath, out var keyframeData))
+ // For video transcodes it is sufficient with equal length segments as ffmpeg will create new keyframes
+ if (request.IsRemuxingVideo && TryExtractKeyframes(request.FilePath, out var keyframeData))
{
segments = ComputeSegments(keyframeData, request.DesiredSegmentLengthMs);
}
diff --git a/src/Jellyfin.MediaEncoding.Keyframes/Jellyfin.MediaEncoding.Keyframes.csproj b/src/Jellyfin.MediaEncoding.Keyframes/Jellyfin.MediaEncoding.Keyframes.csproj
index 31da11e24..29cdf561f 100644
--- a/src/Jellyfin.MediaEncoding.Keyframes/Jellyfin.MediaEncoding.Keyframes.csproj
+++ b/src/Jellyfin.MediaEncoding.Keyframes/Jellyfin.MediaEncoding.Keyframes.csproj
@@ -16,12 +16,12 @@
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
<PackageReference Include="SerilogAnalyzer" Version="0.15.0" PrivateAssets="All" />
- <PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.376" PrivateAssets="All" />
+ <PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.435" PrivateAssets="All" />
<PackageReference Include="SmartAnalyzers.MultithreadingAnalyzer" Version="1.1.31" PrivateAssets="All" />
</ItemGroup>
<ItemGroup>
- <PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="6.0.0" />
+ <PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="6.0.1" />
</ItemGroup>
<ItemGroup>