|
|
|
using System;
|
|
|
|
using Emby.Naming.Common;
|
|
|
|
|
|
|
|
namespace Emby.Naming.Video
|
|
|
|
{
|
|
|
|
/// <summary>
|
|
|
|
/// Parse 3D format related flags.
|
|
|
|
/// </summary>
|
|
|
|
public static class Format3DParser
|
|
|
|
{
|
|
|
|
// Static default result to save on allocation costs.
|
|
|
|
private static readonly Format3DResult _defaultResult = new(false, null);
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Parse 3D format related flags.
|
|
|
|
/// </summary>
|
|
|
|
/// <param name="path">Path to file.</param>
|
|
|
|
/// <param name="namingOptions">The naming options.</param>
|
|
|
|
/// <returns>Returns <see cref="Format3DResult"/> object.</returns>
|
|
|
|
public static Format3DResult Parse(ReadOnlySpan<char> path, NamingOptions namingOptions)
|
|
|
|
{
|
|
|
|
int oldLen = namingOptions.VideoFlagDelimiters.Length;
|
|
|
|
Span<char> delimiters = stackalloc char[oldLen + 1];
|
|
|
|
namingOptions.VideoFlagDelimiters.AsSpan().CopyTo(delimiters);
|
|
|
|
delimiters[oldLen] = ' ';
|
|
|
|
|
|
|
|
return Parse(path, delimiters, namingOptions);
|
|
|
|
}
|
|
|
|
|
|
|
|
private static Format3DResult Parse(ReadOnlySpan<char> path, ReadOnlySpan<char> delimiters, NamingOptions namingOptions)
|
|
|
|
{
|
|
|
|
foreach (var rule in namingOptions.Format3DRules)
|
|
|
|
{
|
|
|
|
var result = Parse(path, rule, delimiters);
|
|
|
|
|
|
|
|
if (result.Is3D)
|
|
|
|
{
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return _defaultResult;
|
|
|
|
}
|
|
|
|
|
|
|
|
private static Format3DResult Parse(ReadOnlySpan<char> path, Format3DRule rule, ReadOnlySpan<char> delimiters)
|
|
|
|
{
|
|
|
|
bool is3D = false;
|
|
|
|
string? format3D = null;
|
|
|
|
|
|
|
|
// If there's no preceding token we just consider it found
|
|
|
|
var foundPrefix = string.IsNullOrEmpty(rule.PrecedingToken);
|
|
|
|
while (path.Length > 0)
|
|
|
|
{
|
|
|
|
var index = path.IndexOfAny(delimiters);
|
|
|
|
if (index == -1)
|
|
|
|
{
|
|
|
|
index = path.Length - 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
var currentSlice = path[..index];
|
|
|
|
path = path[(index + 1)..];
|
|
|
|
|
|
|
|
if (!foundPrefix)
|
|
|
|
{
|
|
|
|
foundPrefix = currentSlice.Equals(rule.PrecedingToken, StringComparison.OrdinalIgnoreCase);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
is3D = foundPrefix && currentSlice.Equals(rule.Token, StringComparison.OrdinalIgnoreCase);
|
|
|
|
|
|
|
|
if (is3D)
|
|
|
|
{
|
|
|
|
format3D = rule.Token;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return is3D ? new Format3DResult(true, format3D) : _defaultResult;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|