using System.Text; using ErsatzTV.Core; using ErsatzTV.Core.Interfaces.Metadata; using ErsatzTV.Core.Iptv; using ErsatzTV.Infrastructure.Data; using Microsoft.EntityFrameworkCore; using Microsoft.IO; namespace ErsatzTV.Application.Channels; public class GetChannelGuideHandler : IRequestHandler> { private readonly IDbContextFactory _dbContextFactory; private readonly ILocalFileSystem _localFileSystem; private readonly RecyclableMemoryStreamManager _recyclableMemoryStreamManager; public GetChannelGuideHandler( IDbContextFactory dbContextFactory, RecyclableMemoryStreamManager recyclableMemoryStreamManager, ILocalFileSystem localFileSystem) { _dbContextFactory = dbContextFactory; _recyclableMemoryStreamManager = recyclableMemoryStreamManager; _localFileSystem = localFileSystem; } public async Task> Handle( GetChannelGuide request, CancellationToken cancellationToken) { await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync(cancellationToken); string channelsFile = Path.Combine(FileSystemLayout.ChannelGuideCacheFolder, "channels.xml"); if (!_localFileSystem.FileExists(channelsFile)) { return BaseError.New($"Required file {channelsFile} is missing"); } long mtime = File.GetLastWriteTime(channelsFile).Ticks; var accessTokenUri = $"?v={mtime}"; if (!string.IsNullOrWhiteSpace(request.AccessToken)) { accessTokenUri += $"&access_token={request.AccessToken}"; } string channelsFragment = await File.ReadAllTextAsync(channelsFile, Encoding.UTF8, cancellationToken); // TODO: is regex faster? channelsFragment = channelsFragment .Replace("{RequestBase}", $"{request.Scheme}://{request.Host}{request.BaseUrl}") .Replace("{AccessTokenUri}", accessTokenUri); var channelDataFragments = new Dictionary(); foreach (string fileName in _localFileSystem.ListFiles(FileSystemLayout.ChannelGuideCacheFolder)) { if (fileName.Contains("channels")) { continue; } string channelDataFragment = await File.ReadAllTextAsync(fileName, Encoding.UTF8, cancellationToken); channelDataFragment = channelDataFragment .Replace("{RequestBase}", $"{request.Scheme}://{request.Host}{request.BaseUrl}") .Replace("{AccessTokenUri}", accessTokenUri); channelDataFragments.Add(Path.GetFileNameWithoutExtension(fileName), channelDataFragment); } return new ChannelGuide(_recyclableMemoryStreamManager, channelsFragment, channelDataFragments); } }