add songs libraries (#490)

* first pass at adding song libraries

* start handling optional video

* fix song playback

* fix song transitions

* add songs page to UI
This commit is contained in:
Jason Dove
2021-11-22 22:26:06 -06:00
committed by GitHub
parent 096f2d42e8
commit 852728c816
63 changed files with 13235 additions and 187 deletions
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,23 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace ErsatzTV.Infrastructure.Migrations
{
public partial class Add_LocalLibrary_Songs : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
// create local songs library
migrationBuilder.Sql(
@"INSERT INTO Library (Name, MediaKind, MediaSourceId)
SELECT 'Songs', 5, Id FROM
(SELECT LMS.Id FROM LocalMediaSource LMS LIMIT 1)");
migrationBuilder.Sql("INSERT INTO LocalLibrary (Id) Values (last_insert_rowid())");
}
protected override void Down(MigrationBuilder migrationBuilder)
{
}
}
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,285 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace ErsatzTV.Infrastructure.Migrations
{
public partial class Add_Songs_SongMetadata : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<int>(
name: "SongMetadataId",
table: "Tag",
type: "INTEGER",
nullable: true);
migrationBuilder.AddColumn<int>(
name: "SongMetadataId",
table: "Studio",
type: "INTEGER",
nullable: true);
migrationBuilder.AddColumn<int>(
name: "SongMetadataId",
table: "MetadataGuid",
type: "INTEGER",
nullable: true);
migrationBuilder.AddColumn<int>(
name: "SongId",
table: "MediaVersion",
type: "INTEGER",
nullable: true);
migrationBuilder.AddColumn<int>(
name: "SongMetadataId",
table: "Genre",
type: "INTEGER",
nullable: true);
migrationBuilder.AddColumn<int>(
name: "SongMetadataId",
table: "Artwork",
type: "INTEGER",
nullable: true);
migrationBuilder.AddColumn<int>(
name: "SongMetadataId",
table: "Actor",
type: "INTEGER",
nullable: true);
migrationBuilder.CreateTable(
name: "Song",
columns: table => new
{
Id = table.Column<int>(type: "INTEGER", nullable: false)
.Annotation("Sqlite:Autoincrement", true)
},
constraints: table =>
{
table.PrimaryKey("PK_Song", x => x.Id);
table.ForeignKey(
name: "FK_Song_MediaItem_Id",
column: x => x.Id,
principalTable: "MediaItem",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "SongMetadata",
columns: table => new
{
Id = table.Column<int>(type: "INTEGER", nullable: false)
.Annotation("Sqlite:Autoincrement", true),
SongId = table.Column<int>(type: "INTEGER", nullable: false),
MetadataKind = table.Column<int>(type: "INTEGER", nullable: false),
Title = table.Column<string>(type: "TEXT", nullable: true),
OriginalTitle = table.Column<string>(type: "TEXT", nullable: true),
SortTitle = table.Column<string>(type: "TEXT", nullable: true),
Year = table.Column<int>(type: "INTEGER", nullable: true),
ReleaseDate = table.Column<DateTime>(type: "TEXT", nullable: true),
DateAdded = table.Column<DateTime>(type: "TEXT", nullable: false),
DateUpdated = table.Column<DateTime>(type: "TEXT", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_SongMetadata", x => x.Id);
table.ForeignKey(
name: "FK_SongMetadata_Song_SongId",
column: x => x.SongId,
principalTable: "Song",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateIndex(
name: "IX_Tag_SongMetadataId",
table: "Tag",
column: "SongMetadataId");
migrationBuilder.CreateIndex(
name: "IX_Studio_SongMetadataId",
table: "Studio",
column: "SongMetadataId");
migrationBuilder.CreateIndex(
name: "IX_MetadataGuid_SongMetadataId",
table: "MetadataGuid",
column: "SongMetadataId");
migrationBuilder.CreateIndex(
name: "IX_MediaVersion_SongId",
table: "MediaVersion",
column: "SongId");
migrationBuilder.CreateIndex(
name: "IX_Genre_SongMetadataId",
table: "Genre",
column: "SongMetadataId");
migrationBuilder.CreateIndex(
name: "IX_Artwork_SongMetadataId",
table: "Artwork",
column: "SongMetadataId");
migrationBuilder.CreateIndex(
name: "IX_Actor_SongMetadataId",
table: "Actor",
column: "SongMetadataId");
migrationBuilder.CreateIndex(
name: "IX_SongMetadata_SongId",
table: "SongMetadata",
column: "SongId");
migrationBuilder.AddForeignKey(
name: "FK_Actor_SongMetadata_SongMetadataId",
table: "Actor",
column: "SongMetadataId",
principalTable: "SongMetadata",
principalColumn: "Id");
migrationBuilder.AddForeignKey(
name: "FK_Artwork_SongMetadata_SongMetadataId",
table: "Artwork",
column: "SongMetadataId",
principalTable: "SongMetadata",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
migrationBuilder.AddForeignKey(
name: "FK_Genre_SongMetadata_SongMetadataId",
table: "Genre",
column: "SongMetadataId",
principalTable: "SongMetadata",
principalColumn: "Id");
migrationBuilder.AddForeignKey(
name: "FK_MediaVersion_Song_SongId",
table: "MediaVersion",
column: "SongId",
principalTable: "Song",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
migrationBuilder.AddForeignKey(
name: "FK_MetadataGuid_SongMetadata_SongMetadataId",
table: "MetadataGuid",
column: "SongMetadataId",
principalTable: "SongMetadata",
principalColumn: "Id");
migrationBuilder.AddForeignKey(
name: "FK_Studio_SongMetadata_SongMetadataId",
table: "Studio",
column: "SongMetadataId",
principalTable: "SongMetadata",
principalColumn: "Id");
migrationBuilder.AddForeignKey(
name: "FK_Tag_SongMetadata_SongMetadataId",
table: "Tag",
column: "SongMetadataId",
principalTable: "SongMetadata",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "FK_Actor_SongMetadata_SongMetadataId",
table: "Actor");
migrationBuilder.DropForeignKey(
name: "FK_Artwork_SongMetadata_SongMetadataId",
table: "Artwork");
migrationBuilder.DropForeignKey(
name: "FK_Genre_SongMetadata_SongMetadataId",
table: "Genre");
migrationBuilder.DropForeignKey(
name: "FK_MediaVersion_Song_SongId",
table: "MediaVersion");
migrationBuilder.DropForeignKey(
name: "FK_MetadataGuid_SongMetadata_SongMetadataId",
table: "MetadataGuid");
migrationBuilder.DropForeignKey(
name: "FK_Studio_SongMetadata_SongMetadataId",
table: "Studio");
migrationBuilder.DropForeignKey(
name: "FK_Tag_SongMetadata_SongMetadataId",
table: "Tag");
migrationBuilder.DropTable(
name: "SongMetadata");
migrationBuilder.DropTable(
name: "Song");
migrationBuilder.DropIndex(
name: "IX_Tag_SongMetadataId",
table: "Tag");
migrationBuilder.DropIndex(
name: "IX_Studio_SongMetadataId",
table: "Studio");
migrationBuilder.DropIndex(
name: "IX_MetadataGuid_SongMetadataId",
table: "MetadataGuid");
migrationBuilder.DropIndex(
name: "IX_MediaVersion_SongId",
table: "MediaVersion");
migrationBuilder.DropIndex(
name: "IX_Genre_SongMetadataId",
table: "Genre");
migrationBuilder.DropIndex(
name: "IX_Artwork_SongMetadataId",
table: "Artwork");
migrationBuilder.DropIndex(
name: "IX_Actor_SongMetadataId",
table: "Actor");
migrationBuilder.DropColumn(
name: "SongMetadataId",
table: "Tag");
migrationBuilder.DropColumn(
name: "SongMetadataId",
table: "Studio");
migrationBuilder.DropColumn(
name: "SongMetadataId",
table: "MetadataGuid");
migrationBuilder.DropColumn(
name: "SongId",
table: "MediaVersion");
migrationBuilder.DropColumn(
name: "SongMetadataId",
table: "Genre");
migrationBuilder.DropColumn(
name: "SongMetadataId",
table: "Artwork");
migrationBuilder.DropColumn(
name: "SongMetadataId",
table: "Actor");
}
}
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,26 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace ErsatzTV.Infrastructure.Migrations
{
public partial class Add_StreamAttachedPic : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<bool>(
name: "AttachedPic",
table: "MediaStream",
type: "INTEGER",
nullable: false,
defaultValue: false);
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "AttachedPic",
table: "MediaStream");
}
}
}
@@ -56,6 +56,9 @@ namespace ErsatzTV.Infrastructure.Migrations
b.Property<int?>("ShowMetadataId")
.HasColumnType("INTEGER");
b.Property<int?>("SongMetadataId")
.HasColumnType("INTEGER");
b.HasKey("Id");
b.HasIndex("ArtistMetadataId");
@@ -75,6 +78,8 @@ namespace ErsatzTV.Infrastructure.Migrations
b.HasIndex("ShowMetadataId");
b.HasIndex("SongMetadataId");
b.ToTable("Actor", (string)null);
});
@@ -169,6 +174,9 @@ namespace ErsatzTV.Infrastructure.Migrations
b.Property<int?>("ShowMetadataId")
.HasColumnType("INTEGER");
b.Property<int?>("SongMetadataId")
.HasColumnType("INTEGER");
b.HasKey("Id");
b.HasIndex("ArtistMetadataId");
@@ -187,6 +195,8 @@ namespace ErsatzTV.Infrastructure.Migrations
b.HasIndex("ShowMetadataId");
b.HasIndex("SongMetadataId");
b.ToTable("Artwork", (string)null);
});
@@ -602,6 +612,9 @@ namespace ErsatzTV.Infrastructure.Migrations
b.Property<int?>("ShowMetadataId")
.HasColumnType("INTEGER");
b.Property<int?>("SongMetadataId")
.HasColumnType("INTEGER");
b.HasKey("Id");
b.HasIndex("ArtistMetadataId");
@@ -618,6 +631,8 @@ namespace ErsatzTV.Infrastructure.Migrations
b.HasIndex("ShowMetadataId");
b.HasIndex("SongMetadataId");
b.ToTable("Genre");
});
@@ -840,6 +855,9 @@ namespace ErsatzTV.Infrastructure.Migrations
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<bool>("AttachedPic")
.HasColumnType("INTEGER");
b.Property<int>("BitsPerRawSample")
.HasColumnType("INTEGER");
@@ -925,6 +943,9 @@ namespace ErsatzTV.Infrastructure.Migrations
b.Property<string>("SampleAspectRatio")
.HasColumnType("TEXT");
b.Property<int?>("SongId")
.HasColumnType("INTEGER");
b.Property<int>("VideoScanKind")
.HasColumnType("INTEGER");
@@ -941,6 +962,8 @@ namespace ErsatzTV.Infrastructure.Migrations
b.HasIndex("OtherVideoId");
b.HasIndex("SongId");
b.ToTable("MediaVersion", (string)null);
});
@@ -974,6 +997,9 @@ namespace ErsatzTV.Infrastructure.Migrations
b.Property<int?>("ShowMetadataId")
.HasColumnType("INTEGER");
b.Property<int?>("SongMetadataId")
.HasColumnType("INTEGER");
b.HasKey("Id");
b.HasIndex("ArtistMetadataId");
@@ -990,6 +1016,8 @@ namespace ErsatzTV.Infrastructure.Migrations
b.HasIndex("ShowMetadataId");
b.HasIndex("SongMetadataId");
b.ToTable("MetadataGuid", (string)null);
});
@@ -1603,6 +1631,46 @@ namespace ErsatzTV.Infrastructure.Migrations
b.ToTable("SmartCollection", (string)null);
});
modelBuilder.Entity("ErsatzTV.Core.Domain.SongMetadata", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<DateTime>("DateAdded")
.HasColumnType("TEXT");
b.Property<DateTime>("DateUpdated")
.HasColumnType("TEXT");
b.Property<int>("MetadataKind")
.HasColumnType("INTEGER");
b.Property<string>("OriginalTitle")
.HasColumnType("TEXT");
b.Property<DateTime?>("ReleaseDate")
.HasColumnType("TEXT");
b.Property<int>("SongId")
.HasColumnType("INTEGER");
b.Property<string>("SortTitle")
.HasColumnType("TEXT");
b.Property<string>("Title")
.HasColumnType("TEXT");
b.Property<int?>("Year")
.HasColumnType("INTEGER");
b.HasKey("Id");
b.HasIndex("SongId");
b.ToTable("SongMetadata", (string)null);
});
modelBuilder.Entity("ErsatzTV.Core.Domain.Studio", b =>
{
b.Property<int>("Id")
@@ -1633,6 +1701,9 @@ namespace ErsatzTV.Infrastructure.Migrations
b.Property<int?>("ShowMetadataId")
.HasColumnType("INTEGER");
b.Property<int?>("SongMetadataId")
.HasColumnType("INTEGER");
b.HasKey("Id");
b.HasIndex("ArtistMetadataId");
@@ -1649,6 +1720,8 @@ namespace ErsatzTV.Infrastructure.Migrations
b.HasIndex("ShowMetadataId");
b.HasIndex("SongMetadataId");
b.ToTable("Studio", (string)null);
});
@@ -1701,6 +1774,9 @@ namespace ErsatzTV.Infrastructure.Migrations
b.Property<int?>("ShowMetadataId")
.HasColumnType("INTEGER");
b.Property<int?>("SongMetadataId")
.HasColumnType("INTEGER");
b.HasKey("Id");
b.HasIndex("ArtistMetadataId");
@@ -1717,6 +1793,8 @@ namespace ErsatzTV.Infrastructure.Migrations
b.HasIndex("ShowMetadataId");
b.HasIndex("SongMetadataId");
b.ToTable("Tag");
});
@@ -2052,6 +2130,13 @@ namespace ErsatzTV.Infrastructure.Migrations
b.ToTable("Show", (string)null);
});
modelBuilder.Entity("ErsatzTV.Core.Domain.Song", b =>
{
b.HasBaseType("ErsatzTV.Core.Domain.MediaItem");
b.ToTable("Song", (string)null);
});
modelBuilder.Entity("ErsatzTV.Core.Domain.EmbyEpisode", b =>
{
b.HasBaseType("ErsatzTV.Core.Domain.Episode");
@@ -2234,6 +2319,10 @@ namespace ErsatzTV.Infrastructure.Migrations
.HasForeignKey("ShowMetadataId")
.OnDelete(DeleteBehavior.Cascade);
b.HasOne("ErsatzTV.Core.Domain.SongMetadata", null)
.WithMany("Actors")
.HasForeignKey("SongMetadataId");
b.Navigation("Artwork");
});
@@ -2289,6 +2378,11 @@ namespace ErsatzTV.Infrastructure.Migrations
.WithMany("Artwork")
.HasForeignKey("ShowMetadataId")
.OnDelete(DeleteBehavior.Cascade);
b.HasOne("ErsatzTV.Core.Domain.SongMetadata", null)
.WithMany("Artwork")
.HasForeignKey("SongMetadataId")
.OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity("ErsatzTV.Core.Domain.Channel", b =>
@@ -2456,6 +2550,10 @@ namespace ErsatzTV.Infrastructure.Migrations
.WithMany("Genres")
.HasForeignKey("ShowMetadataId")
.OnDelete(DeleteBehavior.Cascade);
b.HasOne("ErsatzTV.Core.Domain.SongMetadata", null)
.WithMany("Genres")
.HasForeignKey("SongMetadataId");
});
modelBuilder.Entity("ErsatzTV.Core.Domain.JellyfinConnection", b =>
@@ -2578,6 +2676,11 @@ namespace ErsatzTV.Infrastructure.Migrations
.WithMany("MediaVersions")
.HasForeignKey("OtherVideoId")
.OnDelete(DeleteBehavior.Cascade);
b.HasOne("ErsatzTV.Core.Domain.Song", null)
.WithMany("MediaVersions")
.HasForeignKey("SongId")
.OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity("ErsatzTV.Core.Domain.MetadataGuid", b =>
@@ -2613,6 +2716,10 @@ namespace ErsatzTV.Infrastructure.Migrations
.WithMany("Guids")
.HasForeignKey("ShowMetadataId")
.OnDelete(DeleteBehavior.Cascade);
b.HasOne("ErsatzTV.Core.Domain.SongMetadata", null)
.WithMany("Guids")
.HasForeignKey("SongMetadataId");
});
modelBuilder.Entity("ErsatzTV.Core.Domain.Mood", b =>
@@ -2963,6 +3070,17 @@ namespace ErsatzTV.Infrastructure.Migrations
b.Navigation("Show");
});
modelBuilder.Entity("ErsatzTV.Core.Domain.SongMetadata", b =>
{
b.HasOne("ErsatzTV.Core.Domain.Song", "Song")
.WithMany("SongMetadata")
.HasForeignKey("SongId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Song");
});
modelBuilder.Entity("ErsatzTV.Core.Domain.Studio", b =>
{
b.HasOne("ErsatzTV.Core.Domain.ArtistMetadata", null)
@@ -2995,6 +3113,10 @@ namespace ErsatzTV.Infrastructure.Migrations
.WithMany("Studios")
.HasForeignKey("ShowMetadataId")
.OnDelete(DeleteBehavior.Cascade);
b.HasOne("ErsatzTV.Core.Domain.SongMetadata", null)
.WithMany("Studios")
.HasForeignKey("SongMetadataId");
});
modelBuilder.Entity("ErsatzTV.Core.Domain.Style", b =>
@@ -3038,6 +3160,11 @@ namespace ErsatzTV.Infrastructure.Migrations
.WithMany("Tags")
.HasForeignKey("ShowMetadataId")
.OnDelete(DeleteBehavior.Cascade);
b.HasOne("ErsatzTV.Core.Domain.SongMetadata", null)
.WithMany("Tags")
.HasForeignKey("SongMetadataId")
.OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity("ErsatzTV.Core.Domain.TraktListItem", b =>
@@ -3286,6 +3413,15 @@ namespace ErsatzTV.Infrastructure.Migrations
.IsRequired();
});
modelBuilder.Entity("ErsatzTV.Core.Domain.Song", b =>
{
b.HasOne("ErsatzTV.Core.Domain.MediaItem", null)
.WithOne()
.HasForeignKey("ErsatzTV.Core.Domain.Song", "Id")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("ErsatzTV.Core.Domain.EmbyEpisode", b =>
{
b.HasOne("ErsatzTV.Core.Domain.Episode", null)
@@ -3584,6 +3720,21 @@ namespace ErsatzTV.Infrastructure.Migrations
b.Navigation("MultiCollectionSmartItems");
});
modelBuilder.Entity("ErsatzTV.Core.Domain.SongMetadata", b =>
{
b.Navigation("Actors");
b.Navigation("Artwork");
b.Navigation("Genres");
b.Navigation("Guids");
b.Navigation("Studios");
b.Navigation("Tags");
});
modelBuilder.Entity("ErsatzTV.Core.Domain.TraktList", b =>
{
b.Navigation("Items");
@@ -3663,6 +3814,13 @@ namespace ErsatzTV.Infrastructure.Migrations
b.Navigation("ShowMetadata");
});
modelBuilder.Entity("ErsatzTV.Core.Domain.Song", b =>
{
b.Navigation("MediaVersions");
b.Navigation("SongMetadata");
});
#pragma warning restore 612, 618
}
}