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

namespace Slopper.Infrastructure.Database;

internal sealed class MediaRepository(JellyfinDbContext jellyfinDbContext, Random random) : IMediaRepository
{
    public async Task<MediaItem> GetRandomMediaItem(CancellationToken cancellationToken)
    {
        var query = jellyfinDbContext
            .MediaStreamInfos.AsNoTracking()
            .Where(s => s.StreamType == MediaStreamTypeEntity.Subtitle && s.Language == "eng" && s.Codec != "PGSSUB");

        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(MapName(mediaStreamInfo.Item), MapVideoPath(mediaStreamInfo.Item), MapSubtitle(mediaStreamInfo));

    private static string MapName(BaseItemEntity item) =>
        item switch
        {
            { SeriesName: string seriesName, SeasonName: string seasonName, EpisodeTitle: string episodeTitle } =>
                $"{seriesName} {seasonName} {episodeTitle}",
            { SeriesName: string seriesName, SeasonName: string seasonName, Name: string name } =>
                $"{seriesName} {seasonName} {name}",
            { Name: string name } => name,
            { SortName: string sortName } => sortName,
            { CleanName: string cleanName } => cleanName,
            _ => throw new Exception("No name for media item"),
        };

    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);
}