mirror of
https://github.com/jellyfin/jellyfin.git
synced 2024-09-05 21:37:10 -04:00
Merge pull request #848 from Bond-009/perf
Minor changes to reduce allocations
This commit is contained in:
commit
89d4ce309d
@ -224,7 +224,7 @@ namespace Emby.Server.Implementations.Data
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
db.ExecuteAll(string.Join(";", queries.ToArray()));
|
db.ExecuteAll(string.Join(";", queries));
|
||||||
Logger.LogInformation("PRAGMA synchronous=" + db.Query("PRAGMA synchronous").SelectScalarString().First());
|
Logger.LogInformation("PRAGMA synchronous=" + db.Query("PRAGMA synchronous").SelectScalarString().First());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -232,23 +232,6 @@ namespace Emby.Server.Implementations.Data
|
|||||||
|
|
||||||
protected virtual int? CacheSize => null;
|
protected virtual int? CacheSize => null;
|
||||||
|
|
||||||
internal static void CheckOk(int rc)
|
|
||||||
{
|
|
||||||
string msg = "";
|
|
||||||
|
|
||||||
if (raw.SQLITE_OK != rc)
|
|
||||||
{
|
|
||||||
throw CreateException((ErrorCode)rc, msg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static Exception CreateException(ErrorCode rc, string msg)
|
|
||||||
{
|
|
||||||
var exp = new Exception(msg);
|
|
||||||
|
|
||||||
return exp;
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool _disposed;
|
private bool _disposed;
|
||||||
protected void CheckDisposed()
|
protected void CheckDisposed()
|
||||||
{
|
{
|
||||||
@ -375,13 +358,6 @@ namespace Emby.Server.Implementations.Data
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class DummyToken : IDisposable
|
|
||||||
{
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static IDisposable Read(this ReaderWriterLockSlim obj)
|
public static IDisposable Read(this ReaderWriterLockSlim obj)
|
||||||
{
|
{
|
||||||
//if (BaseSqliteRepository.ThreadSafeMode > 0)
|
//if (BaseSqliteRepository.ThreadSafeMode > 0)
|
||||||
@ -390,6 +366,7 @@ namespace Emby.Server.Implementations.Data
|
|||||||
//}
|
//}
|
||||||
return new WriteLockToken(obj);
|
return new WriteLockToken(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IDisposable Write(this ReaderWriterLockSlim obj)
|
public static IDisposable Write(this ReaderWriterLockSlim obj)
|
||||||
{
|
{
|
||||||
//if (BaseSqliteRepository.ThreadSafeMode > 0)
|
//if (BaseSqliteRepository.ThreadSafeMode > 0)
|
||||||
|
@ -536,7 +536,7 @@ namespace Emby.Server.Implementations.Data
|
|||||||
throw new ArgumentNullException(nameof(item));
|
throw new ArgumentNullException(nameof(item));
|
||||||
}
|
}
|
||||||
|
|
||||||
SaveItems(new List<BaseItem> { item }, cancellationToken);
|
SaveItems(new [] { item }, cancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SaveImages(BaseItem item)
|
public void SaveImages(BaseItem item)
|
||||||
@ -576,7 +576,7 @@ namespace Emby.Server.Implementations.Data
|
|||||||
/// or
|
/// or
|
||||||
/// cancellationToken
|
/// cancellationToken
|
||||||
/// </exception>
|
/// </exception>
|
||||||
public void SaveItems(List<BaseItem> items, CancellationToken cancellationToken)
|
public void SaveItems(IEnumerable<BaseItem> items, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
if (items == null)
|
if (items == null)
|
||||||
{
|
{
|
||||||
@ -587,7 +587,7 @@ namespace Emby.Server.Implementations.Data
|
|||||||
|
|
||||||
CheckDisposed();
|
CheckDisposed();
|
||||||
|
|
||||||
var tuples = new List<Tuple<BaseItem, List<Guid>, BaseItem, string, List<string>>>();
|
var tuples = new List<(BaseItem, List<Guid>, BaseItem, string, List<string>)>();
|
||||||
foreach (var item in items)
|
foreach (var item in items)
|
||||||
{
|
{
|
||||||
var ancestorIds = item.SupportsAncestors ?
|
var ancestorIds = item.SupportsAncestors ?
|
||||||
@ -599,7 +599,7 @@ namespace Emby.Server.Implementations.Data
|
|||||||
var userdataKey = item.GetUserDataKeys().FirstOrDefault();
|
var userdataKey = item.GetUserDataKeys().FirstOrDefault();
|
||||||
var inheritedTags = item.GetInheritedTags();
|
var inheritedTags = item.GetInheritedTags();
|
||||||
|
|
||||||
tuples.Add(new Tuple<BaseItem, List<Guid>, BaseItem, string, List<string>>(item, ancestorIds, topParent, userdataKey, inheritedTags));
|
tuples.Add((item, ancestorIds, topParent, userdataKey, inheritedTags));
|
||||||
}
|
}
|
||||||
|
|
||||||
using (WriteLock.Write())
|
using (WriteLock.Write())
|
||||||
@ -615,7 +615,7 @@ namespace Emby.Server.Implementations.Data
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SaveItemsInTranscation(IDatabaseConnection db, List<Tuple<BaseItem, List<Guid>, BaseItem, string, List<string>>> tuples)
|
private void SaveItemsInTranscation(IDatabaseConnection db, IEnumerable<(BaseItem, List<Guid>, BaseItem, string, List<string>)> tuples)
|
||||||
{
|
{
|
||||||
var statements = PrepareAllSafe(db, new string[]
|
var statements = PrepareAllSafe(db, new string[]
|
||||||
{
|
{
|
||||||
@ -966,7 +966,7 @@ namespace Emby.Server.Implementations.Data
|
|||||||
|
|
||||||
if (item.ExtraIds.Length > 0)
|
if (item.ExtraIds.Length > 0)
|
||||||
{
|
{
|
||||||
saveItemStatement.TryBind("@ExtraIds", string.Join("|", item.ExtraIds.ToArray()));
|
saveItemStatement.TryBind("@ExtraIds", string.Join("|", item.ExtraIds));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -1183,9 +1183,9 @@ namespace Emby.Server.Implementations.Data
|
|||||||
/// <exception cref="ArgumentException"></exception>
|
/// <exception cref="ArgumentException"></exception>
|
||||||
public BaseItem RetrieveItem(Guid id)
|
public BaseItem RetrieveItem(Guid id)
|
||||||
{
|
{
|
||||||
if (id.Equals(Guid.Empty))
|
if (id == Guid.Empty)
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException(nameof(id));
|
throw new ArgumentException(nameof(id), "Guid can't be empty");
|
||||||
}
|
}
|
||||||
|
|
||||||
CheckDisposed();
|
CheckDisposed();
|
||||||
@ -2079,14 +2079,14 @@ namespace Emby.Server.Implementations.Data
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
var sortingFields = query.OrderBy.Select(i => i.Item1);
|
var sortingFields = new HashSet<string>(query.OrderBy.Select(i => i.Item1), StringComparer.OrdinalIgnoreCase);
|
||||||
|
|
||||||
return sortingFields.Contains(ItemSortBy.IsFavoriteOrLiked, StringComparer.OrdinalIgnoreCase)
|
return sortingFields.Contains(ItemSortBy.IsFavoriteOrLiked)
|
||||||
|| sortingFields.Contains(ItemSortBy.IsPlayed, StringComparer.OrdinalIgnoreCase)
|
|| sortingFields.Contains(ItemSortBy.IsPlayed)
|
||||||
|| sortingFields.Contains(ItemSortBy.IsUnplayed, StringComparer.OrdinalIgnoreCase)
|
|| sortingFields.Contains(ItemSortBy.IsUnplayed)
|
||||||
|| sortingFields.Contains(ItemSortBy.PlayCount, StringComparer.OrdinalIgnoreCase)
|
|| sortingFields.Contains(ItemSortBy.PlayCount)
|
||||||
|| sortingFields.Contains(ItemSortBy.DatePlayed, StringComparer.OrdinalIgnoreCase)
|
|| sortingFields.Contains(ItemSortBy.DatePlayed)
|
||||||
|| sortingFields.Contains(ItemSortBy.SeriesDatePlayed, StringComparer.OrdinalIgnoreCase)
|
|| sortingFields.Contains(ItemSortBy.SeriesDatePlayed)
|
||||||
|| query.IsFavoriteOrLiked.HasValue
|
|| query.IsFavoriteOrLiked.HasValue
|
||||||
|| query.IsFavorite.HasValue
|
|| query.IsFavorite.HasValue
|
||||||
|| query.IsResumable.HasValue
|
|| query.IsResumable.HasValue
|
||||||
@ -2094,9 +2094,9 @@ namespace Emby.Server.Implementations.Data
|
|||||||
|| query.IsLiked.HasValue;
|
|| query.IsLiked.HasValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly List<ItemFields> allFields = Enum.GetNames(typeof(ItemFields))
|
private readonly ItemFields[] _allFields = Enum.GetNames(typeof(ItemFields))
|
||||||
.Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true))
|
.Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true))
|
||||||
.ToList();
|
.ToArray();
|
||||||
|
|
||||||
private string[] GetColumnNamesFromField(ItemFields field)
|
private string[] GetColumnNamesFromField(ItemFields field)
|
||||||
{
|
{
|
||||||
@ -2151,18 +2151,26 @@ namespace Emby.Server.Implementations.Data
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static readonly HashSet<string> _programExcludeParentTypes = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
|
||||||
|
{
|
||||||
|
"Series",
|
||||||
|
"Season",
|
||||||
|
"MusicAlbum",
|
||||||
|
"MusicArtist",
|
||||||
|
"PhotoAlbum"
|
||||||
|
};
|
||||||
|
|
||||||
|
private static readonly HashSet<string> _programTypes = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
|
||||||
|
{
|
||||||
|
"Program",
|
||||||
|
"TvChannel",
|
||||||
|
"LiveTvProgram",
|
||||||
|
"LiveTvTvChannel"
|
||||||
|
};
|
||||||
|
|
||||||
private bool HasProgramAttributes(InternalItemsQuery query)
|
private bool HasProgramAttributes(InternalItemsQuery query)
|
||||||
{
|
{
|
||||||
var excludeParentTypes = new string[]
|
if (_programExcludeParentTypes.Contains(query.ParentType))
|
||||||
{
|
|
||||||
"Series",
|
|
||||||
"Season",
|
|
||||||
"MusicAlbum",
|
|
||||||
"MusicArtist",
|
|
||||||
"PhotoAlbum"
|
|
||||||
};
|
|
||||||
|
|
||||||
if (excludeParentTypes.Contains(query.ParentType ?? string.Empty, StringComparer.OrdinalIgnoreCase))
|
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -2172,29 +2180,18 @@ namespace Emby.Server.Implementations.Data
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
var types = new string[]
|
return query.IncludeItemTypes.Any(x => _programTypes.Contains(x));
|
||||||
{
|
|
||||||
"Program",
|
|
||||||
"TvChannel",
|
|
||||||
"LiveTvProgram",
|
|
||||||
"LiveTvTvChannel"
|
|
||||||
};
|
|
||||||
|
|
||||||
return types.Any(i => query.IncludeItemTypes.Contains(i, StringComparer.OrdinalIgnoreCase));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static readonly HashSet<string> _serviceTypes = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
|
||||||
|
{
|
||||||
|
"TvChannel",
|
||||||
|
"LiveTvTvChannel"
|
||||||
|
};
|
||||||
|
|
||||||
private bool HasServiceName(InternalItemsQuery query)
|
private bool HasServiceName(InternalItemsQuery query)
|
||||||
{
|
{
|
||||||
var excludeParentTypes = new string[]
|
if (_programExcludeParentTypes.Contains(query.ParentType))
|
||||||
{
|
|
||||||
"Series",
|
|
||||||
"Season",
|
|
||||||
"MusicAlbum",
|
|
||||||
"MusicArtist",
|
|
||||||
"PhotoAlbum"
|
|
||||||
};
|
|
||||||
|
|
||||||
if (excludeParentTypes.Contains(query.ParentType ?? string.Empty, StringComparer.OrdinalIgnoreCase))
|
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -2204,27 +2201,18 @@ namespace Emby.Server.Implementations.Data
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
var types = new string[]
|
return query.IncludeItemTypes.Any(x => _serviceTypes.Contains(x));
|
||||||
{
|
|
||||||
"TvChannel",
|
|
||||||
"LiveTvTvChannel"
|
|
||||||
};
|
|
||||||
|
|
||||||
return types.Any(i => query.IncludeItemTypes.Contains(i, StringComparer.OrdinalIgnoreCase));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static readonly HashSet<string> _startDateTypes = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
|
||||||
|
{
|
||||||
|
"Program",
|
||||||
|
"LiveTvProgram"
|
||||||
|
};
|
||||||
|
|
||||||
private bool HasStartDate(InternalItemsQuery query)
|
private bool HasStartDate(InternalItemsQuery query)
|
||||||
{
|
{
|
||||||
var excludeParentTypes = new string[]
|
if (_programExcludeParentTypes.Contains(query.ParentType))
|
||||||
{
|
|
||||||
"Series",
|
|
||||||
"Season",
|
|
||||||
"MusicAlbum",
|
|
||||||
"MusicArtist",
|
|
||||||
"PhotoAlbum"
|
|
||||||
};
|
|
||||||
|
|
||||||
if (excludeParentTypes.Contains(query.ParentType ?? string.Empty, StringComparer.OrdinalIgnoreCase))
|
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -2234,13 +2222,7 @@ namespace Emby.Server.Implementations.Data
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
var types = new string[]
|
return query.IncludeItemTypes.Any(x => _startDateTypes.Contains(x));
|
||||||
{
|
|
||||||
"Program",
|
|
||||||
"LiveTvProgram"
|
|
||||||
};
|
|
||||||
|
|
||||||
return types.Any(i => query.IncludeItemTypes.Contains(i, StringComparer.OrdinalIgnoreCase));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool HasEpisodeAttributes(InternalItemsQuery query)
|
private bool HasEpisodeAttributes(InternalItemsQuery query)
|
||||||
@ -2263,16 +2245,26 @@ namespace Emby.Server.Implementations.Data
|
|||||||
return query.IncludeItemTypes.Contains("Trailer", StringComparer.OrdinalIgnoreCase);
|
return query.IncludeItemTypes.Contains("Trailer", StringComparer.OrdinalIgnoreCase);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static readonly HashSet<string> _artistExcludeParentTypes = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
|
||||||
|
{
|
||||||
|
"Series",
|
||||||
|
"Season",
|
||||||
|
"PhotoAlbum"
|
||||||
|
};
|
||||||
|
|
||||||
|
private static readonly HashSet<string> _artistsTypes = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
|
||||||
|
{
|
||||||
|
"Audio",
|
||||||
|
"MusicAlbum",
|
||||||
|
"MusicVideo",
|
||||||
|
"AudioBook",
|
||||||
|
"AudioPodcast"
|
||||||
|
};
|
||||||
|
|
||||||
private bool HasArtistFields(InternalItemsQuery query)
|
private bool HasArtistFields(InternalItemsQuery query)
|
||||||
{
|
{
|
||||||
var excludeParentTypes = new string[]
|
if (_artistExcludeParentTypes.Contains(query.ParentType))
|
||||||
{
|
|
||||||
"Series",
|
|
||||||
"Season",
|
|
||||||
"PhotoAlbum"
|
|
||||||
};
|
|
||||||
|
|
||||||
if (excludeParentTypes.Contains(query.ParentType ?? string.Empty, StringComparer.OrdinalIgnoreCase))
|
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -2282,18 +2274,18 @@ namespace Emby.Server.Implementations.Data
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
var types = new string[]
|
return query.IncludeItemTypes.Any(x => _artistsTypes.Contains(x));
|
||||||
{
|
|
||||||
"Audio",
|
|
||||||
"MusicAlbum",
|
|
||||||
"MusicVideo",
|
|
||||||
"AudioBook",
|
|
||||||
"AudioPodcast"
|
|
||||||
};
|
|
||||||
|
|
||||||
return types.Any(i => query.IncludeItemTypes.Contains(i, StringComparer.OrdinalIgnoreCase));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static readonly HashSet<string> _seriesTypes = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
|
||||||
|
{
|
||||||
|
"Audio",
|
||||||
|
"MusicAlbum",
|
||||||
|
"MusicVideo",
|
||||||
|
"AudioBook",
|
||||||
|
"AudioPodcast"
|
||||||
|
};
|
||||||
|
|
||||||
private bool HasSeriesFields(InternalItemsQuery query)
|
private bool HasSeriesFields(InternalItemsQuery query)
|
||||||
{
|
{
|
||||||
if (string.Equals(query.ParentType, "PhotoAlbum", StringComparison.OrdinalIgnoreCase))
|
if (string.Equals(query.ParentType, "PhotoAlbum", StringComparison.OrdinalIgnoreCase))
|
||||||
@ -2306,26 +2298,18 @@ namespace Emby.Server.Implementations.Data
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
var types = new string[]
|
return query.IncludeItemTypes.Any(x => _seriesTypes.Contains(x));
|
||||||
{
|
|
||||||
"Book",
|
|
||||||
"AudioBook",
|
|
||||||
"Episode",
|
|
||||||
"Season"
|
|
||||||
};
|
|
||||||
|
|
||||||
return types.Any(i => query.IncludeItemTypes.Contains(i, StringComparer.OrdinalIgnoreCase));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private string[] GetFinalColumnsToSelect(InternalItemsQuery query, string[] startColumns)
|
private List<string> GetFinalColumnsToSelect(InternalItemsQuery query, IEnumerable<string> startColumns)
|
||||||
{
|
{
|
||||||
var list = startColumns.ToList();
|
var list = startColumns.ToList();
|
||||||
|
|
||||||
foreach (var field in allFields)
|
foreach (var field in _allFields)
|
||||||
{
|
{
|
||||||
if (!HasField(query, field))
|
if (!HasField(query, field))
|
||||||
{
|
{
|
||||||
foreach (var fieldToRemove in GetColumnNamesFromField(field).ToList())
|
foreach (var fieldToRemove in GetColumnNamesFromField(field))
|
||||||
{
|
{
|
||||||
list.Remove(fieldToRemove);
|
list.Remove(fieldToRemove);
|
||||||
}
|
}
|
||||||
@ -2419,11 +2403,14 @@ namespace Emby.Server.Implementations.Data
|
|||||||
|
|
||||||
list.Add(builder.ToString());
|
list.Add(builder.ToString());
|
||||||
|
|
||||||
var excludeIds = query.ExcludeItemIds.ToList();
|
var oldLen = query.ExcludeItemIds.Length;
|
||||||
excludeIds.Add(item.Id);
|
var newLen = oldLen + item.ExtraIds.Length + 1;
|
||||||
excludeIds.AddRange(item.ExtraIds);
|
var excludeIds = new Guid[newLen];
|
||||||
|
query.ExcludeItemIds.CopyTo(excludeIds, 0);
|
||||||
|
excludeIds[oldLen] = item.Id;
|
||||||
|
item.ExtraIds.CopyTo(excludeIds, oldLen + 1);
|
||||||
|
|
||||||
query.ExcludeItemIds = excludeIds.ToArray();
|
query.ExcludeItemIds = excludeIds;
|
||||||
query.ExcludeProviderIds = item.ProviderIds;
|
query.ExcludeProviderIds = item.ProviderIds;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2444,7 +2431,7 @@ namespace Emby.Server.Implementations.Data
|
|||||||
list.Add(builder.ToString());
|
list.Add(builder.ToString());
|
||||||
}
|
}
|
||||||
|
|
||||||
return list.ToArray();
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void BindSearchParams(InternalItemsQuery query, IStatement statement)
|
private void BindSearchParams(InternalItemsQuery query, IStatement statement)
|
||||||
@ -2723,18 +2710,17 @@ namespace Emby.Server.Implementations.Data
|
|||||||
|
|
||||||
private void AddItem(List<BaseItem> items, BaseItem newItem)
|
private void AddItem(List<BaseItem> items, BaseItem newItem)
|
||||||
{
|
{
|
||||||
var providerIds = newItem.ProviderIds.ToList();
|
|
||||||
|
|
||||||
for (var i = 0; i < items.Count; i++)
|
for (var i = 0; i < items.Count; i++)
|
||||||
{
|
{
|
||||||
var item = items[i];
|
var item = items[i];
|
||||||
|
|
||||||
foreach (var providerId in providerIds)
|
foreach (var providerId in newItem.ProviderIds)
|
||||||
{
|
{
|
||||||
if (providerId.Key == MetadataProviders.TmdbCollection.ToString())
|
if (providerId.Key == MetadataProviders.TmdbCollection.ToString())
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (item.GetProviderId(providerId.Key) == providerId.Value)
|
if (item.GetProviderId(providerId.Key) == providerId.Value)
|
||||||
{
|
{
|
||||||
if (newItem.SourceType == SourceType.Library)
|
if (newItem.SourceType == SourceType.Library)
|
||||||
@ -2753,10 +2739,10 @@ namespace Emby.Server.Implementations.Data
|
|||||||
{
|
{
|
||||||
var elapsed = (DateTime.UtcNow - startDate).TotalMilliseconds;
|
var elapsed = (DateTime.UtcNow - startDate).TotalMilliseconds;
|
||||||
|
|
||||||
int slowThreshold = 1000;
|
int slowThreshold = 100;
|
||||||
|
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
slowThreshold = 250;
|
slowThreshold = 10;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (elapsed >= slowThreshold)
|
if (elapsed >= slowThreshold)
|
||||||
@ -2806,7 +2792,7 @@ namespace Emby.Server.Implementations.Data
|
|||||||
|
|
||||||
var whereText = whereClauses.Count == 0 ?
|
var whereText = whereClauses.Count == 0 ?
|
||||||
string.Empty :
|
string.Empty :
|
||||||
" where " + string.Join(" AND ", whereClauses.ToArray());
|
" where " + string.Join(" AND ", whereClauses);
|
||||||
|
|
||||||
commandText += whereText
|
commandText += whereText
|
||||||
+ GetGroupBy(query)
|
+ GetGroupBy(query)
|
||||||
@ -2930,25 +2916,31 @@ namespace Emby.Server.Implementations.Data
|
|||||||
|
|
||||||
private string GetOrderByText(InternalItemsQuery query)
|
private string GetOrderByText(InternalItemsQuery query)
|
||||||
{
|
{
|
||||||
var orderBy = query.OrderBy.ToList();
|
if (string.IsNullOrEmpty(query.SearchTerm))
|
||||||
var enableOrderInversion = false;
|
|
||||||
|
|
||||||
if (query.SimilarTo != null && orderBy.Count == 0)
|
|
||||||
{
|
{
|
||||||
orderBy.Add(new ValueTuple<string, SortOrder>("SimilarityScore", SortOrder.Descending));
|
int oldLen = query.OrderBy.Length;
|
||||||
orderBy.Add(new ValueTuple<string, SortOrder>(ItemSortBy.Random, SortOrder.Ascending));
|
|
||||||
|
if (query.SimilarTo != null && oldLen == 0)
|
||||||
|
{
|
||||||
|
var arr = new (string, SortOrder)[oldLen + 2];
|
||||||
|
query.OrderBy.CopyTo(arr, 0);
|
||||||
|
arr[oldLen] = ("SimilarityScore", SortOrder.Descending);
|
||||||
|
arr[oldLen + 1] = (ItemSortBy.Random, SortOrder.Ascending);
|
||||||
|
query.OrderBy = arr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
query.OrderBy = new []
|
||||||
|
{
|
||||||
|
("SearchScore", SortOrder.Descending),
|
||||||
|
(ItemSortBy.SortName, SortOrder.Ascending)
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(query.SearchTerm))
|
var orderBy = query.OrderBy;
|
||||||
{
|
|
||||||
orderBy = new List<(string, SortOrder)>();
|
|
||||||
orderBy.Add(new ValueTuple<string, SortOrder>("SearchScore", SortOrder.Descending));
|
|
||||||
orderBy.Add(new ValueTuple<string, SortOrder>(ItemSortBy.SortName, SortOrder.Ascending));
|
|
||||||
}
|
|
||||||
|
|
||||||
query.OrderBy = orderBy.ToArray();
|
if (orderBy.Length == 0)
|
||||||
|
|
||||||
if (orderBy.Count == 0)
|
|
||||||
{
|
{
|
||||||
return string.Empty;
|
return string.Empty;
|
||||||
}
|
}
|
||||||
@ -2957,6 +2949,7 @@ namespace Emby.Server.Implementations.Data
|
|||||||
{
|
{
|
||||||
var columnMap = MapOrderByField(i.Item1, query);
|
var columnMap = MapOrderByField(i.Item1, query);
|
||||||
var columnAscending = i.Item2 == SortOrder.Ascending;
|
var columnAscending = i.Item2 == SortOrder.Ascending;
|
||||||
|
const bool enableOrderInversion = false;
|
||||||
if (columnMap.Item2 && enableOrderInversion)
|
if (columnMap.Item2 && enableOrderInversion)
|
||||||
{
|
{
|
||||||
columnAscending = !columnAscending;
|
columnAscending = !columnAscending;
|
||||||
@ -2968,7 +2961,7 @@ namespace Emby.Server.Implementations.Data
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
private ValueTuple<string, bool> MapOrderByField(string name, InternalItemsQuery query)
|
private (string, bool) MapOrderByField(string name, InternalItemsQuery query)
|
||||||
{
|
{
|
||||||
if (string.Equals(name, ItemSortBy.AirTime, StringComparison.OrdinalIgnoreCase))
|
if (string.Equals(name, ItemSortBy.AirTime, StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
@ -3218,7 +3211,7 @@ namespace Emby.Server.Implementations.Data
|
|||||||
|
|
||||||
var whereText = whereClauses.Count == 0 ?
|
var whereText = whereClauses.Count == 0 ?
|
||||||
string.Empty :
|
string.Empty :
|
||||||
" where " + string.Join(" AND ", whereClauses.ToArray());
|
" where " + string.Join(" AND ", whereClauses);
|
||||||
|
|
||||||
commandText += whereText
|
commandText += whereText
|
||||||
+ GetGroupBy(query)
|
+ GetGroupBy(query)
|
||||||
@ -4378,7 +4371,7 @@ namespace Emby.Server.Implementations.Data
|
|||||||
}
|
}
|
||||||
else if (query.Years.Length > 1)
|
else if (query.Years.Length > 1)
|
||||||
{
|
{
|
||||||
var val = string.Join(",", query.Years.ToArray());
|
var val = string.Join(",", query.Years);
|
||||||
|
|
||||||
whereClauses.Add("ProductionYear in (" + val + ")");
|
whereClauses.Add("ProductionYear in (" + val + ")");
|
||||||
}
|
}
|
||||||
@ -4952,7 +4945,12 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
return new[] { value }.Where(IsValidType);
|
if (IsValidType(value))
|
||||||
|
{
|
||||||
|
return new[] { value };
|
||||||
|
}
|
||||||
|
|
||||||
|
return Array.Empty<string>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void DeleteItem(Guid id, CancellationToken cancellationToken)
|
public void DeleteItem(Guid id, CancellationToken cancellationToken)
|
||||||
@ -5215,32 +5213,32 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public QueryResult<Tuple<BaseItem, ItemCounts>> GetAllArtists(InternalItemsQuery query)
|
public QueryResult<(BaseItem, ItemCounts)> GetAllArtists(InternalItemsQuery query)
|
||||||
{
|
{
|
||||||
return GetItemValues(query, new[] { 0, 1 }, typeof(MusicArtist).FullName);
|
return GetItemValues(query, new[] { 0, 1 }, typeof(MusicArtist).FullName);
|
||||||
}
|
}
|
||||||
|
|
||||||
public QueryResult<Tuple<BaseItem, ItemCounts>> GetArtists(InternalItemsQuery query)
|
public QueryResult<(BaseItem, ItemCounts)> GetArtists(InternalItemsQuery query)
|
||||||
{
|
{
|
||||||
return GetItemValues(query, new[] { 0 }, typeof(MusicArtist).FullName);
|
return GetItemValues(query, new[] { 0 }, typeof(MusicArtist).FullName);
|
||||||
}
|
}
|
||||||
|
|
||||||
public QueryResult<Tuple<BaseItem, ItemCounts>> GetAlbumArtists(InternalItemsQuery query)
|
public QueryResult<(BaseItem, ItemCounts)> GetAlbumArtists(InternalItemsQuery query)
|
||||||
{
|
{
|
||||||
return GetItemValues(query, new[] { 1 }, typeof(MusicArtist).FullName);
|
return GetItemValues(query, new[] { 1 }, typeof(MusicArtist).FullName);
|
||||||
}
|
}
|
||||||
|
|
||||||
public QueryResult<Tuple<BaseItem, ItemCounts>> GetStudios(InternalItemsQuery query)
|
public QueryResult<(BaseItem, ItemCounts)> GetStudios(InternalItemsQuery query)
|
||||||
{
|
{
|
||||||
return GetItemValues(query, new[] { 3 }, typeof(Studio).FullName);
|
return GetItemValues(query, new[] { 3 }, typeof(Studio).FullName);
|
||||||
}
|
}
|
||||||
|
|
||||||
public QueryResult<Tuple<BaseItem, ItemCounts>> GetGenres(InternalItemsQuery query)
|
public QueryResult<(BaseItem, ItemCounts)> GetGenres(InternalItemsQuery query)
|
||||||
{
|
{
|
||||||
return GetItemValues(query, new[] { 2 }, typeof(Genre).FullName);
|
return GetItemValues(query, new[] { 2 }, typeof(Genre).FullName);
|
||||||
}
|
}
|
||||||
|
|
||||||
public QueryResult<Tuple<BaseItem, ItemCounts>> GetMusicGenres(InternalItemsQuery query)
|
public QueryResult<(BaseItem, ItemCounts)> GetMusicGenres(InternalItemsQuery query)
|
||||||
{
|
{
|
||||||
return GetItemValues(query, new[] { 2 }, typeof(MusicGenre).FullName);
|
return GetItemValues(query, new[] { 2 }, typeof(MusicGenre).FullName);
|
||||||
}
|
}
|
||||||
@ -5317,7 +5315,7 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private QueryResult<Tuple<BaseItem, ItemCounts>> GetItemValues(InternalItemsQuery query, int[] itemValueTypes, string returnType)
|
private QueryResult<(BaseItem, ItemCounts)> GetItemValues(InternalItemsQuery query, int[] itemValueTypes, string returnType)
|
||||||
{
|
{
|
||||||
if (query == null)
|
if (query == null)
|
||||||
{
|
{
|
||||||
@ -5335,7 +5333,7 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type
|
|||||||
|
|
||||||
var typeClause = itemValueTypes.Length == 1 ?
|
var typeClause = itemValueTypes.Length == 1 ?
|
||||||
("Type=" + itemValueTypes[0].ToString(CultureInfo.InvariantCulture)) :
|
("Type=" + itemValueTypes[0].ToString(CultureInfo.InvariantCulture)) :
|
||||||
("Type in (" + string.Join(",", itemValueTypes.Select(i => i.ToString(CultureInfo.InvariantCulture)).ToArray()) + ")");
|
("Type in (" + string.Join(",", itemValueTypes.Select(i => i.ToString(CultureInfo.InvariantCulture))) + ")");
|
||||||
|
|
||||||
InternalItemsQuery typeSubQuery = null;
|
InternalItemsQuery typeSubQuery = null;
|
||||||
|
|
||||||
@ -5363,11 +5361,7 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type
|
|||||||
|
|
||||||
whereClauses.Add("guid in (select ItemId from ItemValues where ItemValues.CleanValue=A.CleanName AND " + typeClause + ")");
|
whereClauses.Add("guid in (select ItemId from ItemValues where ItemValues.CleanValue=A.CleanName AND " + typeClause + ")");
|
||||||
|
|
||||||
var typeWhereText = whereClauses.Count == 0 ?
|
itemCountColumnQuery += " where " + string.Join(" AND ", whereClauses);
|
||||||
string.Empty :
|
|
||||||
" where " + string.Join(" AND ", whereClauses);
|
|
||||||
|
|
||||||
itemCountColumnQuery += typeWhereText;
|
|
||||||
|
|
||||||
itemCountColumns = new Dictionary<string, string>()
|
itemCountColumns = new Dictionary<string, string>()
|
||||||
{
|
{
|
||||||
@ -5400,7 +5394,7 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type
|
|||||||
IsSeries = query.IsSeries
|
IsSeries = query.IsSeries
|
||||||
};
|
};
|
||||||
|
|
||||||
columns = GetFinalColumnsToSelect(query, columns.ToArray()).ToList();
|
columns = GetFinalColumnsToSelect(query, columns);
|
||||||
|
|
||||||
var commandText = "select "
|
var commandText = "select "
|
||||||
+ string.Join(",", columns)
|
+ string.Join(",", columns)
|
||||||
@ -5492,8 +5486,8 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type
|
|||||||
{
|
{
|
||||||
return connection.RunInTransaction(db =>
|
return connection.RunInTransaction(db =>
|
||||||
{
|
{
|
||||||
var list = new List<Tuple<BaseItem, ItemCounts>>();
|
var list = new List<(BaseItem, ItemCounts)>();
|
||||||
var result = new QueryResult<Tuple<BaseItem, ItemCounts>>();
|
var result = new QueryResult<(BaseItem, ItemCounts)>();
|
||||||
|
|
||||||
var statements = PrepareAllSafe(db, statementTexts);
|
var statements = PrepareAllSafe(db, statementTexts);
|
||||||
|
|
||||||
@ -5531,7 +5525,7 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type
|
|||||||
{
|
{
|
||||||
var countStartColumn = columns.Count - 1;
|
var countStartColumn = columns.Count - 1;
|
||||||
|
|
||||||
list.Add(new Tuple<BaseItem, ItemCounts>(item, GetItemCounts(row, countStartColumn, typesToCount)));
|
list.Add((item, GetItemCounts(row, countStartColumn, typesToCount)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -6198,6 +6192,5 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type
|
|||||||
|
|
||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -90,7 +90,7 @@ namespace Emby.Server.Implementations.HttpServer
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private IHasHeaders GetHttpResult(IRequest requestContext, Stream content, string contentType, bool addCachePrevention, IDictionary<string, string> responseHeaders = null)
|
private IHasHeaders GetHttpResult(IRequest requestContext, Stream content, string contentType, bool addCachePrevention, IDictionary<string, string> responseHeaders = null)
|
||||||
{
|
{
|
||||||
var result = new StreamWriter(content, contentType, _logger);
|
var result = new StreamWriter(content, contentType);
|
||||||
|
|
||||||
if (responseHeaders == null)
|
if (responseHeaders == null)
|
||||||
{
|
{
|
||||||
@ -131,7 +131,7 @@ namespace Emby.Server.Implementations.HttpServer
|
|||||||
content = Array.Empty<byte>();
|
content = Array.Empty<byte>();
|
||||||
}
|
}
|
||||||
|
|
||||||
result = new StreamWriter(content, contentType, contentLength, _logger);
|
result = new StreamWriter(content, contentType, contentLength);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -143,7 +143,7 @@ namespace Emby.Server.Implementations.HttpServer
|
|||||||
responseHeaders = new Dictionary<string, string>();
|
responseHeaders = new Dictionary<string, string>();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (addCachePrevention && !responseHeaders.TryGetValue("Expires", out string expires))
|
if (addCachePrevention && !responseHeaders.TryGetValue("Expires", out string _))
|
||||||
{
|
{
|
||||||
responseHeaders["Expires"] = "-1";
|
responseHeaders["Expires"] = "-1";
|
||||||
}
|
}
|
||||||
@ -175,7 +175,7 @@ namespace Emby.Server.Implementations.HttpServer
|
|||||||
bytes = Array.Empty<byte>();
|
bytes = Array.Empty<byte>();
|
||||||
}
|
}
|
||||||
|
|
||||||
result = new StreamWriter(bytes, contentType, contentLength, _logger);
|
result = new StreamWriter(bytes, contentType, contentLength);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -187,7 +187,7 @@ namespace Emby.Server.Implementations.HttpServer
|
|||||||
responseHeaders = new Dictionary<string, string>();
|
responseHeaders = new Dictionary<string, string>();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (addCachePrevention && !responseHeaders.TryGetValue("Expires", out string expires))
|
if (addCachePrevention && !responseHeaders.TryGetValue("Expires", out string _))
|
||||||
{
|
{
|
||||||
responseHeaders["Expires"] = "-1";
|
responseHeaders["Expires"] = "-1";
|
||||||
}
|
}
|
||||||
@ -277,9 +277,10 @@ namespace Emby.Server.Implementations.HttpServer
|
|||||||
|
|
||||||
private object ToOptimizedResultInternal<T>(IRequest request, T dto, IDictionary<string, string> responseHeaders = null)
|
private object ToOptimizedResultInternal<T>(IRequest request, T dto, IDictionary<string, string> responseHeaders = null)
|
||||||
{
|
{
|
||||||
var contentType = request.ResponseContentType;
|
// TODO: @bond use Span and .Equals
|
||||||
|
var contentType = request.ResponseContentType?.Split(';')[0].Trim().ToLowerInvariant();
|
||||||
|
|
||||||
switch (GetRealContentType(contentType))
|
switch (contentType)
|
||||||
{
|
{
|
||||||
case "application/xml":
|
case "application/xml":
|
||||||
case "text/xml":
|
case "text/xml":
|
||||||
@ -333,13 +334,13 @@ namespace Emby.Server.Implementations.HttpServer
|
|||||||
|
|
||||||
if (isHeadRequest)
|
if (isHeadRequest)
|
||||||
{
|
{
|
||||||
var result = new StreamWriter(Array.Empty<byte>(), contentType, contentLength, _logger);
|
var result = new StreamWriter(Array.Empty<byte>(), contentType, contentLength);
|
||||||
AddResponseHeaders(result, responseHeaders);
|
AddResponseHeaders(result, responseHeaders);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var result = new StreamWriter(content, contentType, contentLength, _logger);
|
var result = new StreamWriter(content, contentType, contentLength);
|
||||||
AddResponseHeaders(result, responseHeaders);
|
AddResponseHeaders(result, responseHeaders);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -348,13 +349,19 @@ namespace Emby.Server.Implementations.HttpServer
|
|||||||
private byte[] Compress(byte[] bytes, string compressionType)
|
private byte[] Compress(byte[] bytes, string compressionType)
|
||||||
{
|
{
|
||||||
if (string.Equals(compressionType, "br", StringComparison.OrdinalIgnoreCase))
|
if (string.Equals(compressionType, "br", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
return CompressBrotli(bytes);
|
return CompressBrotli(bytes);
|
||||||
|
}
|
||||||
|
|
||||||
if (string.Equals(compressionType, "deflate", StringComparison.OrdinalIgnoreCase))
|
if (string.Equals(compressionType, "deflate", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
return Deflate(bytes);
|
return Deflate(bytes);
|
||||||
|
}
|
||||||
|
|
||||||
if (string.Equals(compressionType, "gzip", StringComparison.OrdinalIgnoreCase))
|
if (string.Equals(compressionType, "gzip", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
return GZip(bytes);
|
return GZip(bytes);
|
||||||
|
}
|
||||||
|
|
||||||
throw new NotSupportedException(compressionType);
|
throw new NotSupportedException(compressionType);
|
||||||
}
|
}
|
||||||
@ -390,13 +397,6 @@ namespace Emby.Server.Implementations.HttpServer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string GetRealContentType(string contentType)
|
|
||||||
{
|
|
||||||
return contentType == null
|
|
||||||
? null
|
|
||||||
: contentType.Split(';')[0].ToLowerInvariant().Trim();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string SerializeToXmlString(object from)
|
private static string SerializeToXmlString(object from)
|
||||||
{
|
{
|
||||||
using (var ms = new MemoryStream())
|
using (var ms = new MemoryStream())
|
||||||
@ -603,7 +603,7 @@ namespace Emby.Server.Implementations.HttpServer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var hasHeaders = new StreamWriter(stream, contentType, _logger)
|
var hasHeaders = new StreamWriter(stream, contentType)
|
||||||
{
|
{
|
||||||
OnComplete = options.OnComplete,
|
OnComplete = options.OnComplete,
|
||||||
OnError = options.OnError
|
OnError = options.OnError
|
||||||
|
@ -14,8 +14,6 @@ namespace Emby.Server.Implementations.HttpServer
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class StreamWriter : IAsyncStreamWriter, IHasHeaders
|
public class StreamWriter : IAsyncStreamWriter, IHasHeaders
|
||||||
{
|
{
|
||||||
private ILogger Logger { get; set; }
|
|
||||||
|
|
||||||
private static readonly CultureInfo UsCulture = new CultureInfo("en-US");
|
private static readonly CultureInfo UsCulture = new CultureInfo("en-US");
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -45,7 +43,7 @@ namespace Emby.Server.Implementations.HttpServer
|
|||||||
/// <param name="source">The source.</param>
|
/// <param name="source">The source.</param>
|
||||||
/// <param name="contentType">Type of the content.</param>
|
/// <param name="contentType">Type of the content.</param>
|
||||||
/// <param name="logger">The logger.</param>
|
/// <param name="logger">The logger.</param>
|
||||||
public StreamWriter(Stream source, string contentType, ILogger logger)
|
public StreamWriter(Stream source, string contentType)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(contentType))
|
if (string.IsNullOrEmpty(contentType))
|
||||||
{
|
{
|
||||||
@ -53,7 +51,6 @@ namespace Emby.Server.Implementations.HttpServer
|
|||||||
}
|
}
|
||||||
|
|
||||||
SourceStream = source;
|
SourceStream = source;
|
||||||
Logger = logger;
|
|
||||||
|
|
||||||
Headers["Content-Type"] = contentType;
|
Headers["Content-Type"] = contentType;
|
||||||
|
|
||||||
@ -69,7 +66,7 @@ namespace Emby.Server.Implementations.HttpServer
|
|||||||
/// <param name="source">The source.</param>
|
/// <param name="source">The source.</param>
|
||||||
/// <param name="contentType">Type of the content.</param>
|
/// <param name="contentType">Type of the content.</param>
|
||||||
/// <param name="logger">The logger.</param>
|
/// <param name="logger">The logger.</param>
|
||||||
public StreamWriter(byte[] source, string contentType, int contentLength, ILogger logger)
|
public StreamWriter(byte[] source, string contentType, int contentLength)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(contentType))
|
if (string.IsNullOrEmpty(contentType))
|
||||||
{
|
{
|
||||||
@ -77,7 +74,6 @@ namespace Emby.Server.Implementations.HttpServer
|
|||||||
}
|
}
|
||||||
|
|
||||||
SourceBytes = source;
|
SourceBytes = source;
|
||||||
Logger = logger;
|
|
||||||
|
|
||||||
Headers["Content-Type"] = contentType;
|
Headers["Content-Type"] = contentType;
|
||||||
|
|
||||||
|
@ -1225,9 +1225,9 @@ namespace Emby.Server.Implementations.Library
|
|||||||
/// <exception cref="ArgumentNullException">id</exception>
|
/// <exception cref="ArgumentNullException">id</exception>
|
||||||
public BaseItem GetItemById(Guid id)
|
public BaseItem GetItemById(Guid id)
|
||||||
{
|
{
|
||||||
if (id.Equals(Guid.Empty))
|
if (id == Guid.Empty)
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException(nameof(id));
|
throw new ArgumentException(nameof(id), "Guid can't be empty");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (LibraryItemsCache.TryGetValue(id, out BaseItem item))
|
if (LibraryItemsCache.TryGetValue(id, out BaseItem item))
|
||||||
@ -1237,8 +1237,6 @@ namespace Emby.Server.Implementations.Library
|
|||||||
|
|
||||||
item = RetrieveItem(id);
|
item = RetrieveItem(id);
|
||||||
|
|
||||||
//_logger.LogDebug("GetitemById {0}", id);
|
|
||||||
|
|
||||||
if (item != null)
|
if (item != null)
|
||||||
{
|
{
|
||||||
RegisterItem(item);
|
RegisterItem(item);
|
||||||
@ -1333,7 +1331,7 @@ namespace Emby.Server.Implementations.Library
|
|||||||
return ItemRepository.GetItemIdsList(query);
|
return ItemRepository.GetItemIdsList(query);
|
||||||
}
|
}
|
||||||
|
|
||||||
public QueryResult<Tuple<BaseItem, ItemCounts>> GetStudios(InternalItemsQuery query)
|
public QueryResult<(BaseItem, ItemCounts)> GetStudios(InternalItemsQuery query)
|
||||||
{
|
{
|
||||||
if (query.User != null)
|
if (query.User != null)
|
||||||
{
|
{
|
||||||
@ -1344,7 +1342,7 @@ namespace Emby.Server.Implementations.Library
|
|||||||
return ItemRepository.GetStudios(query);
|
return ItemRepository.GetStudios(query);
|
||||||
}
|
}
|
||||||
|
|
||||||
public QueryResult<Tuple<BaseItem, ItemCounts>> GetGenres(InternalItemsQuery query)
|
public QueryResult<(BaseItem, ItemCounts)> GetGenres(InternalItemsQuery query)
|
||||||
{
|
{
|
||||||
if (query.User != null)
|
if (query.User != null)
|
||||||
{
|
{
|
||||||
@ -1355,7 +1353,7 @@ namespace Emby.Server.Implementations.Library
|
|||||||
return ItemRepository.GetGenres(query);
|
return ItemRepository.GetGenres(query);
|
||||||
}
|
}
|
||||||
|
|
||||||
public QueryResult<Tuple<BaseItem, ItemCounts>> GetMusicGenres(InternalItemsQuery query)
|
public QueryResult<(BaseItem, ItemCounts)> GetMusicGenres(InternalItemsQuery query)
|
||||||
{
|
{
|
||||||
if (query.User != null)
|
if (query.User != null)
|
||||||
{
|
{
|
||||||
@ -1366,7 +1364,7 @@ namespace Emby.Server.Implementations.Library
|
|||||||
return ItemRepository.GetMusicGenres(query);
|
return ItemRepository.GetMusicGenres(query);
|
||||||
}
|
}
|
||||||
|
|
||||||
public QueryResult<Tuple<BaseItem, ItemCounts>> GetAllArtists(InternalItemsQuery query)
|
public QueryResult<(BaseItem, ItemCounts)> GetAllArtists(InternalItemsQuery query)
|
||||||
{
|
{
|
||||||
if (query.User != null)
|
if (query.User != null)
|
||||||
{
|
{
|
||||||
@ -1377,7 +1375,7 @@ namespace Emby.Server.Implementations.Library
|
|||||||
return ItemRepository.GetAllArtists(query);
|
return ItemRepository.GetAllArtists(query);
|
||||||
}
|
}
|
||||||
|
|
||||||
public QueryResult<Tuple<BaseItem, ItemCounts>> GetArtists(InternalItemsQuery query)
|
public QueryResult<(BaseItem, ItemCounts)> GetArtists(InternalItemsQuery query)
|
||||||
{
|
{
|
||||||
if (query.User != null)
|
if (query.User != null)
|
||||||
{
|
{
|
||||||
@ -1421,7 +1419,7 @@ namespace Emby.Server.Implementations.Library
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public QueryResult<Tuple<BaseItem, ItemCounts>> GetAlbumArtists(InternalItemsQuery query)
|
public QueryResult<(BaseItem, ItemCounts)> GetAlbumArtists(InternalItemsQuery query)
|
||||||
{
|
{
|
||||||
if (query.User != null)
|
if (query.User != null)
|
||||||
{
|
{
|
||||||
@ -1808,18 +1806,16 @@ namespace Emby.Server.Implementations.Library
|
|||||||
/// <returns>Task.</returns>
|
/// <returns>Task.</returns>
|
||||||
public void CreateItems(IEnumerable<BaseItem> items, BaseItem parent, CancellationToken cancellationToken)
|
public void CreateItems(IEnumerable<BaseItem> items, BaseItem parent, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var list = items.ToList();
|
ItemRepository.SaveItems(items, cancellationToken);
|
||||||
|
|
||||||
ItemRepository.SaveItems(list, cancellationToken);
|
foreach (var item in items)
|
||||||
|
|
||||||
foreach (var item in list)
|
|
||||||
{
|
{
|
||||||
RegisterItem(item);
|
RegisterItem(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ItemAdded != null)
|
if (ItemAdded != null)
|
||||||
{
|
{
|
||||||
foreach (var item in list)
|
foreach (var item in items)
|
||||||
{
|
{
|
||||||
// With the live tv guide this just creates too much noise
|
// With the live tv guide this just creates too much noise
|
||||||
if (item.SourceType != SourceType.Library)
|
if (item.SourceType != SourceType.Library)
|
||||||
@ -1853,7 +1849,7 @@ namespace Emby.Server.Implementations.Library
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Updates the item.
|
/// Updates the item.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void UpdateItems(List<BaseItem> items, BaseItem parent, ItemUpdateType updateReason, CancellationToken cancellationToken)
|
public void UpdateItems(IEnumerable<BaseItem> items, BaseItem parent, ItemUpdateType updateReason, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
foreach (var item in items)
|
foreach (var item in items)
|
||||||
{
|
{
|
||||||
@ -1908,7 +1904,7 @@ namespace Emby.Server.Implementations.Library
|
|||||||
/// <returns>Task.</returns>
|
/// <returns>Task.</returns>
|
||||||
public void UpdateItem(BaseItem item, BaseItem parent, ItemUpdateType updateReason, CancellationToken cancellationToken)
|
public void UpdateItem(BaseItem item, BaseItem parent, ItemUpdateType updateReason, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
UpdateItems(new List<BaseItem> { item }, parent, updateReason, cancellationToken);
|
UpdateItems(new [] { item }, parent, updateReason, cancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -2005,9 +2001,7 @@ namespace Emby.Server.Implementations.Library
|
|||||||
.FirstOrDefault();
|
.FirstOrDefault();
|
||||||
}
|
}
|
||||||
|
|
||||||
var options = collectionFolder == null ? new LibraryOptions() : collectionFolder.GetLibraryOptions();
|
return collectionFolder == null ? new LibraryOptions() : collectionFolder.GetLibraryOptions();
|
||||||
|
|
||||||
return options;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public string GetContentType(BaseItem item)
|
public string GetContentType(BaseItem item)
|
||||||
@ -2017,11 +2011,13 @@ namespace Emby.Server.Implementations.Library
|
|||||||
{
|
{
|
||||||
return configuredContentType;
|
return configuredContentType;
|
||||||
}
|
}
|
||||||
|
|
||||||
configuredContentType = GetConfiguredContentType(item, true);
|
configuredContentType = GetConfiguredContentType(item, true);
|
||||||
if (!string.IsNullOrEmpty(configuredContentType))
|
if (!string.IsNullOrEmpty(configuredContentType))
|
||||||
{
|
{
|
||||||
return configuredContentType;
|
return configuredContentType;
|
||||||
}
|
}
|
||||||
|
|
||||||
return GetInheritedContentType(item);
|
return GetInheritedContentType(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2056,6 +2052,7 @@ namespace Emby.Server.Implementations.Library
|
|||||||
{
|
{
|
||||||
return collectionFolder.CollectionType;
|
return collectionFolder.CollectionType;
|
||||||
}
|
}
|
||||||
|
|
||||||
return GetContentTypeOverride(item.ContainingFolderPath, inheritConfiguredPath);
|
return GetContentTypeOverride(item.ContainingFolderPath, inheritConfiguredPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2066,6 +2063,7 @@ namespace Emby.Server.Implementations.Library
|
|||||||
{
|
{
|
||||||
return nameValuePair.Value;
|
return nameValuePair.Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2108,9 +2106,9 @@ namespace Emby.Server.Implementations.Library
|
|||||||
string viewType,
|
string viewType,
|
||||||
string sortName)
|
string sortName)
|
||||||
{
|
{
|
||||||
var path = Path.Combine(ConfigurationManager.ApplicationPaths.InternalMetadataPath, "views");
|
var path = Path.Combine(ConfigurationManager.ApplicationPaths.InternalMetadataPath,
|
||||||
|
"views",
|
||||||
path = Path.Combine(path, _fileSystem.GetValidFilename(viewType));
|
_fileSystem.GetValidFilename(viewType));
|
||||||
|
|
||||||
var id = GetNewItemId(path + "_namedview_" + name, typeof(UserView));
|
var id = GetNewItemId(path + "_namedview_" + name, typeof(UserView));
|
||||||
|
|
||||||
|
@ -168,9 +168,9 @@ namespace Emby.Server.Implementations.Library
|
|||||||
/// <exception cref="ArgumentNullException"></exception>
|
/// <exception cref="ArgumentNullException"></exception>
|
||||||
public User GetUserById(Guid id)
|
public User GetUserById(Guid id)
|
||||||
{
|
{
|
||||||
if (id.Equals(Guid.Empty))
|
if (id == Guid.Empty)
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException(nameof(id));
|
throw new ArgumentException(nameof(id), "Guid can't be empty");
|
||||||
}
|
}
|
||||||
|
|
||||||
return Users.FirstOrDefault(u => u.Id == id);
|
return Users.FirstOrDefault(u => u.Id == id);
|
||||||
|
@ -184,7 +184,7 @@ namespace Emby.Server.Implementations.LiveTv
|
|||||||
|
|
||||||
public QueryResult<BaseItem> GetInternalChannels(LiveTvChannelQuery query, DtoOptions dtoOptions, CancellationToken cancellationToken)
|
public QueryResult<BaseItem> GetInternalChannels(LiveTvChannelQuery query, DtoOptions dtoOptions, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var user = query.UserId.Equals(Guid.Empty) ? null : _userManager.GetUserById(query.UserId);
|
var user = query.UserId == Guid.Empty ? null : _userManager.GetUserById(query.UserId);
|
||||||
|
|
||||||
var topFolder = GetInternalLiveTvFolder(cancellationToken);
|
var topFolder = GetInternalLiveTvFolder(cancellationToken);
|
||||||
|
|
||||||
|
@ -41,6 +41,27 @@ namespace Emby.Server.Implementations.Serialization
|
|||||||
ServiceStack.Text.JsonSerializer.SerializeToStream(obj, obj.GetType(), stream);
|
ServiceStack.Text.JsonSerializer.SerializeToStream(obj, obj.GetType(), stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Serializes to stream.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="obj">The obj.</param>
|
||||||
|
/// <param name="stream">The stream.</param>
|
||||||
|
/// <exception cref="ArgumentNullException">obj</exception>
|
||||||
|
public void SerializeToStream<T>(T obj, Stream stream)
|
||||||
|
{
|
||||||
|
if (obj == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(obj));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stream == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(stream));
|
||||||
|
}
|
||||||
|
|
||||||
|
ServiceStack.Text.JsonSerializer.SerializeToStream<T>(obj, stream);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Serializes to file.
|
/// Serializes to file.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -28,30 +28,6 @@ namespace Jellyfin.Server.SocketSharp
|
|||||||
// HandlerFactoryPath = GetHandlerPathIfAny(UrlPrefixes[0]);
|
// HandlerFactoryPath = GetHandlerPathIfAny(UrlPrefixes[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string GetHandlerPathIfAny(string listenerUrl)
|
|
||||||
{
|
|
||||||
if (listenerUrl == null)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
var pos = listenerUrl.IndexOf("://", StringComparison.OrdinalIgnoreCase);
|
|
||||||
if (pos == -1)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
var startHostUrl = listenerUrl.Substring(pos + "://".Length);
|
|
||||||
var endPos = startHostUrl.IndexOf('/', StringComparison.Ordinal);
|
|
||||||
if (endPos == -1)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
var endHostUrl = startHostUrl.Substring(endPos + 1);
|
|
||||||
return string.IsNullOrEmpty(endHostUrl) ? null : endHostUrl.TrimEnd('/');
|
|
||||||
}
|
|
||||||
|
|
||||||
public HttpListenerRequest HttpRequest => request;
|
public HttpListenerRequest HttpRequest => request;
|
||||||
|
|
||||||
public object OriginalRequest => request;
|
public object OriginalRequest => request;
|
||||||
@ -102,7 +78,7 @@ namespace Jellyfin.Server.SocketSharp
|
|||||||
name = name.Trim(HttpTrimCharacters);
|
name = name.Trim(HttpTrimCharacters);
|
||||||
|
|
||||||
// First, check for correctly formed multi-line value
|
// First, check for correctly formed multi-line value
|
||||||
// Second, check for absenece of CTL characters
|
// Second, check for absence of CTL characters
|
||||||
int crlf = 0;
|
int crlf = 0;
|
||||||
for (int i = 0; i < name.Length; ++i)
|
for (int i = 0; i < name.Length; ++i)
|
||||||
{
|
{
|
||||||
@ -231,8 +207,15 @@ namespace Jellyfin.Server.SocketSharp
|
|||||||
{
|
{
|
||||||
foreach (var acceptsType in acceptContentTypes)
|
foreach (var acceptsType in acceptContentTypes)
|
||||||
{
|
{
|
||||||
var contentType = HttpResultFactory.GetRealContentType(acceptsType);
|
// TODO: @bond move to Span when Span.Split lands
|
||||||
acceptsAnything = acceptsAnything || contentType == "*/*";
|
// https://github.com/dotnet/corefx/issues/26528
|
||||||
|
var contentType = acceptsType?.Split(';')[0].Trim();
|
||||||
|
acceptsAnything = contentType.Equals("*/*", StringComparison.OrdinalIgnoreCase);
|
||||||
|
|
||||||
|
if (acceptsAnything)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (acceptsAnything)
|
if (acceptsAnything)
|
||||||
@ -241,7 +224,7 @@ namespace Jellyfin.Server.SocketSharp
|
|||||||
{
|
{
|
||||||
return defaultContentType;
|
return defaultContentType;
|
||||||
}
|
}
|
||||||
else if (serverDefaultContentType != null)
|
else
|
||||||
{
|
{
|
||||||
return serverDefaultContentType;
|
return serverDefaultContentType;
|
||||||
}
|
}
|
||||||
@ -284,11 +267,11 @@ namespace Jellyfin.Server.SocketSharp
|
|||||||
|
|
||||||
private static string GetQueryStringContentType(IRequest httpReq)
|
private static string GetQueryStringContentType(IRequest httpReq)
|
||||||
{
|
{
|
||||||
var format = httpReq.QueryString["format"];
|
ReadOnlySpan<char> format = httpReq.QueryString["format"];
|
||||||
if (format == null)
|
if (format == null)
|
||||||
{
|
{
|
||||||
const int formatMaxLength = 4;
|
const int formatMaxLength = 4;
|
||||||
var pi = httpReq.PathInfo;
|
ReadOnlySpan<char> pi = httpReq.PathInfo;
|
||||||
if (pi == null || pi.Length <= formatMaxLength)
|
if (pi == null || pi.Length <= formatMaxLength)
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
@ -296,7 +279,7 @@ namespace Jellyfin.Server.SocketSharp
|
|||||||
|
|
||||||
if (pi[0] == '/')
|
if (pi[0] == '/')
|
||||||
{
|
{
|
||||||
pi = pi.Substring(1);
|
pi = pi.Slice(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
format = LeftPart(pi, '/');
|
format = LeftPart(pi, '/');
|
||||||
@ -330,6 +313,17 @@ namespace Jellyfin.Server.SocketSharp
|
|||||||
return pos == -1 ? strVal : strVal.Substring(0, pos);
|
return pos == -1 ? strVal : strVal.Substring(0, pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static ReadOnlySpan<char> LeftPart(ReadOnlySpan<char> strVal, char needle)
|
||||||
|
{
|
||||||
|
if (strVal == null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var pos = strVal.IndexOf(needle);
|
||||||
|
return pos == -1 ? strVal : strVal.Slice(0, pos);
|
||||||
|
}
|
||||||
|
|
||||||
public static string HandlerFactoryPath;
|
public static string HandlerFactoryPath;
|
||||||
|
|
||||||
private string pathInfo;
|
private string pathInfo;
|
||||||
@ -341,7 +335,7 @@ namespace Jellyfin.Server.SocketSharp
|
|||||||
{
|
{
|
||||||
var mode = HandlerFactoryPath;
|
var mode = HandlerFactoryPath;
|
||||||
|
|
||||||
var pos = request.RawUrl.IndexOf("?", StringComparison.Ordinal);
|
var pos = request.RawUrl.IndexOf('?', StringComparison.Ordinal);
|
||||||
if (pos != -1)
|
if (pos != -1)
|
||||||
{
|
{
|
||||||
var path = request.RawUrl.Substring(0, pos);
|
var path = request.RawUrl.Substring(0, pos);
|
||||||
@ -525,10 +519,13 @@ namespace Jellyfin.Server.SocketSharp
|
|||||||
|
|
||||||
public static string NormalizePathInfo(string pathInfo, string handlerPath)
|
public static string NormalizePathInfo(string pathInfo, string handlerPath)
|
||||||
{
|
{
|
||||||
var trimmed = pathInfo.TrimStart('/');
|
if (handlerPath != null)
|
||||||
if (handlerPath != null && trimmed.StartsWith(handlerPath, StringComparison.OrdinalIgnoreCase))
|
|
||||||
{
|
{
|
||||||
return trimmed.Substring(handlerPath.Length);
|
var trimmed = pathInfo.TrimStart('/');
|
||||||
|
if (trimmed.StartsWith(handlerPath, StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
return trimmed.Substring(handlerPath.Length);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return pathInfo;
|
return pathInfo;
|
||||||
|
@ -9,6 +9,7 @@ using MediaBrowser.Controller.Net;
|
|||||||
using MediaBrowser.Controller.Session;
|
using MediaBrowser.Controller.Session;
|
||||||
using MediaBrowser.Model.Entities;
|
using MediaBrowser.Model.Entities;
|
||||||
using MediaBrowser.Model.Services;
|
using MediaBrowser.Model.Services;
|
||||||
|
using MediaBrowser.Model.Querying;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
namespace MediaBrowser.Api
|
namespace MediaBrowser.Api
|
||||||
@ -118,8 +119,7 @@ namespace MediaBrowser.Api
|
|||||||
{
|
{
|
||||||
var options = new DtoOptions();
|
var options = new DtoOptions();
|
||||||
|
|
||||||
var hasFields = request as IHasItemFields;
|
if (request is IHasItemFields hasFields)
|
||||||
if (hasFields != null)
|
|
||||||
{
|
{
|
||||||
options.Fields = hasFields.GetItemFields();
|
options.Fields = hasFields.GetItemFields();
|
||||||
}
|
}
|
||||||
@ -133,9 +133,11 @@ namespace MediaBrowser.Api
|
|||||||
client.IndexOf("media center", StringComparison.OrdinalIgnoreCase) != -1 ||
|
client.IndexOf("media center", StringComparison.OrdinalIgnoreCase) != -1 ||
|
||||||
client.IndexOf("classic", StringComparison.OrdinalIgnoreCase) != -1)
|
client.IndexOf("classic", StringComparison.OrdinalIgnoreCase) != -1)
|
||||||
{
|
{
|
||||||
var list = options.Fields.ToList();
|
int oldLen = options.Fields.Length;
|
||||||
list.Add(Model.Querying.ItemFields.RecursiveItemCount);
|
var arr = new ItemFields[oldLen + 1];
|
||||||
options.Fields = list.ToArray();
|
options.Fields.CopyTo(arr, 0);
|
||||||
|
arr[oldLen] = Model.Querying.ItemFields.RecursiveItemCount;
|
||||||
|
options.Fields = arr;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (client.IndexOf("kodi", StringComparison.OrdinalIgnoreCase) != -1 ||
|
if (client.IndexOf("kodi", StringComparison.OrdinalIgnoreCase) != -1 ||
|
||||||
@ -146,9 +148,12 @@ namespace MediaBrowser.Api
|
|||||||
client.IndexOf("samsung", StringComparison.OrdinalIgnoreCase) != -1 ||
|
client.IndexOf("samsung", StringComparison.OrdinalIgnoreCase) != -1 ||
|
||||||
client.IndexOf("androidtv", StringComparison.OrdinalIgnoreCase) != -1)
|
client.IndexOf("androidtv", StringComparison.OrdinalIgnoreCase) != -1)
|
||||||
{
|
{
|
||||||
var list = options.Fields.ToList();
|
|
||||||
list.Add(Model.Querying.ItemFields.ChildCount);
|
int oldLen = options.Fields.Length;
|
||||||
options.Fields = list.ToArray();
|
var arr = new ItemFields[oldLen + 1];
|
||||||
|
options.Fields.CopyTo(arr, 0);
|
||||||
|
arr[oldLen] = Model.Querying.ItemFields.ChildCount;
|
||||||
|
options.Fields = arr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -167,7 +172,16 @@ namespace MediaBrowser.Api
|
|||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(hasDtoOptions.EnableImageTypes))
|
if (!string.IsNullOrWhiteSpace(hasDtoOptions.EnableImageTypes))
|
||||||
{
|
{
|
||||||
options.ImageTypes = (hasDtoOptions.EnableImageTypes ?? string.Empty).Split(',').Where(i => !string.IsNullOrWhiteSpace(i)).Select(v => (ImageType)Enum.Parse(typeof(ImageType), v, true)).ToArray();
|
if (string.IsNullOrEmpty(hasDtoOptions.EnableImageTypes))
|
||||||
|
{
|
||||||
|
options.ImageTypes = Array.Empty<ImageType>();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
options.ImageTypes = hasDtoOptions.EnableImageTypes.Split(new [] { ',' }, StringSplitOptions.RemoveEmptyEntries)
|
||||||
|
.Select(v => (ImageType)Enum.Parse(typeof(ImageType), v, true))
|
||||||
|
.ToArray();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -112,7 +112,7 @@ namespace MediaBrowser.Api.UserLibrary
|
|||||||
return ToOptimizedResult(result);
|
return ToOptimizedResult(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override QueryResult<Tuple<BaseItem, ItemCounts>> GetItems(GetItemsByName request, InternalItemsQuery query)
|
protected override QueryResult<(BaseItem, ItemCounts)> GetItems(GetItemsByName request, InternalItemsQuery query)
|
||||||
{
|
{
|
||||||
if (request is GetAlbumArtists)
|
if (request is GetAlbumArtists)
|
||||||
{
|
{
|
||||||
|
@ -209,9 +209,9 @@ namespace MediaBrowser.Api.UserLibrary
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual QueryResult<Tuple<BaseItem, ItemCounts>> GetItems(GetItemsByName request, InternalItemsQuery query)
|
protected virtual QueryResult<(BaseItem, ItemCounts)> GetItems(GetItemsByName request, InternalItemsQuery query)
|
||||||
{
|
{
|
||||||
return new QueryResult<Tuple<BaseItem, ItemCounts>>();
|
return new QueryResult<(BaseItem, ItemCounts)>();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SetItemCounts(BaseItemDto dto, ItemCounts counts)
|
private void SetItemCounts(BaseItemDto dto, ItemCounts counts)
|
||||||
|
@ -396,14 +396,12 @@ namespace MediaBrowser.Api.UserLibrary
|
|||||||
|
|
||||||
public VideoType[] GetVideoTypes()
|
public VideoType[] GetVideoTypes()
|
||||||
{
|
{
|
||||||
var val = VideoTypes;
|
if (string.IsNullOrEmpty(VideoTypes))
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(val))
|
|
||||||
{
|
{
|
||||||
return new VideoType[] { };
|
return Array.Empty<VideoType>();
|
||||||
}
|
}
|
||||||
|
|
||||||
return val.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Select(v => (VideoType)Enum.Parse(typeof(VideoType), v, true)).ToArray();
|
return VideoTypes.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Select(v => (VideoType)Enum.Parse(typeof(VideoType), v, true)).ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -92,7 +92,7 @@ namespace MediaBrowser.Api.UserLibrary
|
|||||||
return ToOptimizedResult(result);
|
return ToOptimizedResult(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override QueryResult<Tuple<BaseItem, ItemCounts>> GetItems(GetItemsByName request, InternalItemsQuery query)
|
protected override QueryResult<(BaseItem, ItemCounts)> GetItems(GetItemsByName request, InternalItemsQuery query)
|
||||||
{
|
{
|
||||||
var viewType = GetParentItemViewType(request);
|
var viewType = GetParentItemViewType(request);
|
||||||
|
|
||||||
|
@ -90,7 +90,7 @@ namespace MediaBrowser.Api.UserLibrary
|
|||||||
|
|
||||||
var options = GetDtoOptions(_authContext, request);
|
var options = GetDtoOptions(_authContext, request);
|
||||||
|
|
||||||
var ancestorIds = new List<Guid>();
|
var ancestorIds = Array.Empty<Guid>();
|
||||||
|
|
||||||
var excludeFolderIds = user.Configuration.LatestItemsExcludes;
|
var excludeFolderIds = user.Configuration.LatestItemsExcludes;
|
||||||
if (parentIdGuid.Equals(Guid.Empty) && excludeFolderIds.Length > 0)
|
if (parentIdGuid.Equals(Guid.Empty) && excludeFolderIds.Length > 0)
|
||||||
@ -99,12 +99,12 @@ namespace MediaBrowser.Api.UserLibrary
|
|||||||
.Where(i => i is Folder)
|
.Where(i => i is Folder)
|
||||||
.Where(i => !excludeFolderIds.Contains(i.Id.ToString("N")))
|
.Where(i => !excludeFolderIds.Contains(i.Id.ToString("N")))
|
||||||
.Select(i => i.Id)
|
.Select(i => i.Id)
|
||||||
.ToList();
|
.ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
var itemsResult = _libraryManager.GetItemsResult(new InternalItemsQuery(user)
|
var itemsResult = _libraryManager.GetItemsResult(new InternalItemsQuery(user)
|
||||||
{
|
{
|
||||||
OrderBy = new[] { ItemSortBy.DatePlayed }.Select(i => new ValueTuple<string, SortOrder>(i, SortOrder.Descending)).ToArray(),
|
OrderBy = new[] { (ItemSortBy.DatePlayed, SortOrder.Descending) },
|
||||||
IsResumable = true,
|
IsResumable = true,
|
||||||
StartIndex = request.StartIndex,
|
StartIndex = request.StartIndex,
|
||||||
Limit = request.Limit,
|
Limit = request.Limit,
|
||||||
@ -115,7 +115,7 @@ namespace MediaBrowser.Api.UserLibrary
|
|||||||
IsVirtualItem = false,
|
IsVirtualItem = false,
|
||||||
CollapseBoxSetItems = false,
|
CollapseBoxSetItems = false,
|
||||||
EnableTotalRecordCount = request.EnableTotalRecordCount,
|
EnableTotalRecordCount = request.EnableTotalRecordCount,
|
||||||
AncestorIds = ancestorIds.ToArray(),
|
AncestorIds = ancestorIds,
|
||||||
IncludeItemTypes = request.GetIncludeItemTypes(),
|
IncludeItemTypes = request.GetIncludeItemTypes(),
|
||||||
ExcludeItemTypes = request.GetExcludeItemTypes(),
|
ExcludeItemTypes = request.GetExcludeItemTypes(),
|
||||||
SearchTerm = request.SearchTerm
|
SearchTerm = request.SearchTerm
|
||||||
@ -155,7 +155,7 @@ namespace MediaBrowser.Api.UserLibrary
|
|||||||
/// <param name="request">The request.</param>
|
/// <param name="request">The request.</param>
|
||||||
private QueryResult<BaseItemDto> GetItems(GetItems request)
|
private QueryResult<BaseItemDto> GetItems(GetItems request)
|
||||||
{
|
{
|
||||||
var user = !request.UserId.Equals(Guid.Empty) ? _userManager.GetUserById(request.UserId) : null;
|
var user = request.UserId == Guid.Empty ? null : _userManager.GetUserById(request.UserId);
|
||||||
|
|
||||||
var dtoOptions = GetDtoOptions(_authContext, request);
|
var dtoOptions = GetDtoOptions(_authContext, request);
|
||||||
|
|
||||||
@ -190,11 +190,8 @@ namespace MediaBrowser.Api.UserLibrary
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private QueryResult<BaseItem> GetQueryResult(GetItems request, DtoOptions dtoOptions, User user)
|
private QueryResult<BaseItem> GetQueryResult(GetItems request, DtoOptions dtoOptions, User user)
|
||||||
{
|
{
|
||||||
if (string.Equals(request.IncludeItemTypes, "Playlist", StringComparison.OrdinalIgnoreCase))
|
if (string.Equals(request.IncludeItemTypes, "Playlist", StringComparison.OrdinalIgnoreCase)
|
||||||
{
|
|| string.Equals(request.IncludeItemTypes, "BoxSet", StringComparison.OrdinalIgnoreCase))
|
||||||
request.ParentId = null;
|
|
||||||
}
|
|
||||||
else if (string.Equals(request.IncludeItemTypes, "BoxSet", StringComparison.OrdinalIgnoreCase))
|
|
||||||
{
|
{
|
||||||
request.ParentId = null;
|
request.ParentId = null;
|
||||||
}
|
}
|
||||||
|
@ -83,7 +83,7 @@ namespace MediaBrowser.Api.UserLibrary
|
|||||||
return ToOptimizedResult(result);
|
return ToOptimizedResult(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override QueryResult<Tuple<BaseItem, ItemCounts>> GetItems(GetItemsByName request, InternalItemsQuery query)
|
protected override QueryResult<(BaseItem, ItemCounts)> GetItems(GetItemsByName request, InternalItemsQuery query)
|
||||||
{
|
{
|
||||||
return LibraryManager.GetMusicGenres(query);
|
return LibraryManager.GetMusicGenres(query);
|
||||||
}
|
}
|
||||||
|
@ -101,7 +101,7 @@ namespace MediaBrowser.Api.UserLibrary
|
|||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override QueryResult<Tuple<BaseItem, ItemCounts>> GetItems(GetItemsByName request, InternalItemsQuery query)
|
protected override QueryResult<(BaseItem, ItemCounts)> GetItems(GetItemsByName request, InternalItemsQuery query)
|
||||||
{
|
{
|
||||||
var items = LibraryManager.GetPeopleItems(new InternalPeopleQuery
|
var items = LibraryManager.GetPeopleItems(new InternalPeopleQuery
|
||||||
{
|
{
|
||||||
@ -109,10 +109,10 @@ namespace MediaBrowser.Api.UserLibrary
|
|||||||
NameContains = query.NameContains ?? query.SearchTerm
|
NameContains = query.NameContains ?? query.SearchTerm
|
||||||
});
|
});
|
||||||
|
|
||||||
return new QueryResult<Tuple<BaseItem, ItemCounts>>
|
return new QueryResult<(BaseItem, ItemCounts)>
|
||||||
{
|
{
|
||||||
TotalRecordCount = items.Count,
|
TotalRecordCount = items.Count,
|
||||||
Items = items.Take(query.Limit ?? int.MaxValue).Select(i => new Tuple<BaseItem, ItemCounts>(i, new ItemCounts())).ToArray()
|
Items = items.Take(query.Limit ?? int.MaxValue).Select(i => (i as BaseItem, new ItemCounts())).ToArray()
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,7 +91,7 @@ namespace MediaBrowser.Api.UserLibrary
|
|||||||
return ToOptimizedResult(result);
|
return ToOptimizedResult(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override QueryResult<Tuple<BaseItem, ItemCounts>> GetItems(GetItemsByName request, InternalItemsQuery query)
|
protected override QueryResult<(BaseItem, ItemCounts)> GetItems(GetItemsByName request, InternalItemsQuery query)
|
||||||
{
|
{
|
||||||
return LibraryManager.GetStudios(query);
|
return LibraryManager.GetStudios(query);
|
||||||
}
|
}
|
||||||
|
@ -193,7 +193,7 @@ namespace MediaBrowser.Controller.Library
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Updates the item.
|
/// Updates the item.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
void UpdateItems(List<BaseItem> items, BaseItem parent, ItemUpdateType updateReason, CancellationToken cancellationToken);
|
void UpdateItems(IEnumerable<BaseItem> items, BaseItem parent, ItemUpdateType updateReason, CancellationToken cancellationToken);
|
||||||
void UpdateItem(BaseItem item, BaseItem parent, ItemUpdateType updateReason, CancellationToken cancellationToken);
|
void UpdateItem(BaseItem item, BaseItem parent, ItemUpdateType updateReason, CancellationToken cancellationToken);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -520,12 +520,12 @@ namespace MediaBrowser.Controller.Library
|
|||||||
void UpdateMediaPath(string virtualFolderName, MediaPathInfo path);
|
void UpdateMediaPath(string virtualFolderName, MediaPathInfo path);
|
||||||
void RemoveMediaPath(string virtualFolderName, string path);
|
void RemoveMediaPath(string virtualFolderName, string path);
|
||||||
|
|
||||||
QueryResult<Tuple<BaseItem, ItemCounts>> GetGenres(InternalItemsQuery query);
|
QueryResult<(BaseItem, ItemCounts)> GetGenres(InternalItemsQuery query);
|
||||||
QueryResult<Tuple<BaseItem, ItemCounts>> GetMusicGenres(InternalItemsQuery query);
|
QueryResult<(BaseItem, ItemCounts)> GetMusicGenres(InternalItemsQuery query);
|
||||||
QueryResult<Tuple<BaseItem, ItemCounts>> GetStudios(InternalItemsQuery query);
|
QueryResult<(BaseItem, ItemCounts)> GetStudios(InternalItemsQuery query);
|
||||||
QueryResult<Tuple<BaseItem, ItemCounts>> GetArtists(InternalItemsQuery query);
|
QueryResult<(BaseItem, ItemCounts)> GetArtists(InternalItemsQuery query);
|
||||||
QueryResult<Tuple<BaseItem, ItemCounts>> GetAlbumArtists(InternalItemsQuery query);
|
QueryResult<(BaseItem, ItemCounts)> GetAlbumArtists(InternalItemsQuery query);
|
||||||
QueryResult<Tuple<BaseItem, ItemCounts>> GetAllArtists(InternalItemsQuery query);
|
QueryResult<(BaseItem, ItemCounts)> GetAllArtists(InternalItemsQuery query);
|
||||||
|
|
||||||
int GetCount(InternalItemsQuery query);
|
int GetCount(InternalItemsQuery query);
|
||||||
|
|
||||||
|
@ -32,7 +32,7 @@ namespace MediaBrowser.Controller.Persistence
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="items">The items.</param>
|
/// <param name="items">The items.</param>
|
||||||
/// <param name="cancellationToken">The cancellation token.</param>
|
/// <param name="cancellationToken">The cancellation token.</param>
|
||||||
void SaveItems(List<BaseItem> items, CancellationToken cancellationToken);
|
void SaveItems(IEnumerable<BaseItem> items, CancellationToken cancellationToken);
|
||||||
|
|
||||||
void SaveImages(BaseItem item);
|
void SaveImages(BaseItem item);
|
||||||
|
|
||||||
@ -141,12 +141,12 @@ namespace MediaBrowser.Controller.Persistence
|
|||||||
|
|
||||||
int GetCount(InternalItemsQuery query);
|
int GetCount(InternalItemsQuery query);
|
||||||
|
|
||||||
QueryResult<Tuple<BaseItem, ItemCounts>> GetGenres(InternalItemsQuery query);
|
QueryResult<(BaseItem, ItemCounts)> GetGenres(InternalItemsQuery query);
|
||||||
QueryResult<Tuple<BaseItem, ItemCounts>> GetMusicGenres(InternalItemsQuery query);
|
QueryResult<(BaseItem, ItemCounts)> GetMusicGenres(InternalItemsQuery query);
|
||||||
QueryResult<Tuple<BaseItem, ItemCounts>> GetStudios(InternalItemsQuery query);
|
QueryResult<(BaseItem, ItemCounts)> GetStudios(InternalItemsQuery query);
|
||||||
QueryResult<Tuple<BaseItem, ItemCounts>> GetArtists(InternalItemsQuery query);
|
QueryResult<(BaseItem, ItemCounts)> GetArtists(InternalItemsQuery query);
|
||||||
QueryResult<Tuple<BaseItem, ItemCounts>> GetAlbumArtists(InternalItemsQuery query);
|
QueryResult<(BaseItem, ItemCounts)> GetAlbumArtists(InternalItemsQuery query);
|
||||||
QueryResult<Tuple<BaseItem, ItemCounts>> GetAllArtists(InternalItemsQuery query);
|
QueryResult<(BaseItem, ItemCounts)> GetAllArtists(InternalItemsQuery query);
|
||||||
|
|
||||||
List<string> GetMusicGenreNames();
|
List<string> GetMusicGenreNames();
|
||||||
List<string> GetStudioNames();
|
List<string> GetStudioNames();
|
||||||
|
@ -14,6 +14,14 @@ namespace MediaBrowser.Model.Serialization
|
|||||||
/// <exception cref="ArgumentNullException">obj</exception>
|
/// <exception cref="ArgumentNullException">obj</exception>
|
||||||
void SerializeToStream(object obj, Stream stream);
|
void SerializeToStream(object obj, Stream stream);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Serializes to stream.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="obj">The obj.</param>
|
||||||
|
/// <param name="stream">The stream.</param>
|
||||||
|
/// <exception cref="ArgumentNullException">obj</exception>
|
||||||
|
void SerializeToStream<T>(T obj, Stream stream);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Serializes to file.
|
/// Serializes to file.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
Loading…
Reference in New Issue
Block a user