From 5be844e1b755bca6b8dd23509f96b7040b16f2f3 Mon Sep 17 00:00:00 2001 From: TowyTowy Date: Sun, 12 Jul 2026 12:11:29 +0200 Subject: Fix 3D format detection when the tag is the last token of the path Format3DParser drops the last character of the final path token: when IndexOfAny finds no more delimiters, the slice is taken with 'index = path.Length - 1', so e.g. "hsbs" is compared as "hsb" and never matches any rule. File paths are unaffected because the extension is always the final token, but directory based media have no extension. For DVD/BluRay folder rips (BaseVideoResolver parses the folder path via Set3DFormat), a trailing 3D tag such as "Gravity (2013) 3d hsbs/BDMV" is silently ignored and Video3DFormat is never set. This is a regression from 42a2cc174 which replaced the string.Split based FlagParser with span slicing; the Split implementation kept the final token intact. Co-Authored-By: Claude Fable 5 --- Emby.Naming/Video/Format3DParser.cs | 13 +++++++++---- tests/Jellyfin.Naming.Tests/Video/Format3DTests.cs | 21 +++++++++++++++++++++ 2 files changed, 30 insertions(+), 4 deletions(-) diff --git a/Emby.Naming/Video/Format3DParser.cs b/Emby.Naming/Video/Format3DParser.cs index eb5e71d78f..a287a2525b 100644 --- a/Emby.Naming/Video/Format3DParser.cs +++ b/Emby.Naming/Video/Format3DParser.cs @@ -52,13 +52,18 @@ namespace Emby.Naming.Video while (path.Length > 0) { var index = path.IndexOfAny(delimiters); + ReadOnlySpan currentSlice; if (index == -1) { - index = path.Length - 1; + // No delimiter left, the last token is the remainder of the path + currentSlice = path; + path = default; + } + else + { + currentSlice = path[..index]; + path = path[(index + 1)..]; } - - var currentSlice = path[..index]; - path = path[(index + 1)..]; if (!foundPrefix) { diff --git a/tests/Jellyfin.Naming.Tests/Video/Format3DTests.cs b/tests/Jellyfin.Naming.Tests/Video/Format3DTests.cs index d42bd66a1c..0e35071dd4 100644 --- a/tests/Jellyfin.Naming.Tests/Video/Format3DTests.cs +++ b/tests/Jellyfin.Naming.Tests/Video/Format3DTests.cs @@ -19,6 +19,27 @@ namespace Jellyfin.Naming.Tests.Video Test("Super movie 3d hsbs.mp4", true, "hsbs"); } + [Fact] + public void TestFormat3DAtEndOfPath() + { + // Directory based media (eg. DVD or BluRay folder rips) have no file extension, + // so the 3D tag can be the last token of the path. + Test("Super movie (2009) 3d hsbs", true, "hsbs"); + Test("Super movie (2009).3d.sbs", true, "sbs"); + Test("Super movie (2009) 3d htab", true, "htab"); + Test("Super movie (2009).hsbs", true, "hsbs"); + Test("Super movie (2009) 3d", false, null); + } + + [Fact] + public void TestResolveDirectory3D() + { + var result = VideoResolver.ResolveDirectory("/movies/Oblivion (2013) 3d hsbs", _namingOptions); + + Assert.True(result?.Is3D); + Assert.Equal("hsbs", result?.Format3D, true); + } + [Fact] public void Test3DName() { -- cgit v1.2.3