add channel watermark (#254)

* wip

* wip

* implement watermark settings

* code cleanup

* update changelog
This commit is contained in:
Jason Dove
2021-06-11 21:42:06 -05:00
committed by GitHub
parent 5b36252dd0
commit 0365d4c8f8
23 changed files with 3521 additions and 36 deletions
@@ -21,6 +21,11 @@ namespace ErsatzTV.Infrastructure.Data.Configurations
builder.HasMany(c => c.Artwork)
.WithOne()
.OnDelete(DeleteBehavior.Cascade);
builder.HasOne(c => c.Watermark)
.WithOne(w => w.Channel)
.HasForeignKey<Channel>(c => c.WatermarkId)
.OnDelete(DeleteBehavior.Cascade);
}
}
}
@@ -0,0 +1,11 @@
using ErsatzTV.Core.Domain;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
namespace ErsatzTV.Infrastructure.Data.Configurations
{
public class ChannelWatermarkConfiguration : IEntityTypeConfiguration<ChannelWatermark>
{
public void Configure(EntityTypeBuilder<ChannelWatermark> builder) => builder.ToTable("ChannelWatermark");
}
}
@@ -14,44 +14,59 @@ namespace ErsatzTV.Infrastructure.Data.Repositories
public class ChannelRepository : IChannelRepository
{
private readonly IDbConnection _dbConnection;
private readonly TvContext _dbContext;
private readonly IDbContextFactory<TvContext> _dbContextFactory;
public ChannelRepository(TvContext dbContext, IDbConnection dbConnection)
public ChannelRepository(IDbContextFactory<TvContext> dbContextFactory, IDbConnection dbConnection)
{
_dbContext = dbContext;
_dbContextFactory = dbContextFactory;
_dbConnection = dbConnection;
}
public async Task<Channel> Add(Channel channel)
{
await _dbContext.Channels.AddAsync(channel);
await _dbContext.SaveChangesAsync();
await using TvContext dbContext = _dbContextFactory.CreateDbContext();
await dbContext.Channels.AddAsync(channel);
await dbContext.SaveChangesAsync();
return channel;
}
public Task<Option<Channel>> Get(int id) =>
_dbContext.Channels
public async Task<Option<Channel>> Get(int id)
{
await using TvContext dbContext = _dbContextFactory.CreateDbContext();
return await dbContext.Channels
.Include(c => c.Artwork)
.Include(c => c.Watermark)
.OrderBy(c => c.Id)
.SingleOrDefaultAsync(c => c.Id == id)
.Map(Optional);
}
public Task<Option<Channel>> GetByNumber(string number) =>
_dbContext.Channels
public async Task<Option<Channel>> GetByNumber(string number)
{
await using TvContext dbContext = _dbContextFactory.CreateDbContext();
return await dbContext.Channels
.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 Task<List<Channel>> GetAll() =>
_dbContext.Channels
public async Task<List<Channel>> GetAll()
{
await using TvContext dbContext = _dbContextFactory.CreateDbContext();
return await dbContext.Channels
.Include(c => c.FFmpegProfile)
.Include(c => c.Artwork)
.ToListAsync();
}
public Task<List<Channel>> GetAllForGuide() =>
_dbContext.Channels
public async Task<List<Channel>> GetAllForGuide()
{
await using TvContext dbContext = _dbContextFactory.CreateDbContext();
return await dbContext.Channels
.Include(c => c.Artwork)
.Include(c => c.Playouts)
.ThenInclude(p => p.Items)
@@ -80,23 +95,57 @@ namespace ErsatzTV.Infrastructure.Data.Repositories
.ThenInclude(i => (i as MusicVideo).Artist)
.ThenInclude(a => a.ArtistMetadata)
.ToListAsync();
}
public Task Update(Channel channel)
public async Task<bool> Update(Channel channel)
{
_dbContext.Channels.Update(channel);
return _dbContext.SaveChangesAsync();
await using TvContext dbContext = _dbContextFactory.CreateDbContext();
dbContext.Entry(channel).State = EntityState.Modified;
if (channel.Watermark != null)
{
dbContext.Entry(channel.Watermark).State =
channel.WatermarkId == null ? EntityState.Added : EntityState.Modified;
}
foreach (Artwork artwork in Optional(channel.Artwork).Flatten())
{
dbContext.Entry(artwork).State = artwork.Id > 0 ? EntityState.Modified : EntityState.Added;
}
bool result = await dbContext.SaveChangesAsync() > 0;
return result;
}
public async Task Delete(int channelId)
{
Channel channel = await _dbContext.Channels.FindAsync(channelId);
_dbContext.Channels.Remove(channel);
await _dbContext.SaveChangesAsync();
await using TvContext dbContext = _dbContextFactory.CreateDbContext();
Channel channel = await dbContext.Channels.FindAsync(channelId);
dbContext.Channels.Remove(channel);
await dbContext.SaveChangesAsync();
}
public Task<int> CountPlayouts(int channelId) =>
_dbConnection.QuerySingleAsync<int>(
@"SELECT COUNT(*) FROM Playout WHERE ChannelId = @ChannelId",
new { ChannelId = channelId });
public async Task<Unit> RemoveWatermark(Channel channel)
{
if (channel.Watermark != null)
{
await _dbConnection.ExecuteAsync(
"UPDATE Channel SET WatermarkId = NULL WHERE Id = @ChannelId",
new { ChannelId = channel.Id });
await _dbConnection.ExecuteAsync(
"DELETE FROM ChannelWatermark WHERE Id = @WatermarkId",
new { channel.WatermarkId });
channel.Watermark = null;
channel.WatermarkId = null;
}
return Unit.Default;
}
}
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,68 @@
using Microsoft.EntityFrameworkCore.Migrations;
namespace ErsatzTV.Infrastructure.Migrations
{
public partial class Add_ChannelWatermark : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<int>(
name: "WatermarkId",
table: "Channel",
type: "INTEGER",
nullable: true);
migrationBuilder.CreateTable(
name: "ChannelWatermark",
columns: table => new
{
Id = table.Column<int>(type: "INTEGER", nullable: false)
.Annotation("Sqlite:Autoincrement", true),
Location = table.Column<int>(type: "INTEGER", nullable: false),
Size = table.Column<int>(type: "INTEGER", nullable: false),
Mode = table.Column<int>(type: "INTEGER", nullable: false),
WidthPercent = table.Column<int>(type: "INTEGER", nullable: false),
HorizontalMarginPercent = table.Column<int>(type: "INTEGER", nullable: false),
VerticalMarginPercent = table.Column<int>(type: "INTEGER", nullable: false),
FrequencyMinutes = table.Column<int>(type: "INTEGER", nullable: false),
DurationSeconds = table.Column<int>(type: "INTEGER", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_ChannelWatermark", x => x.Id);
});
migrationBuilder.CreateIndex(
name: "IX_Channel_WatermarkId",
table: "Channel",
column: "WatermarkId",
unique: true);
migrationBuilder.AddForeignKey(
name: "FK_Channel_ChannelWatermark_WatermarkId",
table: "Channel",
column: "WatermarkId",
principalTable: "ChannelWatermark",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "FK_Channel_ChannelWatermark_WatermarkId",
table: "Channel");
migrationBuilder.DropTable(
name: "ChannelWatermark");
migrationBuilder.DropIndex(
name: "IX_Channel_WatermarkId",
table: "Channel");
migrationBuilder.DropColumn(
name: "WatermarkId",
table: "Channel");
}
}
}
@@ -203,6 +203,9 @@ namespace ErsatzTV.Infrastructure.Migrations
b.Property<Guid>("UniqueId")
.HasColumnType("TEXT");
b.Property<int?>("WatermarkId")
.HasColumnType("INTEGER");
b.HasKey("Id");
b.HasIndex("FFmpegProfileId");
@@ -210,9 +213,47 @@ namespace ErsatzTV.Infrastructure.Migrations
b.HasIndex("Number")
.IsUnique();
b.HasIndex("WatermarkId")
.IsUnique();
b.ToTable("Channel");
});
modelBuilder.Entity("ErsatzTV.Core.Domain.ChannelWatermark", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<int>("DurationSeconds")
.HasColumnType("INTEGER");
b.Property<int>("FrequencyMinutes")
.HasColumnType("INTEGER");
b.Property<int>("HorizontalMarginPercent")
.HasColumnType("INTEGER");
b.Property<int>("Location")
.HasColumnType("INTEGER");
b.Property<int>("Mode")
.HasColumnType("INTEGER");
b.Property<int>("Size")
.HasColumnType("INTEGER");
b.Property<int>("VerticalMarginPercent")
.HasColumnType("INTEGER");
b.Property<int>("WidthPercent")
.HasColumnType("INTEGER");
b.HasKey("Id");
b.ToTable("ChannelWatermark");
});
modelBuilder.Entity("ErsatzTV.Core.Domain.Collection", b =>
{
b.Property<int>("Id")
@@ -1800,7 +1841,14 @@ namespace ErsatzTV.Infrastructure.Migrations
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("ErsatzTV.Core.Domain.ChannelWatermark", "Watermark")
.WithOne("Channel")
.HasForeignKey("ErsatzTV.Core.Domain.Channel", "WatermarkId")
.OnDelete(DeleteBehavior.Cascade);
b.Navigation("FFmpegProfile");
b.Navigation("Watermark");
});
modelBuilder.Entity("ErsatzTV.Core.Domain.CollectionItem", b =>
@@ -2685,6 +2733,11 @@ namespace ErsatzTV.Infrastructure.Migrations
b.Navigation("Playouts");
});
modelBuilder.Entity("ErsatzTV.Core.Domain.ChannelWatermark", b =>
{
b.Navigation("Channel");
});
modelBuilder.Entity("ErsatzTV.Core.Domain.Collection", b =>
{
b.Navigation("CollectionItems");