Merge remote-tracking branch 'upstream/master' into search-rebased

This commit is contained in:
Shadowghost
2026-05-16 09:57:06 +02:00
189 changed files with 3738 additions and 2972 deletions

View File

@@ -824,6 +824,26 @@ public sealed partial class BaseItemRepository
}
}
if (filter.SubtitleLanguages.Count > 0)
{
var foldersWithSubtitles = DescendantQueryHelper.GetFolderIdsMatching(context, new HasMediaStreamType(MediaStreamTypeEntity.Subtitle, filter.SubtitleLanguages));
baseQuery = baseQuery
.Where(e =>
(!e.IsFolder && e.MediaStreams!.Any(f => f.StreamType == MediaStreamTypeEntity.Subtitle
&& (filter.SubtitleLanguages.Contains(f.Language) || (filter.SubtitleLanguages.Contains("und") && string.IsNullOrEmpty(f.Language)))))
|| (e.IsFolder && foldersWithSubtitles.Contains(e.Id)));
}
if (filter.AudioLanguages.Count > 0)
{
var foldersWithAudio = DescendantQueryHelper.GetFolderIdsMatching(context, new HasMediaStreamType(MediaStreamTypeEntity.Audio, filter.AudioLanguages));
baseQuery = baseQuery
.Where(e =>
(!e.IsFolder && e.MediaStreams!.Any(f => f.StreamType == MediaStreamTypeEntity.Audio
&& (filter.AudioLanguages.Contains(f.Language) || (filter.AudioLanguages.Contains("und") && string.IsNullOrEmpty(f.Language)))))
|| (e.IsFolder && foldersWithAudio.Contains(e.Id)));
}
if (filter.HasChapterImages.HasValue)
{
var hasChapterImages = filter.HasChapterImages.Value;
@@ -946,6 +966,17 @@ public sealed partial class BaseItemRepository
baseQuery = baseQuery.WhereHasAnyProviderIds(filter.HasAnyProviderIds);
}
if (filter.HasAnyProviderIds is not null && filter.HasAnyProviderIds.Count > 0)
{
var includeAny = filter.HasAnyProviderIds
.SelectMany(kvp => kvp.Value.Select(v => $"{kvp.Key}:{v}"))
.ToArray();
if (includeAny.Length > 0)
{
baseQuery = baseQuery.Where(e => e.Provider!.Select(f => f.ProviderId + ":" + f.ProviderValue)!.Any(f => includeAny.Contains(f)));
}
}
if (filter.HasImdbId.HasValue)
{
baseQuery = filter.HasImdbId.Value
@@ -1050,8 +1081,12 @@ public sealed partial class BaseItemRepository
if (filter.VideoTypes.Length > 0)
{
// Dvds and Blu-rays can either be stored in a folder structure or as an iso file
// => to find all matches we need to check both: VideoType and IsoType
// alternatively, we could provide specific IsoType filters
var videoTypeBs = filter.VideoTypes.Select(vt => $"\"VideoType\":\"{vt}\"").ToArray();
Expression<Func<BaseItemEntity, bool>> hasVideoType = e => videoTypeBs.Any(f => e.Data!.Contains(f));
var isoTypeBs = filter.VideoTypes.Select(vt => $"\"IsoType\":\"{vt}\"").ToArray();
Expression<Func<BaseItemEntity, bool>> hasVideoType = e => videoTypeBs.Any(f => e.Data!.Contains(f)) || isoTypeBs.Any(f => e.Data!.Contains(f));
baseQuery = baseQuery.WhereItemOrDescendantMatches(context, hasVideoType);
}

View File

@@ -55,6 +55,17 @@ public class MediaStreamRepository : IMediaStreamRepository
return TranslateQuery(context.MediaStreamInfos.AsNoTracking(), filter).AsEnumerable().Select(Map).ToArray();
}
/// <inheritdoc />
public IReadOnlyList<string> GetMediaStreamLanguages(MediaStreamType mediaStreamType)
{
using var context = _dbProvider.CreateDbContext();
return context.MediaStreamInfos
.Where(e => e.StreamType == (MediaStreamTypeEntity)mediaStreamType)
.Select(s => string.IsNullOrEmpty(s.Language) ? "und" : s.Language) // und = undetermined
.Distinct()
.ToArray();
}
private string? GetPathToSave(string? path)
{
if (path is null)

View File

@@ -119,7 +119,6 @@ public class PeopleRepository(IDbContextFactory<JellyfinDbContext> dbProvider, I
.ToArray();
var toAdd = people
.Where(e => e.Type is not PersonKind.Artist && e.Type is not PersonKind.AlbumArtist)
.Where(e => !existingPersons.Any(f => string.Equals(f.Name, e.Name, StringComparison.OrdinalIgnoreCase) && f.PersonType == e.Type.ToString()))
.Select(Map);
context.Peoples.AddRange(toAdd);
@@ -133,11 +132,6 @@ public class PeopleRepository(IDbContextFactory<JellyfinDbContext> dbProvider, I
foreach (var person in people)
{
if (person.Type == PersonKind.Artist || person.Type == PersonKind.AlbumArtist)
{
continue;
}
var entityPerson = personsEntities.First(e => string.Equals(e.Name, person.Name, StringComparison.OrdinalIgnoreCase) && e.PersonType == person.Type.ToString());
var existingMap = existingMaps.FirstOrDefault(e => string.Equals(e.People.Name, person.Name, StringComparison.OrdinalIgnoreCase) && e.People.PersonType == person.Type.ToString() && e.Role == person.Role);
if (existingMap is null)