From 9ba91d4583f3671eaacae8e073fb53288f9b8715 Mon Sep 17 00:00:00 2001 From: Cody Robibero Date: Thu, 20 Aug 2026 18:10:50 -0400 Subject: Normalize fix, apply in more places --- src/Jellyfin.Extensions/StringExtensions.cs | 37 +++++++++++++++++++++++++++++ src/Jellyfin.LiveTv/IO/EncodedRecorder.cs | 4 ++-- 2 files changed, 39 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/Jellyfin.Extensions/StringExtensions.cs b/src/Jellyfin.Extensions/StringExtensions.cs index 906efbcbcc..38f1cf738f 100644 --- a/src/Jellyfin.Extensions/StringExtensions.cs +++ b/src/Jellyfin.Extensions/StringExtensions.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Text; using System.Text.RegularExpressions; using ICU4N.Text; @@ -173,5 +174,41 @@ namespace Jellyfin.Extensions return cleaned; } + + /// + /// Escapes an argument so that it survives command line parsing as a single argument when it is wrapped in double quotes by the caller. + /// + /// The argument to escape. + /// The escaped argument. + public static string EscapeProcessArgument(this string value) + { + ArgumentNullException.ThrowIfNull(value); + + var span = value.AsSpan(); + if (!span.Contains('"')) + { + var trailing = span.Length - span.TrimEnd('\\').Length; + return trailing == 0 ? value : string.Concat(value, new string('\\', trailing)); + } + + var escaped = new StringBuilder(value.Length + 8); + var backslashes = 0; + + foreach (var character in span) + { + if (character == '\\') + { + backslashes++; + continue; + } + + escaped + .Append('\\', character == '"' ? (backslashes * 2) + 1 : backslashes) + .Append(character); + backslashes = 0; + } + + return escaped.Append('\\', backslashes * 2).ToString(); + } } } diff --git a/src/Jellyfin.LiveTv/IO/EncodedRecorder.cs b/src/Jellyfin.LiveTv/IO/EncodedRecorder.cs index 19c4514766..633c4f95ed 100644 --- a/src/Jellyfin.LiveTv/IO/EncodedRecorder.cs +++ b/src/Jellyfin.LiveTv/IO/EncodedRecorder.cs @@ -188,8 +188,8 @@ namespace Jellyfin.LiveTv.IO var commandLineArgs = string.Format( CultureInfo.InvariantCulture, "-i \"{0}\" {2} -map_metadata -1 -threads {6} {3}{4}{5} -y \"{1}\"", - inputTempFile, - targetFile.Replace("\"", "\\\"", StringComparison.Ordinal), // Escape quotes in filename + inputTempFile.EscapeProcessArgument(), + targetFile.EscapeProcessArgument(), videoArgs, GetAudioArgs(mediaSource), subtitleArgs, -- cgit v1.2.3