using ErsatzTV.Core.Api.Channels; using ErsatzTV.Core.Domain; using ErsatzTV.Core.Interfaces.Repositories; using Microsoft.EntityFrameworkCore; namespace ErsatzTV.Infrastructure.Data.Repositories; public class ChannelRepository(IDbContextFactory dbContextFactory) : IChannelRepository { public async Task> GetChannel(int id) { await using TvContext dbContext = await dbContextFactory.CreateDbContextAsync(); return await dbContext.Channels .AsNoTracking() .Include(c => c.FFmpegProfile) .Include(c => c.Artwork) .Include(c => c.Watermark) .Include(c => c.Playouts) .ThenInclude(p => p.BuildStatus) .Include(c => c.MirrorSourceChannel) .ThenInclude(mc => mc.Playouts) .ThenInclude(p => p.BuildStatus) .Include(c => c.ChannelGraphicsElements) .ThenInclude(x => x.GraphicsElement) .OrderBy(c => c.Id) .SingleOrDefaultAsync(c => c.Id == id) .Map(Optional); } public async Task> GetByNumber(string number) { await using TvContext dbContext = await dbContextFactory.CreateDbContextAsync(); return await dbContext.Channels .AsNoTracking() .Include(c => c.FFmpegProfile) .ThenInclude(p => p.Resolution) .Include(c => c.Artwork) .Include(c => c.Watermark) .OrderBy(c => c.Number) .SingleOrDefaultAsync(c => c.Number == number) .Map(Optional); } public async Task> GetAll(CancellationToken cancellationToken) { await using TvContext dbContext = await dbContextFactory.CreateDbContextAsync(cancellationToken); return await dbContext.Channels .AsNoTracking() .Include(c => c.FFmpegProfile) .Include(c => c.Artwork) .Include(c => c.Playouts) .ThenInclude(p => p.BuildStatus) .Include(c => c.MirrorSourceChannel) .ThenInclude(mc => mc.Playouts) .ThenInclude(p => p.BuildStatus) .ToListAsync(cancellationToken); } public async Task> GetPlayoutUpcomingHealth( IReadOnlyCollection playoutIds, DateTime nowUtc, CancellationToken cancellationToken) { if (playoutIds.Count == 0) { return new Dictionary(); } await using TvContext dbContext = await dbContextFactory.CreateDbContextAsync(cancellationToken); return await dbContext.PlayoutItems .AsNoTracking() .Where(pi => playoutIds.Contains(pi.PlayoutId) && pi.Finish >= nowUtc) .GroupBy(pi => pi.PlayoutId) .Select(g => new { PlayoutId = g.Key, Total = g.Count(), Broken = g.Count(pi => pi.MediaItem.State == MediaItemState.FileNotFound || pi.MediaItem.State == MediaItemState.Unavailable) }) .ToDictionaryAsync( x => x.PlayoutId, x => new PlayoutUpcoming(x.Total, x.Broken), cancellationToken); } public async Task> GetWatermarkByName(string name) { await using TvContext dbContext = await dbContextFactory.CreateDbContextAsync(); List maybeWatermarks = await dbContext.ChannelWatermarks .AsNoTracking() .Where(cw => EF.Functions.Like(cw.Name, $"%{name}%")) .ToListAsync(); return maybeWatermarks.HeadOrNone(); } }