aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Emby.Naming/ExternalFiles/ExternalPathParser.cs2
-rw-r--r--Emby.Server.Implementations/Localization/Ratings/au.csv2
-rw-r--r--Emby.Server.Implementations/Playlists/PlaylistManager.cs13
-rw-r--r--Emby.Server.Implementations/ScheduledTasks/Tasks/CleanupCollectionAndPlaylistPathsTask.cs9
-rw-r--r--Jellyfin.Api/Controllers/ItemRefreshController.cs3
-rw-r--r--Jellyfin.Api/Helpers/StreamingHelpers.cs5
-rw-r--r--MediaBrowser.Controller/Entities/Folder.cs12
-rw-r--r--MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs4
-rw-r--r--MediaBrowser.Controller/Playlists/Playlist.cs8
-rw-r--r--MediaBrowser.LocalMetadata/Images/EpisodeLocalImageProvider.cs12
-rw-r--r--MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs6
-rw-r--r--MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs27
-rw-r--r--MediaBrowser.Model/Entities/MediaStream.cs16
-rw-r--r--MediaBrowser.Providers/Manager/MetadataService.cs2
-rw-r--r--MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzAlbumProvider.cs2
-rw-r--r--MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs4
-rw-r--r--src/Jellyfin.Networking/Manager/NetworkManager.cs10
-rw-r--r--tests/Jellyfin.Naming.Tests/ExternalFiles/ExternalPathParserTests.cs1
18 files changed, 81 insertions, 57 deletions
diff --git a/Emby.Naming/ExternalFiles/ExternalPathParser.cs b/Emby.Naming/ExternalFiles/ExternalPathParser.cs
index 9d54533c2..7a01b02f3 100644
--- a/Emby.Naming/ExternalFiles/ExternalPathParser.cs
+++ b/Emby.Naming/ExternalFiles/ExternalPathParser.cs
@@ -107,7 +107,7 @@ namespace Emby.Naming.ExternalFiles
pathInfo.Language = culture.ThreeLetterISOLanguageName;
extraString = extraString.Replace(currentSlice, string.Empty, StringComparison.OrdinalIgnoreCase);
}
- else if (_namingOptions.MediaHearingImpairedFlags.Any(s => currentSliceWithoutSeparator.Contains(s, StringComparison.OrdinalIgnoreCase)))
+ else if (_namingOptions.MediaHearingImpairedFlags.Any(s => currentSliceWithoutSeparator.Equals(s, StringComparison.OrdinalIgnoreCase)))
{
pathInfo.IsHearingImpaired = true;
extraString = extraString.Replace(currentSlice, string.Empty, StringComparison.OrdinalIgnoreCase);
diff --git a/Emby.Server.Implementations/Localization/Ratings/au.csv b/Emby.Server.Implementations/Localization/Ratings/au.csv
index 688125917..6e12759a4 100644
--- a/Emby.Server.Implementations/Localization/Ratings/au.csv
+++ b/Emby.Server.Implementations/Localization/Ratings/au.csv
@@ -1,11 +1,11 @@
Exempt,0
G,0
7+,7
+PG,15
M,15
MA,15
MA15+,15
MA 15+,15
-PG,16
16+,16
R,18
R18+,18
diff --git a/Emby.Server.Implementations/Playlists/PlaylistManager.cs b/Emby.Server.Implementations/Playlists/PlaylistManager.cs
index 8a35b96b3..47ff22c0b 100644
--- a/Emby.Server.Implementations/Playlists/PlaylistManager.cs
+++ b/Emby.Server.Implementations/Playlists/PlaylistManager.cs
@@ -170,8 +170,13 @@ namespace Emby.Server.Implementations.Playlists
private List<Playlist> GetUserPlaylists(Guid userId)
{
var user = _userManager.GetUserById(userId);
+ var playlistsFolder = GetPlaylistsFolder(userId);
+ if (playlistsFolder is null)
+ {
+ return [];
+ }
- return GetPlaylistsFolder(userId).GetChildren(user, true).OfType<Playlist>().ToList();
+ return playlistsFolder.GetChildren(user, true).OfType<Playlist>().ToList();
}
private static string GetTargetPath(string path)
@@ -184,11 +189,11 @@ namespace Emby.Server.Implementations.Playlists
return path;
}
- private IReadOnlyList<BaseItem> GetPlaylistItems(IEnumerable<Guid> itemIds, MediaType playlistMediaType, User user, DtoOptions options)
+ private IReadOnlyList<BaseItem> GetPlaylistItems(IEnumerable<Guid> itemIds, User user, DtoOptions options)
{
var items = itemIds.Select(_libraryManager.GetItemById).Where(i => i is not null);
- return Playlist.GetPlaylistItems(playlistMediaType, items, user, options);
+ return Playlist.GetPlaylistItems(items, user, options);
}
public Task AddItemToPlaylistAsync(Guid playlistId, IReadOnlyCollection<Guid> itemIds, Guid userId)
@@ -208,7 +213,7 @@ namespace Emby.Server.Implementations.Playlists
?? throw new ArgumentException("No Playlist exists with Id " + playlistId);
// Retrieve all the items to be added to the playlist
- var newItems = GetPlaylistItems(newItemIds, playlist.MediaType, user, options)
+ var newItems = GetPlaylistItems(newItemIds, user, options)
.Where(i => i.SupportsAddingToPlaylist);
// Filter out duplicate items, if necessary
diff --git a/Emby.Server.Implementations/ScheduledTasks/Tasks/CleanupCollectionAndPlaylistPathsTask.cs b/Emby.Server.Implementations/ScheduledTasks/Tasks/CleanupCollectionAndPlaylistPathsTask.cs
index 19b245464..804097219 100644
--- a/Emby.Server.Implementations/ScheduledTasks/Tasks/CleanupCollectionAndPlaylistPathsTask.cs
+++ b/Emby.Server.Implementations/ScheduledTasks/Tasks/CleanupCollectionAndPlaylistPathsTask.cs
@@ -127,15 +127,8 @@ public class CleanupCollectionAndPlaylistPathsTask : IScheduledTask
{
_logger.LogDebug("Updating {FolderName}", folder.Name);
folder.LinkedChildren = folder.LinkedChildren.Except(itemsToRemove).ToArray();
+ _providerManager.SaveMetadataAsync(folder, ItemUpdateType.MetadataEdit);
folder.UpdateToRepositoryAsync(ItemUpdateType.MetadataEdit, cancellationToken);
-
- _providerManager.QueueRefresh(
- folder.Id,
- new MetadataRefreshOptions(new DirectoryService(_fileSystem))
- {
- ForceSave = true
- },
- RefreshPriority.High);
}
}
diff --git a/Jellyfin.Api/Controllers/ItemRefreshController.cs b/Jellyfin.Api/Controllers/ItemRefreshController.cs
index c1343b130..d7a8c37c4 100644
--- a/Jellyfin.Api/Controllers/ItemRefreshController.cs
+++ b/Jellyfin.Api/Controllers/ItemRefreshController.cs
@@ -80,7 +80,8 @@ public class ItemRefreshController : BaseJellyfinApiController
|| imageRefreshMode == MetadataRefreshMode.FullRefresh
|| replaceAllImages
|| replaceAllMetadata,
- IsAutomated = false
+ IsAutomated = false,
+ RemoveOldMetadata = replaceAllMetadata
};
_providerManager.QueueRefresh(item.Id, refreshOptions, RefreshPriority.High);
diff --git a/Jellyfin.Api/Helpers/StreamingHelpers.cs b/Jellyfin.Api/Helpers/StreamingHelpers.cs
index af4a9e689..535ef27c3 100644
--- a/Jellyfin.Api/Helpers/StreamingHelpers.cs
+++ b/Jellyfin.Api/Helpers/StreamingHelpers.cs
@@ -154,6 +154,11 @@ public static class StreamingHelpers
// Some channels from HDHomerun will experience A/V sync issues
streamingRequest.SegmentContainer = "ts";
streamingRequest.VideoCodec = "h264";
+ streamingRequest.AudioCodec = "aac";
+ state.SupportedVideoCodecs = ["h264"];
+ state.Request.VideoCodec = "h264";
+ state.SupportedAudioCodecs = ["aac"];
+ state.Request.AudioCodec = "aac";
}
var liveStreamInfo = await mediaSourceManager.GetLiveStreamWithDirectStreamProvider(streamingRequest.LiveStreamId, cancellationToken).ConfigureAwait(false);
diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs
index fcb45e7e5..b2e5d7263 100644
--- a/MediaBrowser.Controller/Entities/Folder.cs
+++ b/MediaBrowser.Controller/Entities/Folder.cs
@@ -6,6 +6,7 @@ using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
+using System.Security;
using System.Text.Json.Serialization;
using System.Threading;
using System.Threading.Tasks;
@@ -370,9 +371,18 @@ namespace MediaBrowser.Controller.Entities
{
nonCachedChildren = GetNonCachedChildren(directoryService);
}
+ catch (IOException ex)
+ {
+ Logger.LogError(ex, "Error retrieving children from file system");
+ }
+ catch (SecurityException ex)
+ {
+ Logger.LogError(ex, "Error retrieving children from file system");
+ }
catch (Exception ex)
{
- Logger.LogError(ex, "Error retrieving children folder");
+ Logger.LogError(ex, "Error retrieving children");
+ return;
}
progress.Report(ProgressHelpers.RetrievedChildren);
diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs
index a845c8124..9d7d2fd12 100644
--- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs
+++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs
@@ -1209,8 +1209,8 @@ namespace MediaBrowser.Controller.MediaEncoding
var subtitlePath = state.SubtitleStream.Path;
var subtitleExtension = Path.GetExtension(subtitlePath.AsSpan());
- if (subtitleExtension.Equals(".sub", StringComparison.OrdinalIgnoreCase)
- || subtitleExtension.Equals(".sup", StringComparison.OrdinalIgnoreCase))
+ // dvdsub/vobsub graphical subtitles use .sub+.idx pairs
+ if (subtitleExtension.Equals(".sub", StringComparison.OrdinalIgnoreCase))
{
var idxFile = Path.ChangeExtension(subtitlePath, ".idx");
if (File.Exists(idxFile))
diff --git a/MediaBrowser.Controller/Playlists/Playlist.cs b/MediaBrowser.Controller/Playlists/Playlist.cs
index 6fc9a7e1b..45aefacf6 100644
--- a/MediaBrowser.Controller/Playlists/Playlist.cs
+++ b/MediaBrowser.Controller/Playlists/Playlist.cs
@@ -166,7 +166,7 @@ namespace MediaBrowser.Controller.Playlists
return base.GetChildren(user, true, query);
}
- public static IReadOnlyList<BaseItem> GetPlaylistItems(MediaType playlistMediaType, IEnumerable<BaseItem> inputItems, User user, DtoOptions options)
+ public static IReadOnlyList<BaseItem> GetPlaylistItems(IEnumerable<BaseItem> inputItems, User user, DtoOptions options)
{
if (user is not null)
{
@@ -177,14 +177,14 @@ namespace MediaBrowser.Controller.Playlists
foreach (var item in inputItems)
{
- var playlistItems = GetPlaylistItems(item, user, playlistMediaType, options);
+ var playlistItems = GetPlaylistItems(item, user, options);
list.AddRange(playlistItems);
}
return list;
}
- private static IEnumerable<BaseItem> GetPlaylistItems(BaseItem item, User user, MediaType mediaType, DtoOptions options)
+ private static IEnumerable<BaseItem> GetPlaylistItems(BaseItem item, User user, DtoOptions options)
{
if (item is MusicGenre musicGenre)
{
@@ -216,7 +216,7 @@ namespace MediaBrowser.Controller.Playlists
{
Recursive = true,
IsFolder = false,
- MediaTypes = [mediaType],
+ MediaTypes = [MediaType.Audio, MediaType.Video],
EnableTotalRecordCount = false,
DtoOptions = options
};
diff --git a/MediaBrowser.LocalMetadata/Images/EpisodeLocalImageProvider.cs b/MediaBrowser.LocalMetadata/Images/EpisodeLocalImageProvider.cs
index 6a5e3bf04..f00d508bb 100644
--- a/MediaBrowser.LocalMetadata/Images/EpisodeLocalImageProvider.cs
+++ b/MediaBrowser.LocalMetadata/Images/EpisodeLocalImageProvider.cs
@@ -40,13 +40,12 @@ namespace MediaBrowser.LocalMetadata.Images
var parentPathFiles = directoryService.GetFiles(parentPath);
var nameWithoutExtension = Path.GetFileNameWithoutExtension(item.Path.AsSpan()).ToString();
- var thumbName = string.Concat(nameWithoutExtension, "-thumb");
- var images = GetImageFilesFromFolder(thumbName, parentPathFiles);
+ var images = GetImageFilesFromFolder(nameWithoutExtension, parentPathFiles);
- var metadataSubPath = directoryService.GetDirectories(parentPath).Where(d => d.Name.EndsWith("metadata", StringComparison.OrdinalIgnoreCase)).ToList();
- foreach (var path in metadataSubPath)
+ var metadataSubDir = directoryService.GetDirectories(parentPath).FirstOrDefault(d => d.Name.Equals("metadata", StringComparison.Ordinal));
+ if (metadataSubDir is not null)
{
- var files = directoryService.GetFiles(path.FullName);
+ var files = directoryService.GetFiles(metadataSubDir.FullName);
images.AddRange(GetImageFilesFromFolder(nameWithoutExtension, files));
}
@@ -55,9 +54,8 @@ namespace MediaBrowser.LocalMetadata.Images
private List<LocalImageInfo> GetImageFilesFromFolder(ReadOnlySpan<char> filenameWithoutExtension, List<FileSystemMetadata> filePaths)
{
- var thumbName = string.Concat(filenameWithoutExtension, "-thumb");
-
var list = new List<LocalImageInfo>(1);
+ var thumbName = string.Concat(filenameWithoutExtension, "-thumb");
foreach (var i in filePaths)
{
diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs
index f85510dac..d0d41c2d3 100644
--- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs
+++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs
@@ -1155,10 +1155,10 @@ namespace MediaBrowser.MediaEncoding.Encoder
// Get all files from the BDMV/STREAMING directory
// Only return playable local .m2ts files
+ var files = _fileSystem.GetFiles(Path.Join(path, "BDMV", "STREAM")).ToList();
return validPlaybackFiles
- .Select(f => _fileSystem.GetFileInfo(Path.Join(path, "BDMV", "STREAM", f)))
- .Where(f => f.Exists)
- .Select(f => f.FullName)
+ .Select(validFile => files.FirstOrDefault(f => Path.GetFileName(f.FullName.AsSpan()).Equals(validFile, StringComparison.OrdinalIgnoreCase))?.FullName)
+ .Where(f => f is not null)
.ToList();
}
diff --git a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs
index a587fa9db..8b2685fe1 100644
--- a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs
+++ b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs
@@ -280,8 +280,8 @@ namespace MediaBrowser.MediaEncoding.Probing
splitFormat[i] = "mpeg";
}
- // Handle MPEG-2 container
- else if (string.Equals(splitFormat[i], "mpeg", StringComparison.OrdinalIgnoreCase))
+ // Handle MPEG-TS container
+ else if (string.Equals(splitFormat[i], "mpegts", StringComparison.OrdinalIgnoreCase))
{
splitFormat[i] = "ts";
}
@@ -624,15 +624,19 @@ namespace MediaBrowser.MediaEncoding.Probing
{
if (string.Equals(codec, "dvb_subtitle", StringComparison.OrdinalIgnoreCase))
{
- codec = "dvbsub";
+ codec = "DVBSUB";
}
- else if ((codec ?? string.Empty).Contains("PGS", StringComparison.OrdinalIgnoreCase))
+ else if (string.Equals(codec, "dvb_teletext", StringComparison.OrdinalIgnoreCase))
{
- codec = "PGSSUB";
+ codec = "DVBTXT";
}
- else if ((codec ?? string.Empty).Contains("DVD", StringComparison.OrdinalIgnoreCase))
+ else if (string.Equals(codec, "dvd_subtitle", StringComparison.OrdinalIgnoreCase))
{
- codec = "DVDSUB";
+ codec = "DVDSUB"; // .sub+.idx
+ }
+ else if (string.Equals(codec, "hdmv_pgs_subtitle", StringComparison.OrdinalIgnoreCase))
+ {
+ codec = "PGSSUB"; // .sup
}
return codec;
@@ -779,11 +783,10 @@ namespace MediaBrowser.MediaEncoding.Probing
&& !string.Equals(streamInfo.FieldOrder, "progressive", StringComparison.OrdinalIgnoreCase);
if (isAudio
- && (string.Equals(stream.Codec, "bmp", StringComparison.OrdinalIgnoreCase)
- || string.Equals(stream.Codec, "gif", StringComparison.OrdinalIgnoreCase)
- || string.Equals(stream.Codec, "mjpeg", StringComparison.OrdinalIgnoreCase)
- || string.Equals(stream.Codec, "png", StringComparison.OrdinalIgnoreCase)
- || string.Equals(stream.Codec, "webp", StringComparison.OrdinalIgnoreCase)))
+ || string.Equals(stream.Codec, "bmp", StringComparison.OrdinalIgnoreCase)
+ || string.Equals(stream.Codec, "gif", StringComparison.OrdinalIgnoreCase)
+ || string.Equals(stream.Codec, "png", StringComparison.OrdinalIgnoreCase)
+ || string.Equals(stream.Codec, "webp", StringComparison.OrdinalIgnoreCase))
{
stream.Type = MediaStreamType.EmbeddedImage;
}
diff --git a/MediaBrowser.Model/Entities/MediaStream.cs b/MediaBrowser.Model/Entities/MediaStream.cs
index 3e01c6efc..e1082adea 100644
--- a/MediaBrowser.Model/Entities/MediaStream.cs
+++ b/MediaBrowser.Model/Entities/MediaStream.cs
@@ -656,14 +656,14 @@ namespace MediaBrowser.Model.Entities
{
string codec = format ?? string.Empty;
- // sub = external .sub file
-
- return !codec.Contains("pgs", StringComparison.OrdinalIgnoreCase)
- && !codec.Contains("dvd", StringComparison.OrdinalIgnoreCase)
- && !codec.Contains("dvbsub", StringComparison.OrdinalIgnoreCase)
- && !string.Equals(codec, "sub", StringComparison.OrdinalIgnoreCase)
- && !string.Equals(codec, "sup", StringComparison.OrdinalIgnoreCase)
- && !string.Equals(codec, "dvb_subtitle", StringComparison.OrdinalIgnoreCase);
+ // microdvd and dvdsub/vobsub share the ".sub" file extension, but it's text-based.
+
+ return codec.Contains("microdvd", StringComparison.OrdinalIgnoreCase)
+ || (!codec.Contains("pgs", StringComparison.OrdinalIgnoreCase)
+ && !codec.Contains("dvdsub", StringComparison.OrdinalIgnoreCase)
+ && !codec.Contains("dvbsub", StringComparison.OrdinalIgnoreCase)
+ && !string.Equals(codec, "sup", StringComparison.OrdinalIgnoreCase)
+ && !string.Equals(codec, "sub", StringComparison.OrdinalIgnoreCase));
}
public bool SupportsSubtitleConversionTo(string toCodec)
diff --git a/MediaBrowser.Providers/Manager/MetadataService.cs b/MediaBrowser.Providers/Manager/MetadataService.cs
index 7fd64809d..1751c5b9b 100644
--- a/MediaBrowser.Providers/Manager/MetadataService.cs
+++ b/MediaBrowser.Providers/Manager/MetadataService.cs
@@ -669,6 +669,8 @@ namespace MediaBrowser.Providers.Manager
};
temp.Item.Path = item.Path;
temp.Item.Id = item.Id;
+ temp.Item.PreferredMetadataCountryCode = item.PreferredMetadataCountryCode;
+ temp.Item.PreferredMetadataLanguage = item.PreferredMetadataLanguage;
var foundImageTypes = new List<ImageType>();
diff --git a/MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzAlbumProvider.cs b/MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzAlbumProvider.cs
index d0bd7d609..c35324746 100644
--- a/MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzAlbumProvider.cs
+++ b/MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzAlbumProvider.cs
@@ -250,7 +250,7 @@ public class MusicBrainzAlbumProvider : IRemoteMetadataProvider<MusicAlbum, Albu
// If we have a release ID but not a release group ID, lookup the release group
if (!string.IsNullOrWhiteSpace(releaseId) && string.IsNullOrWhiteSpace(releaseGroupId))
{
- var release = await _musicBrainzQuery.LookupReleaseAsync(new Guid(releaseId), Include.Releases, cancellationToken).ConfigureAwait(false);
+ var release = await _musicBrainzQuery.LookupReleaseAsync(new Guid(releaseId), Include.ReleaseGroups, cancellationToken).ConfigureAwait(false);
releaseGroupId = release.ReleaseGroup?.Id.ToString();
result.HasMetadata = true;
}
diff --git a/MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs b/MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs
index 97cdc6854..d049c5a8e 100644
--- a/MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs
+++ b/MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs
@@ -519,7 +519,9 @@ namespace MediaBrowser.XbmcMetadata.Parsers
if (reader.TryReadDateTimeExact(nfoConfiguration.ReleaseDateFormat, out var releaseDate))
{
item.PremiereDate = releaseDate;
- item.ProductionYear = releaseDate.Year;
+
+ // Production year can already be set by the year tag
+ item.ProductionYear ??= releaseDate.Year;
}
break;
diff --git a/src/Jellyfin.Networking/Manager/NetworkManager.cs b/src/Jellyfin.Networking/Manager/NetworkManager.cs
index 148b33fcb..cf6a2cc55 100644
--- a/src/Jellyfin.Networking/Manager/NetworkManager.cs
+++ b/src/Jellyfin.Networking/Manager/NetworkManager.cs
@@ -919,10 +919,14 @@ public class NetworkManager : INetworkManager, IDisposable
{
ArgumentNullException.ThrowIfNull(address);
- // See conversation at https://github.com/jellyfin/jellyfin/pull/3515.
+ // Map IPv6 mapped IPv4 back to IPv4 (happens if Kestrel runs in dual-socket mode)
+ if (address.IsIPv4MappedToIPv6)
+ {
+ address = address.MapToIPv4();
+ }
+
if ((TrustAllIPv6Interfaces && address.AddressFamily == AddressFamily.InterNetworkV6)
- || address.Equals(IPAddress.Loopback)
- || address.Equals(IPAddress.IPv6Loopback))
+ || IPAddress.IsLoopback(address))
{
return true;
}
diff --git a/tests/Jellyfin.Naming.Tests/ExternalFiles/ExternalPathParserTests.cs b/tests/Jellyfin.Naming.Tests/ExternalFiles/ExternalPathParserTests.cs
index ba602b5d2..0b8b1f644 100644
--- a/tests/Jellyfin.Naming.Tests/ExternalFiles/ExternalPathParserTests.cs
+++ b/tests/Jellyfin.Naming.Tests/ExternalFiles/ExternalPathParserTests.cs
@@ -104,6 +104,7 @@ public class ExternalPathParserTests
[InlineData(".en.cc.title", "title", "eng", false, false, true)]
[InlineData(".hi.en.title", "title", "eng", false, false, true)]
[InlineData(".en.hi.title", "title", "eng", false, false, true)]
+ [InlineData(".Subs for Chinese Audio.eng", "Subs for Chinese Audio", "eng", false, false, false)]
public void ParseFile_ExtraTokens_ParseToValues(string tokens, string? title, string? language, bool isDefault = false, bool isForced = false, bool isHearingImpaired = false)
{
var path = "My.Video" + tokens + ".srt";