📄 src/Infrastructure/Database/Jellyfin/MediaRepository.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Jellyfin.Database.Implementations;
using Jellyfin.Database.Implementations.Entities;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Options;
using Slopper.Domain;

namespace Slopper.Infrastructure.Database.Jellyfin;

internal sealed class MediaRepository(
    IOptions<MediaRepositoryOptions> options,
    JellyfinDbContext jellyfinDbContext,
    Random random
) : IMediaRepository
{
    private readonly IReadOnlyCollection<string> subtitleCodecs = options.Value.SubtitleCodecs;

    public async Task<MediaItem> GetRandomMediaItem(CancellationToken cancellationToken)
    {
        var query = jellyfinDbContext
            .MediaStreamInfos.AsNoTracking()
            .Where(s =>
                s.StreamType == MediaStreamTypeEntity.Subtitle
                && s.Language == "eng"
                && subtitleCodecs.Contains(s.Codec)
            );

        var count = await query.CountAsync(cancellationToken);
        var index = random.Next(count);

        var mediaStreamInfo =
            await query
                .Include(s => s.Item)
                .OrderBy(s => s.ItemId)
                .ThenBy(s => s.StreamIndex)
                .Skip(index)
                .FirstOrDefaultAsync(cancellationToken)
            ?? throw new Exception("No media available");

        return Map(mediaStreamInfo);
    }

    private static MediaItem Map(MediaStreamInfo mediaStreamInfo) =>
        new(mediaStreamInfo.ItemId, MapVideoPath(mediaStreamInfo.Item), MapSubtitle(mediaStreamInfo));

    private static string MapVideoPath(BaseItemEntity item) =>
        item.Path ?? throw new Exception("No video stream for media item");

    private static Subtitles MapSubtitle(MediaStreamInfo mediaStreamInfo) =>
        mediaStreamInfo.IsExternal
            ? new Subtitles.External(mediaStreamInfo.Path ?? throw new Exception("External subtitles without path"))
            : new Subtitles.Embedded(mediaStreamInfo.StreamIndex);
}