aboutsummaryrefslogtreecommitdiff
path: root/MediaBrowser.Controller/Entities
diff options
context:
space:
mode:
Diffstat (limited to 'MediaBrowser.Controller/Entities')
-rw-r--r--MediaBrowser.Controller/Entities/BaseItem.cs31
-rw-r--r--MediaBrowser.Controller/Entities/Video.cs18
2 files changed, 35 insertions, 14 deletions
diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs
index 84ba560900..0a3fdbc1ab 100644
--- a/MediaBrowser.Controller/Entities/BaseItem.cs
+++ b/MediaBrowser.Controller/Entities/BaseItem.cs
@@ -87,9 +87,7 @@ namespace MediaBrowser.Controller.Entities
Model.Entities.ExtraType.Short
};
- // Separators the naming layer treats as version delimiters (Emby.Naming VideoFlagDelimiters),
- // used when stripping the shared prefix from an alternate version's media source name.
- private static readonly char[] VersionSeparators = [' ', '-', '_', '.'];
+ private static readonly char[] VersionDelimiters = ['-', '_', '.'];
private string _sortName;
@@ -1235,13 +1233,13 @@ namespace MediaBrowser.Controller.Entities
// Prefer the suffix that differs from the other versions: strip the prefix shared by
// all sibling files. This works regardless of folder layout, so it also labels episode
// versions that share a season folder (e.g. "Greyscale" instead of the full
- // "Show - S01E02 - Title - Greyscale"). The prefix is already retreated to a separator
+ // "Show - S01E02 - Title - Greyscale"). The prefix is already retreated to a delimiter
// boundary (see GetCommonVersionPrefix).
if (!string.IsNullOrEmpty(commonPrefix)
&& displayName.Length > commonPrefix.Length
&& displayName.StartsWith(commonPrefix, StringComparison.OrdinalIgnoreCase))
{
- var name = displayName.AsSpan(commonPrefix.Length).TrimStart(VersionSeparators);
+ var name = displayName.AsSpan(commonPrefix.Length).TrimStart([' ', .. VersionDelimiters]);
if (!name.IsWhiteSpace())
{
terms.Add(name.ToString());
@@ -1255,7 +1253,7 @@ namespace MediaBrowser.Controller.Entities
var containingFolderName = System.IO.Path.GetFileName(ContainingFolderPath);
if (displayName.Length > containingFolderName.Length && displayName.StartsWith(containingFolderName, StringComparison.OrdinalIgnoreCase))
{
- var name = displayName.AsSpan(containingFolderName.Length).TrimStart(VersionSeparators);
+ var name = displayName.AsSpan(containingFolderName.Length).TrimStart([' ', .. VersionDelimiters]);
if (!name.IsWhiteSpace())
{
terms.Add(name.ToString());
@@ -1341,11 +1339,14 @@ namespace MediaBrowser.Controller.Entities
/// <summary>
/// Computes the case-insensitive longest common prefix of the supplied version file names,
- /// retreated to the last separator boundary. Retreating keeps the differing suffix intact:
+ /// retreated to the last delimiter boundary. Retreating keeps the differing suffix intact:
/// it avoids slicing through a word every version shares (e.g. "Grey" in "Greyscale" and
/// "Greyish") while still trimming the common part when every version is suffixed (e.g.
- /// "- Greyscale" / "- Colorized"). The separators mirror the version delimiters recognised by
- /// the naming layer (Emby.Naming VideoFlagDelimiters).
+ /// "- Greyscale" / "- Colorized"). It prefers a structural delimiter ('-', '_', '.') so a
+ /// token shared by the descriptors but separated only by spaces (e.g. a common "2160p ") is
+ /// kept in the label, falling back to a space only when no structural delimiter is shared. The
+ /// separators mirror the version delimiters recognised by the naming layer (Emby.Naming
+ /// VideoFlagDelimiters).
/// </summary>
/// <param name="fileNames">The version file names without extension; must contain at least one entry.</param>
/// <returns>The shared prefix retreated to a separator boundary, or an empty string when none is shared.</returns>
@@ -1379,12 +1380,22 @@ namespace MediaBrowser.Controller.Entities
if (!prefixIsWholeName)
{
+ // Retreat to the last structural delimiter ('-', '_', '.').
var cut = prefix.Length;
- while (cut > 0 && Array.IndexOf(VersionSeparators, prefix[cut - 1]) < 0)
+ while (cut > 0 && Array.IndexOf(VersionDelimiters, prefix[cut - 1]) < 0)
{
cut--;
}
+ if (cut == 0)
+ {
+ cut = prefix.Length;
+ while (cut > 0 && prefix[cut - 1] != ' ')
+ {
+ cut--;
+ }
+ }
+
prefix = prefix[..cut];
}
diff --git a/MediaBrowser.Controller/Entities/Video.cs b/MediaBrowser.Controller/Entities/Video.cs
index 168ef7d817..f48de0869a 100644
--- a/MediaBrowser.Controller/Entities/Video.cs
+++ b/MediaBrowser.Controller/Entities/Video.cs
@@ -409,16 +409,26 @@ namespace MediaBrowser.Controller.Entities
}
/// <summary>
+ /// Gets this video together with all of its alternate versions (local and linked and, when this
+ /// is itself an alternate, the primary and the primary's other versions), deduplicated.
+ /// </summary>
+ /// <returns>This video and every alternate version of it.</returns>
+ public IReadOnlyList<Video> GetAllVersions()
+ {
+ return GetAllItemsForMediaSources()
+ .Select(i => i.Item)
+ .OfType<Video>()
+ .ToList();
+ }
+
+ /// <summary>
/// Gets the alternate version of this video that matches the supplied item id.
/// </summary>
/// <param name="itemId">The version item id (the playback media source id).</param>
/// <returns>The matching version, or <c>null</c> when the id is not a version of this video.</returns>
public Video GetAlternateVersion(Guid itemId)
{
- return GetAllItemsForMediaSources()
- .Select(i => i.Item)
- .OfType<Video>()
- .FirstOrDefault(i => i.Id.Equals(itemId));
+ return GetAllVersions().FirstOrDefault(i => i.Id.Equals(itemId));
}
public override string CreatePresentationUniqueKey()