Enhanced the bumper system to support a new background type, 'Clip', allowing text to be overlaid on existing video clips. This update includes the addition of a BackgroundClipShowId property in various records and classes, ensuring that the clip's duration dictates the bumper length. Updated validation rules, mapping, and rendering logic to accommodate this new feature. Localization strings were also updated to reflect the new background option and its implications for audio handling.
132 lines
5.1 KiB
C#
132 lines
5.1 KiB
C#
using Microsoft.Extensions.Options;
|
|
using NSubstitute;
|
|
using TeleWave.Application.Broadcast.Bumpers;
|
|
using TeleWave.Application.Common.Interfaces;
|
|
using TeleWave.Application.Streaming;
|
|
using TeleWave.Application.Tests.Support;
|
|
using TeleWave.Domain.Broadcast;
|
|
using TeleWave.Domain.Images;
|
|
using TeleWave.Domain.Library;
|
|
using TeleWave.Domain.Media;
|
|
using Xunit;
|
|
|
|
namespace TeleWave.Application.Tests.Broadcast;
|
|
|
|
/// <summary>
|
|
/// Восстановление спецификации для фонового рендерера. Текст берётся из кэша как есть: время показа
|
|
/// и пара соседей задним числом не восстанавливаются, а ffmpeg запускается уже после записи ленты.
|
|
/// </summary>
|
|
public class BumperSpecLoaderTests
|
|
{
|
|
private static readonly IReadOnlyList<BumperRenderLine> Lines =
|
|
[
|
|
new(BumperLineStyle.Label, BumperLineColor.Accent, "СЕЙЧАС"),
|
|
new(BumperLineStyle.Title, BumperLineColor.Text, "Симпсоны"),
|
|
];
|
|
|
|
private static BumperSpecLoader NewLoader(
|
|
Infrastructure.Persistence.AppDbContext db,
|
|
IBumperTemplateStorage? storage = null,
|
|
IImageStore? images = null,
|
|
IMediaStorage? media = null
|
|
) =>
|
|
new(
|
|
db,
|
|
storage ?? Substitute.For<IBumperTemplateStorage>(),
|
|
images ?? Substitute.For<IImageStore>(),
|
|
media ?? Substitute.For<IMediaStorage>(),
|
|
Options.Create(new BumperOptions()),
|
|
Options.Create(new StreamingOptions { SegmentSeconds = 5 })
|
|
);
|
|
|
|
[Fact]
|
|
public async Task Load_UnknownAsset_ReturnsNull()
|
|
{
|
|
var fixture = new TestDb();
|
|
await using var db = fixture.New();
|
|
|
|
Assert.Null(await NewLoader(db).LoadAsync(Guid.NewGuid(), CancellationToken.None));
|
|
}
|
|
|
|
[Fact]
|
|
public async Task Load_RestoresRenderedTextAndPaths()
|
|
{
|
|
var fixture = new TestDb();
|
|
var template = BumperTemplate.Create("Блок", "Текст 1");
|
|
template.UpdateStyle(
|
|
new BumperStyle("Блок", BumperFont.Serif, "0x111111", "0x222222", "0x333333", "white")
|
|
);
|
|
template.SetAudio(".mp3", 12);
|
|
var background = Image.Create(ImageCategory.BumperBackground, ".png", "bg.png");
|
|
template.SetBackgroundImage(background.Id);
|
|
|
|
var poster = Image.Create(ImageCategory.ShowPoster, ".jpg", "poster.jpg");
|
|
var show = Show.Create("Терминатор", ShowKind.Single);
|
|
show.ApplyMetadata("tmdb", "1", null, 1991, poster.Id);
|
|
|
|
var asset = MediaAsset.RegisterGenerated("Блок: СЕЙЧАС / Симпсоны");
|
|
var cache = BumperAsset.Create(
|
|
template.Id,
|
|
template.Variants[0].Id,
|
|
"sig",
|
|
BumperRenderedText.ToJson(Lines),
|
|
show.Id,
|
|
asset.Id
|
|
);
|
|
|
|
await using (var seed = fixture.New())
|
|
{
|
|
seed.BumperTemplates.Add(template);
|
|
seed.Images.AddRange(background, poster);
|
|
seed.Shows.Add(show);
|
|
seed.MediaAssets.Add(asset);
|
|
seed.BumperAssets.Add(cache);
|
|
await seed.SaveChangesAsync(CancellationToken.None);
|
|
}
|
|
|
|
var storage = Substitute.For<IBumperTemplateStorage>();
|
|
storage.AudioPath(template.Id, ".mp3").Returns("/media/bumpers/audio.mp3");
|
|
var images = Substitute.For<IImageStore>();
|
|
images.ResolvePath(background.Id, ".png").Returns("/media/images/bg.png");
|
|
images.ResolvePath(poster.Id, ".jpg").Returns("/media/images/poster.jpg");
|
|
|
|
await using var db = fixture.New();
|
|
var spec = await NewLoader(db, storage, images).LoadAsync(asset.Id, CancellationToken.None);
|
|
|
|
Assert.NotNull(spec);
|
|
Assert.Equal(Lines, spec.Lines);
|
|
Assert.Equal("/media/bumpers/audio.mp3", spec.MusicFile);
|
|
Assert.Equal("/media/images/bg.png", spec.BackgroundFile);
|
|
Assert.Equal("/media/images/poster.jpg", spec.PosterFile);
|
|
Assert.Equal("0x333333", spec.AccentColor);
|
|
// Длина звука 12 с выравнивается вверх до кратности сегменту (5 с).
|
|
Assert.Equal(15, spec.DurationSeconds);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task Load_TemplateGone_ReturnsNull()
|
|
{
|
|
var fixture = new TestDb();
|
|
var asset = MediaAsset.RegisterGenerated("Заставка");
|
|
var cache = BumperAsset.Create(
|
|
Guid.NewGuid(),
|
|
Guid.NewGuid(),
|
|
"sig",
|
|
BumperRenderedText.ToJson(Lines),
|
|
null,
|
|
asset.Id
|
|
);
|
|
|
|
await using (var seed = fixture.New())
|
|
{
|
|
seed.MediaAssets.Add(asset);
|
|
seed.BumperAssets.Add(cache);
|
|
await seed.SaveChangesAsync(CancellationToken.None);
|
|
}
|
|
|
|
await using var db = fixture.New();
|
|
// Блок удалили, пока ассет ждал рендера — рендерить нечем, и это не авария.
|
|
Assert.Null(await NewLoader(db).LoadAsync(asset.Id, CancellationToken.None));
|
|
}
|
|
}
|