|
|
|
@ -1002,15 +1002,12 @@ namespace Emby.Server.Implementations.Data
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var parts = value.Split('|', StringSplitOptions.RemoveEmptyEntries);
|
|
|
|
|
|
|
|
|
|
foreach (var part in parts)
|
|
|
|
|
foreach (var part in value.SpanSplit('|'))
|
|
|
|
|
{
|
|
|
|
|
var idParts = part.Split('=');
|
|
|
|
|
|
|
|
|
|
if (idParts.Length == 2)
|
|
|
|
|
var providerDelimiterIndex = part.IndexOf('=');
|
|
|
|
|
if (providerDelimiterIndex != -1 && providerDelimiterIndex == part.LastIndexOf('='))
|
|
|
|
|
{
|
|
|
|
|
item.SetProviderId(idParts[0], idParts[1]);
|
|
|
|
|
item.SetProviderId(part.Slice(0, providerDelimiterIndex).ToString(), part.Slice(providerDelimiterIndex + 1).ToString());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -1045,9 +1042,8 @@ namespace Emby.Server.Implementations.Data
|
|
|
|
|
return Array.Empty<ItemImageInfo>();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var parts = value.Split('|' , StringSplitOptions.RemoveEmptyEntries);
|
|
|
|
|
var list = new List<ItemImageInfo>();
|
|
|
|
|
foreach (var part in parts)
|
|
|
|
|
foreach (var part in value.SpanSplit('|'))
|
|
|
|
|
{
|
|
|
|
|
var image = ItemImageInfoFromValueString(part);
|
|
|
|
|
|
|
|
|
@ -1086,41 +1082,93 @@ namespace Emby.Server.Implementations.Data
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public ItemImageInfo ItemImageInfoFromValueString(string value)
|
|
|
|
|
internal ItemImageInfo ItemImageInfoFromValueString(ReadOnlySpan<char> value)
|
|
|
|
|
{
|
|
|
|
|
var parts = value.Split('*', StringSplitOptions.None);
|
|
|
|
|
var nextSegment = value.IndexOf('*');
|
|
|
|
|
if (nextSegment == -1)
|
|
|
|
|
{
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (parts.Length < 3)
|
|
|
|
|
ReadOnlySpan<char> path = value[..nextSegment];
|
|
|
|
|
value = value[(nextSegment + 1)..];
|
|
|
|
|
nextSegment = value.IndexOf('*');
|
|
|
|
|
if (nextSegment == -1)
|
|
|
|
|
{
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var image = new ItemImageInfo();
|
|
|
|
|
ReadOnlySpan<char> dateModified = value[..nextSegment];
|
|
|
|
|
value = value[(nextSegment + 1)..];
|
|
|
|
|
nextSegment = value.IndexOf('*');
|
|
|
|
|
if (nextSegment == -1)
|
|
|
|
|
{
|
|
|
|
|
nextSegment = value.Length;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
image.Path = RestorePath(parts[0]);
|
|
|
|
|
ReadOnlySpan<char> imageType = value[..nextSegment];
|
|
|
|
|
|
|
|
|
|
if (long.TryParse(parts[1], NumberStyles.Any, CultureInfo.InvariantCulture, out var ticks))
|
|
|
|
|
var image = new ItemImageInfo
|
|
|
|
|
{
|
|
|
|
|
Path = RestorePath(path.ToString())
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
if (long.TryParse(dateModified, NumberStyles.Any, CultureInfo.InvariantCulture, out var ticks))
|
|
|
|
|
{
|
|
|
|
|
image.DateModified = new DateTime(ticks, DateTimeKind.Utc);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (Enum.TryParse(parts[2], true, out ImageType type))
|
|
|
|
|
if (Enum.TryParse(imageType.ToString(), true, out ImageType type))
|
|
|
|
|
{
|
|
|
|
|
image.Type = type;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (parts.Length >= 5)
|
|
|
|
|
// Optional parameters: width*height*blurhash
|
|
|
|
|
if (nextSegment + 1 < value.Length - 1)
|
|
|
|
|
{
|
|
|
|
|
if (int.TryParse(parts[3], NumberStyles.Integer, CultureInfo.InvariantCulture, out var width)
|
|
|
|
|
&& int.TryParse(parts[4], NumberStyles.Integer, CultureInfo.InvariantCulture, out var height))
|
|
|
|
|
value = value[(nextSegment + 1)..];
|
|
|
|
|
nextSegment = value.IndexOf('*');
|
|
|
|
|
if (nextSegment == -1 || nextSegment == value.Length)
|
|
|
|
|
{
|
|
|
|
|
return image;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ReadOnlySpan<char> widthSpan = value[..nextSegment];
|
|
|
|
|
|
|
|
|
|
value = value[(nextSegment + 1)..];
|
|
|
|
|
nextSegment = value.IndexOf('*');
|
|
|
|
|
if (nextSegment == -1)
|
|
|
|
|
{
|
|
|
|
|
nextSegment = value.Length;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ReadOnlySpan<char> heightSpan = value[..nextSegment];
|
|
|
|
|
|
|
|
|
|
if (int.TryParse(widthSpan, NumberStyles.Integer, CultureInfo.InvariantCulture, out var width)
|
|
|
|
|
&& int.TryParse(heightSpan, NumberStyles.Integer, CultureInfo.InvariantCulture, out var height))
|
|
|
|
|
{
|
|
|
|
|
image.Width = width;
|
|
|
|
|
image.Height = height;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (parts.Length >= 6)
|
|
|
|
|
if (nextSegment < value.Length - 1)
|
|
|
|
|
{
|
|
|
|
|
image.BlurHash = parts[5].Replace('/', '*').Replace('\\', '|');
|
|
|
|
|
value = value[(nextSegment + 1)..];
|
|
|
|
|
var length = value.Length;
|
|
|
|
|
|
|
|
|
|
Span<char> blurHashSpan = stackalloc char[length];
|
|
|
|
|
for (int i = 0; i < length; i++)
|
|
|
|
|
{
|
|
|
|
|
var c = value[i];
|
|
|
|
|
blurHashSpan[i] = c switch
|
|
|
|
|
{
|
|
|
|
|
'/' => '*',
|
|
|
|
|
'\\' => '|',
|
|
|
|
|
_ => c
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
image.BlurHash = new string(blurHashSpan);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -2110,27 +2158,6 @@ namespace Emby.Server.Implementations.Data
|
|
|
|
|
|
|
|
|
|
private readonly ItemFields[] _allFields = Enum.GetValues<ItemFields>();
|
|
|
|
|
|
|
|
|
|
private string[] GetColumnNamesFromField(ItemFields field)
|
|
|
|
|
{
|
|
|
|
|
switch (field)
|
|
|
|
|
{
|
|
|
|
|
case ItemFields.Settings:
|
|
|
|
|
return new[] { "IsLocked", "PreferredMetadataCountryCode", "PreferredMetadataLanguage", "LockedFields" };
|
|
|
|
|
case ItemFields.ServiceName:
|
|
|
|
|
return new[] { "ExternalServiceId" };
|
|
|
|
|
case ItemFields.SortName:
|
|
|
|
|
return new[] { "ForcedSortName" };
|
|
|
|
|
case ItemFields.Taglines:
|
|
|
|
|
return new[] { "Tagline" };
|
|
|
|
|
case ItemFields.Tags:
|
|
|
|
|
return new[] { "Tags" };
|
|
|
|
|
case ItemFields.IsHD:
|
|
|
|
|
return Array.Empty<string>();
|
|
|
|
|
default:
|
|
|
|
|
return new[] { field.ToString() };
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private bool HasField(InternalItemsQuery query, ItemFields name)
|
|
|
|
|
{
|
|
|
|
|
switch (name)
|
|
|
|
@ -2319,9 +2346,32 @@ namespace Emby.Server.Implementations.Data
|
|
|
|
|
{
|
|
|
|
|
if (!HasField(query, field))
|
|
|
|
|
{
|
|
|
|
|
foreach (var fieldToRemove in GetColumnNamesFromField(field))
|
|
|
|
|
switch (field)
|
|
|
|
|
{
|
|
|
|
|
list.Remove(fieldToRemove);
|
|
|
|
|
case ItemFields.Settings:
|
|
|
|
|
list.Remove("IsLocked");
|
|
|
|
|
list.Remove("PreferredMetadataCountryCode");
|
|
|
|
|
list.Remove("PreferredMetadataLanguage");
|
|
|
|
|
list.Remove("LockedFields");
|
|
|
|
|
break;
|
|
|
|
|
case ItemFields.ServiceName:
|
|
|
|
|
list.Remove("ExternalServiceId");
|
|
|
|
|
break;
|
|
|
|
|
case ItemFields.SortName:
|
|
|
|
|
list.Remove("ForcedSortName");
|
|
|
|
|
break;
|
|
|
|
|
case ItemFields.Taglines:
|
|
|
|
|
list.Remove("Tagline");
|
|
|
|
|
break;
|
|
|
|
|
case ItemFields.Tags:
|
|
|
|
|
list.Remove("Tags");
|
|
|
|
|
break;
|
|
|
|
|
case ItemFields.IsHD:
|
|
|
|
|
// do nothing
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
list.Remove(field.ToString());
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -2568,9 +2618,9 @@ namespace Emby.Server.Implementations.Data
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var commandText = "select "
|
|
|
|
|
+ string.Join(',', GetFinalColumnsToSelect(query, new[] { "count(distinct PresentationUniqueKey)" }))
|
|
|
|
|
+ GetFromText()
|
|
|
|
|
+ GetJoinUserDataText(query);
|
|
|
|
|
+ string.Join(',', GetFinalColumnsToSelect(query, new[] { "count(distinct PresentationUniqueKey)" }))
|
|
|
|
|
+ GetFromText()
|
|
|
|
|
+ GetJoinUserDataText(query);
|
|
|
|
|
|
|
|
|
|
var whereClauses = GetWhereClauses(query, null);
|
|
|
|
|
if (whereClauses.Count != 0)
|
|
|
|
|