add more fields to music video credit templates (#1210)
This commit is contained in:
@@ -6,6 +6,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
|||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
### Added
|
### Added
|
||||||
- Add `Troubleshooting` page with aggregated settings/hardware accel info for easy reference
|
- Add `Troubleshooting` page with aggregated settings/hardware accel info for easy reference
|
||||||
|
- Read `director` fields from music video NFO metadata
|
||||||
|
- Pass `directors` and `studios` to music video credit templates
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
- Fix scaling anamorphic content from non-local libraries
|
- Fix scaling anamorphic content from non-local libraries
|
||||||
|
|||||||
@@ -98,6 +98,12 @@ public class GetPlayoutItemProcessByChannelNumberHandler : FFmpegProcessHandler<
|
|||||||
.ThenInclude(mi => (mi as MusicVideo).MusicVideoMetadata)
|
.ThenInclude(mi => (mi as MusicVideo).MusicVideoMetadata)
|
||||||
.ThenInclude(mvm => mvm.Artists)
|
.ThenInclude(mvm => mvm.Artists)
|
||||||
.Include(i => i.MediaItem)
|
.Include(i => i.MediaItem)
|
||||||
|
.ThenInclude(mi => (mi as MusicVideo).MusicVideoMetadata)
|
||||||
|
.ThenInclude(mvm => mvm.Studios)
|
||||||
|
.Include(i => i.MediaItem)
|
||||||
|
.ThenInclude(mi => (mi as MusicVideo).MusicVideoMetadata)
|
||||||
|
.ThenInclude(mvm => mvm.Directors)
|
||||||
|
.Include(i => i.MediaItem)
|
||||||
.ThenInclude(mi => (mi as MusicVideo).MediaVersions)
|
.ThenInclude(mi => (mi as MusicVideo).MediaVersions)
|
||||||
.ThenInclude(mv => mv.MediaFiles)
|
.ThenInclude(mv => mv.MediaFiles)
|
||||||
.Include(i => i.MediaItem)
|
.Include(i => i.MediaItem)
|
||||||
|
|||||||
@@ -8,4 +8,5 @@ public class MusicVideoMetadata : Metadata
|
|||||||
public int MusicVideoId { get; set; }
|
public int MusicVideoId { get; set; }
|
||||||
public MusicVideo MusicVideo { get; set; }
|
public MusicVideo MusicVideo { get; set; }
|
||||||
public List<MusicVideoArtist> Artists { get; set; }
|
public List<MusicVideoArtist> Artists { get; set; }
|
||||||
|
public List<Director> Directors { get; set; }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ public interface IMusicVideoRepository
|
|||||||
Task<bool> AddGenre(MusicVideoMetadata metadata, Genre genre);
|
Task<bool> AddGenre(MusicVideoMetadata metadata, Genre genre);
|
||||||
Task<bool> AddTag(MusicVideoMetadata metadata, Tag tag);
|
Task<bool> AddTag(MusicVideoMetadata metadata, Tag tag);
|
||||||
Task<bool> AddStudio(MusicVideoMetadata metadata, Studio studio);
|
Task<bool> AddStudio(MusicVideoMetadata metadata, Studio studio);
|
||||||
|
Task<bool> AddDirector(MusicVideoMetadata metadata, Director director);
|
||||||
Task<bool> RemoveArtist(MusicVideoArtist artist);
|
Task<bool> RemoveArtist(MusicVideoArtist artist);
|
||||||
Task<List<MusicVideoMetadata>> GetMusicVideosForCards(List<int> ids);
|
Task<List<MusicVideoMetadata>> GetMusicVideosForCards(List<int> ids);
|
||||||
Task<IEnumerable<string>> FindOrphanPaths(LibraryPath libraryPath);
|
Task<IEnumerable<string>> FindOrphanPaths(LibraryPath libraryPath);
|
||||||
|
|||||||
+4
@@ -41,5 +41,9 @@ public class MusicVideoMetadataConfiguration : IEntityTypeConfiguration<MusicVid
|
|||||||
builder.HasMany(mvm => mvm.Artists)
|
builder.HasMany(mvm => mvm.Artists)
|
||||||
.WithOne()
|
.WithOne()
|
||||||
.OnDelete(DeleteBehavior.Cascade);
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
|
||||||
|
builder.HasMany(mvm => mvm.Directors)
|
||||||
|
.WithOne()
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,6 +33,8 @@ public class MusicVideoRepository : IMusicVideoRepository
|
|||||||
.ThenInclude(mvm => mvm.Tags)
|
.ThenInclude(mvm => mvm.Tags)
|
||||||
.Include(mv => mv.MusicVideoMetadata)
|
.Include(mv => mv.MusicVideoMetadata)
|
||||||
.ThenInclude(mvm => mvm.Studios)
|
.ThenInclude(mvm => mvm.Studios)
|
||||||
|
.Include(mv => mv.MusicVideoMetadata)
|
||||||
|
.ThenInclude(mvm => mvm.Directors)
|
||||||
.Include(mv => mv.LibraryPath)
|
.Include(mv => mv.LibraryPath)
|
||||||
.ThenInclude(lp => lp.Library)
|
.ThenInclude(lp => lp.Library)
|
||||||
.Include(mv => mv.MediaVersions)
|
.Include(mv => mv.MediaVersions)
|
||||||
@@ -134,6 +136,14 @@ public class MusicVideoRepository : IMusicVideoRepository
|
|||||||
new { studio.Name, MetadataId = metadata.Id }).Map(result => result > 0);
|
new { studio.Name, MetadataId = metadata.Id }).Map(result => result > 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<bool> AddDirector(MusicVideoMetadata metadata, Director director)
|
||||||
|
{
|
||||||
|
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
|
||||||
|
return await dbContext.Connection.ExecuteAsync(
|
||||||
|
"INSERT INTO Director (Name, MusicVideoMetadataId) VALUES (@Name, @MetadataId)",
|
||||||
|
new { director.Name, MetadataId = metadata.Id }).Map(result => result > 0);
|
||||||
|
}
|
||||||
|
|
||||||
public async Task<bool> RemoveArtist(MusicVideoArtist artist)
|
public async Task<bool> RemoveArtist(MusicVideoArtist artist)
|
||||||
{
|
{
|
||||||
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
|
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
|
||||||
@@ -191,6 +201,7 @@ public class MusicVideoRepository : IMusicVideoRepository
|
|||||||
.Include(m => m.Genres)
|
.Include(m => m.Genres)
|
||||||
.Include(m => m.Tags)
|
.Include(m => m.Tags)
|
||||||
.Include(m => m.Studios)
|
.Include(m => m.Studios)
|
||||||
|
.Include(m => m.Directors)
|
||||||
.Include(m => m.MusicVideo)
|
.Include(m => m.MusicVideo)
|
||||||
.ThenInclude(mv => mv.Artist)
|
.ThenInclude(mv => mv.Artist)
|
||||||
.ThenInclude(a => a.ArtistMetadata)
|
.ThenInclude(a => a.ArtistMetadata)
|
||||||
|
|||||||
@@ -120,6 +120,8 @@ public class MusicVideoCreditsGenerator : IMusicVideoCreditsGenerator
|
|||||||
metadata.ReleaseDate,
|
metadata.ReleaseDate,
|
||||||
AllArtists = (metadata.Artists ?? new List<MusicVideoArtist>()).Map(a => a.Name),
|
AllArtists = (metadata.Artists ?? new List<MusicVideoArtist>()).Map(a => a.Name),
|
||||||
Artist = artist,
|
Artist = artist,
|
||||||
|
Studios = (metadata.Studios ?? new List<Studio>()).Map(s => s.Name),
|
||||||
|
Directors = (metadata.Directors ?? new List<Director>()).Map(s => s.Name),
|
||||||
musicVideo.GetHeadVersion().Duration,
|
musicVideo.GetHeadVersion().Duration,
|
||||||
StreamSeek = await settings.StreamSeek.IfNoneAsync(TimeSpan.Zero)
|
StreamSeek = await settings.StreamSeek.IfNoneAsync(TimeSpan.Zero)
|
||||||
});
|
});
|
||||||
|
|||||||
+4429
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,49 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace ErsatzTV.Infrastructure.Migrations
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class Add_MusicVideo_Directors : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.AddColumn<int>(
|
||||||
|
name: "MusicVideoMetadataId",
|
||||||
|
table: "Director",
|
||||||
|
type: "INTEGER",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_Director_MusicVideoMetadataId",
|
||||||
|
table: "Director",
|
||||||
|
column: "MusicVideoMetadataId");
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_Director_MusicVideoMetadata_MusicVideoMetadataId",
|
||||||
|
table: "Director",
|
||||||
|
column: "MusicVideoMetadataId",
|
||||||
|
principalTable: "MusicVideoMetadata",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_Director_MusicVideoMetadata_MusicVideoMetadataId",
|
||||||
|
table: "Director");
|
||||||
|
|
||||||
|
migrationBuilder.DropIndex(
|
||||||
|
name: "IX_Director_MusicVideoMetadataId",
|
||||||
|
table: "Director");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "MusicVideoMetadataId",
|
||||||
|
table: "Director");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -397,6 +397,9 @@ namespace ErsatzTV.Infrastructure.Migrations
|
|||||||
b.Property<int?>("MovieMetadataId")
|
b.Property<int?>("MovieMetadataId")
|
||||||
.HasColumnType("INTEGER");
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int?>("MusicVideoMetadataId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
b.Property<string>("Name")
|
b.Property<string>("Name")
|
||||||
.HasColumnType("TEXT");
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
@@ -409,6 +412,8 @@ namespace ErsatzTV.Infrastructure.Migrations
|
|||||||
|
|
||||||
b.HasIndex("MovieMetadataId");
|
b.HasIndex("MovieMetadataId");
|
||||||
|
|
||||||
|
b.HasIndex("MusicVideoMetadataId");
|
||||||
|
|
||||||
b.HasIndex("OtherVideoMetadataId");
|
b.HasIndex("OtherVideoMetadataId");
|
||||||
|
|
||||||
b.ToTable("Director", (string)null);
|
b.ToTable("Director", (string)null);
|
||||||
@@ -2857,6 +2862,11 @@ namespace ErsatzTV.Infrastructure.Migrations
|
|||||||
.HasForeignKey("MovieMetadataId")
|
.HasForeignKey("MovieMetadataId")
|
||||||
.OnDelete(DeleteBehavior.Cascade);
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
|
||||||
|
b.HasOne("ErsatzTV.Core.Domain.MusicVideoMetadata", null)
|
||||||
|
.WithMany("Directors")
|
||||||
|
.HasForeignKey("MusicVideoMetadataId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
|
||||||
b.HasOne("ErsatzTV.Core.Domain.OtherVideoMetadata", null)
|
b.HasOne("ErsatzTV.Core.Domain.OtherVideoMetadata", null)
|
||||||
.WithMany("Directors")
|
.WithMany("Directors")
|
||||||
.HasForeignKey("OtherVideoMetadataId")
|
.HasForeignKey("OtherVideoMetadataId")
|
||||||
@@ -4206,6 +4216,8 @@ namespace ErsatzTV.Infrastructure.Migrations
|
|||||||
|
|
||||||
b.Navigation("Artwork");
|
b.Navigation("Artwork");
|
||||||
|
|
||||||
|
b.Navigation("Directors");
|
||||||
|
|
||||||
b.Navigation("Genres");
|
b.Navigation("Genres");
|
||||||
|
|
||||||
b.Navigation("Guids");
|
b.Navigation("Guids");
|
||||||
|
|||||||
@@ -182,6 +182,21 @@ Le groupe a également enregistré une version espagnole de ce titre, La reina d
|
|||||||
nfo.Studios.Should().BeEquivalentTo(new List<string> { "Test Studio" });
|
nfo.Studios.Should().BeEquivalentTo(new List<string> { "Test Studio" });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public async Task MetadataNfo_With_Directors_Should_Return_Nfo()
|
||||||
|
{
|
||||||
|
await using var stream = new MemoryStream(
|
||||||
|
Encoding.UTF8.GetBytes(@"<musicvideo><director>Test Director</director></musicvideo>"));
|
||||||
|
|
||||||
|
Either<BaseError, MusicVideoNfo> result = await _musicVideoNfoReader.Read(stream);
|
||||||
|
|
||||||
|
result.IsRight.Should().BeTrue();
|
||||||
|
foreach (MusicVideoNfo nfo in result.RightToSeq())
|
||||||
|
{
|
||||||
|
nfo.Directors.Should().BeEquivalentTo(new List<string> { "Test Director" });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static string NormalizeLineEndingsLF(string str) =>
|
private static string NormalizeLineEndingsLF(string str) =>
|
||||||
str
|
str
|
||||||
|
|||||||
@@ -278,7 +278,8 @@ public class LocalMetadataProvider : ILocalMetadataProvider
|
|||||||
Artists = nfo.Artists.Map(a => new MusicVideoArtist { Name = a }).ToList(),
|
Artists = nfo.Artists.Map(a => new MusicVideoArtist { Name = a }).ToList(),
|
||||||
Genres = nfo.Genres.Map(g => new Genre { Name = g }).ToList(),
|
Genres = nfo.Genres.Map(g => new Genre { Name = g }).ToList(),
|
||||||
Tags = nfo.Tags.Map(t => new Tag { Name = t }).ToList(),
|
Tags = nfo.Tags.Map(t => new Tag { Name = t }).ToList(),
|
||||||
Studios = nfo.Studios.Map(s => new Studio { Name = s }).ToList()
|
Studios = nfo.Studios.Map(s => new Studio { Name = s }).ToList(),
|
||||||
|
Directors = nfo.Directors.Map(s => new Director { Name = s }).ToList()
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -832,6 +833,26 @@ public class LocalMetadataProvider : ILocalMetadataProvider
|
|||||||
updated = true;
|
updated = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
foreach (Director director in existing.Directors
|
||||||
|
.Filter(d => metadata.Directors.All(d2 => d2.Name != d.Name)).ToList())
|
||||||
|
{
|
||||||
|
existing.Directors.Remove(director);
|
||||||
|
if (await _metadataRepository.RemoveDirector(director))
|
||||||
|
{
|
||||||
|
updated = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (Director director in metadata.Directors
|
||||||
|
.Filter(d => existing.Directors.All(d2 => d2.Name != d.Name)).ToList())
|
||||||
|
{
|
||||||
|
existing.Directors.Add(director);
|
||||||
|
if (await _musicVideoRepository.AddDirector(existing, director))
|
||||||
|
{
|
||||||
|
updated = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return await _metadataRepository.Update(existing) || updated;
|
return await _metadataRepository.Update(existing) || updated;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ public class MusicVideoNfo
|
|||||||
Genres = new List<string>();
|
Genres = new List<string>();
|
||||||
Tags = new List<string>();
|
Tags = new List<string>();
|
||||||
Studios = new List<string>();
|
Studios = new List<string>();
|
||||||
|
Directors = new List<string>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<string> Artists { get; }
|
public List<string> Artists { get; }
|
||||||
@@ -20,4 +21,5 @@ public class MusicVideoNfo
|
|||||||
public List<string> Genres { get; }
|
public List<string> Genres { get; }
|
||||||
public List<string> Tags { get; }
|
public List<string> Tags { get; }
|
||||||
public List<string> Studios { get; }
|
public List<string> Studios { get; }
|
||||||
|
public List<string> Directors { get; }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -91,6 +91,12 @@ public class MusicVideoNfoReader : NfoReader<MusicVideoNfo>, IMusicVideoNfoReade
|
|||||||
nfo,
|
nfo,
|
||||||
(musicVideo, studio) => musicVideo.Studios.Add(studio));
|
(musicVideo, studio) => musicVideo.Studios.Add(studio));
|
||||||
break;
|
break;
|
||||||
|
case "director":
|
||||||
|
await ReadStringContent(
|
||||||
|
reader,
|
||||||
|
nfo,
|
||||||
|
(musicVideo, director) => musicVideo.Directors.Add(director));
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ Style: RoboR,Roboto-Regular.ttf,{{ resolution.height // 20.0 }},&HFFFFFF,&HFFFFF
|
|||||||
{{~ _last_end_ts = timespan.from_seconds (_duration_s | math.minus 9) ~}}
|
{{~ _last_end_ts = timespan.from_seconds (_duration_s | math.minus 9) ~}}
|
||||||
{{~ if all_artists | array.size == 0 ~}}
|
{{~ if all_artists | array.size == 0 ~}}
|
||||||
{{~ capture _artists_t ~}}{{~ artist ~}}{{~ end ~}}
|
{{~ capture _artists_t ~}}{{~ artist ~}}{{~ end ~}}
|
||||||
{{ else }}
|
{{~ else ~}}
|
||||||
{{~ capture _artists_t ~}}{{~ all_artists | array.join " | " ~}}{{~ end ~}}
|
{{~ capture _artists_t ~}}{{~ all_artists | array.join " | " ~}}{{~ end ~}}
|
||||||
{{~ end ~}}
|
{{~ end ~}}
|
||||||
{{~ capture _fancy_title_t ~}}{%{{\b1}{\fscy150}{\1c&HC2C1BF&}}%}{{~ title ~}}{{~ end ~}}
|
{{~ capture _fancy_title_t ~}}{%{{\b1}{\fscy150}{\1c&HC2C1BF&}}%}{{~ title ~}}{{~ end ~}}
|
||||||
|
|||||||
Reference in New Issue
Block a user