add multi collections (#315)
* start to add multi-collections * create multi collection with no items * edit multi collections * fix plex credentials threading issue * add playback order to multi collection items * group episodes outside of shuffled enumerator * move playback order onto each schedule item * fix multi collection grouping * update changelog
This commit is contained in:
+27
@@ -0,0 +1,27 @@
|
||||
using ErsatzTV.Core.Domain;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Metadata.Builders;
|
||||
|
||||
namespace ErsatzTV.Infrastructure.Data.Configurations
|
||||
{
|
||||
public class MultiCollectionConfiguration : IEntityTypeConfiguration<MultiCollection>
|
||||
{
|
||||
public void Configure(EntityTypeBuilder<MultiCollection> builder)
|
||||
{
|
||||
builder.ToTable("MultiCollection");
|
||||
|
||||
builder.HasMany(m => m.Collections)
|
||||
.WithMany(m => m.MultiCollections)
|
||||
.UsingEntity<MultiCollectionItem>(
|
||||
j => j.HasOne(mci => mci.Collection)
|
||||
.WithMany(c => c.MultiCollectionItems)
|
||||
.HasForeignKey(mci => mci.CollectionId)
|
||||
.OnDelete(DeleteBehavior.Cascade),
|
||||
j => j.HasOne(mci => mci.MultiCollection)
|
||||
.WithMany(mc => mc.MultiCollectionItems)
|
||||
.HasForeignKey(mci => mci.MultiCollectionId)
|
||||
.OnDelete(DeleteBehavior.Cascade),
|
||||
j => j.HasKey(mci => new { mci.MultiCollectionId, mci.CollectionId }));
|
||||
}
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
using ErsatzTV.Core.Domain;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Metadata.Builders;
|
||||
|
||||
namespace ErsatzTV.Infrastructure.Data.Configurations
|
||||
{
|
||||
public class MultiCollectionItemConfiguration : IEntityTypeConfiguration<MultiCollectionItem>
|
||||
{
|
||||
public void Configure(EntityTypeBuilder<MultiCollectionItem> builder) => builder.ToTable("MultiCollectionItem");
|
||||
}
|
||||
}
|
||||
+6
@@ -19,6 +19,12 @@ namespace ErsatzTV.Infrastructure.Data.Configurations
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired(false);
|
||||
|
||||
builder.HasOne(i => i.MultiCollection)
|
||||
.WithMany()
|
||||
.HasForeignKey(i => i.MultiCollectionId)
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired(false);
|
||||
|
||||
builder.HasOne(i => i.MediaItem)
|
||||
.WithMany()
|
||||
.HasForeignKey(i => i.MediaItemId)
|
||||
|
||||
@@ -21,6 +21,12 @@ namespace ErsatzTV.Infrastructure.Data.Configurations
|
||||
.HasForeignKey(i => i.MediaItemId)
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired(false);
|
||||
|
||||
builder.HasOne(i => i.MultiCollection)
|
||||
.WithMany()
|
||||
.HasForeignKey(i => i.MultiCollectionId)
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,8 @@ using System.Threading.Tasks;
|
||||
using Dapper;
|
||||
using ErsatzTV.Core.Domain;
|
||||
using ErsatzTV.Core.Interfaces.Repositories;
|
||||
using ErsatzTV.Core.Scheduling;
|
||||
using ErsatzTV.Infrastructure.Extensions;
|
||||
using LanguageExt;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using static LanguageExt.Prelude;
|
||||
@@ -50,16 +52,113 @@ namespace ErsatzTV.Infrastructure.Data.Repositories
|
||||
return result.Distinct().ToList();
|
||||
}
|
||||
|
||||
public async Task<List<MediaItem>> GetMultiCollectionItems(int id)
|
||||
{
|
||||
await using TvContext dbContext = _dbContextFactory.CreateDbContext();
|
||||
|
||||
var result = new List<MediaItem>();
|
||||
|
||||
Option<MultiCollection> maybeMultiCollection = await dbContext.MultiCollections
|
||||
.Include(mc => mc.Collections)
|
||||
.SelectOneAsync(mc => mc.Id, mc => mc.Id == id);
|
||||
|
||||
foreach (MultiCollection multiCollection in maybeMultiCollection)
|
||||
{
|
||||
foreach (int collectionId in multiCollection.Collections.Map(c => c.Id))
|
||||
{
|
||||
result.AddRange(await GetMovieItems(dbContext, collectionId));
|
||||
result.AddRange(await GetShowItems(dbContext, collectionId));
|
||||
result.AddRange(await GetSeasonItems(dbContext, collectionId));
|
||||
result.AddRange(await GetEpisodeItems(dbContext, collectionId));
|
||||
result.AddRange(await GetArtistItems(dbContext, collectionId));
|
||||
result.AddRange(await GetMusicVideoItems(dbContext, collectionId));
|
||||
}
|
||||
}
|
||||
|
||||
return result.Distinct().ToList();
|
||||
}
|
||||
|
||||
public async Task<List<CollectionWithItems>> GetMultiCollectionCollections(int id)
|
||||
{
|
||||
await using TvContext dbContext = _dbContextFactory.CreateDbContext();
|
||||
|
||||
var result = new List<CollectionWithItems>();
|
||||
|
||||
Option<MultiCollection> maybeMultiCollection = await dbContext.MultiCollections
|
||||
.Include(mc => mc.Collections)
|
||||
.Include(mc => mc.MultiCollectionItems)
|
||||
.ThenInclude(mci => mci.Collection)
|
||||
.SelectOneAsync(mc => mc.Id, mc => mc.Id == id);
|
||||
|
||||
foreach (MultiCollection multiCollection in maybeMultiCollection)
|
||||
{
|
||||
foreach (MultiCollectionItem multiCollectionItem in multiCollection.MultiCollectionItems)
|
||||
{
|
||||
List<MediaItem> items = await GetItems(multiCollectionItem.CollectionId);
|
||||
|
||||
if (multiCollectionItem.Collection.UseCustomPlaybackOrder)
|
||||
{
|
||||
foreach (Collection collection in await GetCollectionWithCollectionItemsUntracked(
|
||||
multiCollectionItem.CollectionId))
|
||||
{
|
||||
var sortedItems = collection.CollectionItems
|
||||
.OrderBy(ci => ci.CustomIndex)
|
||||
.Map(ci => items.First(i => i.Id == ci.MediaItemId))
|
||||
.ToList();
|
||||
|
||||
result.Add(
|
||||
new CollectionWithItems(
|
||||
multiCollectionItem.CollectionId,
|
||||
sortedItems,
|
||||
multiCollectionItem.ScheduleAsGroup,
|
||||
multiCollectionItem.PlaybackOrder,
|
||||
multiCollectionItem.Collection.UseCustomPlaybackOrder));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
result.Add(
|
||||
new CollectionWithItems(
|
||||
multiCollectionItem.CollectionId,
|
||||
items,
|
||||
multiCollectionItem.ScheduleAsGroup,
|
||||
multiCollectionItem.PlaybackOrder,
|
||||
multiCollectionItem.Collection.UseCustomPlaybackOrder));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// remove duplicate items from ungrouped collections
|
||||
var toRemoveFrom = result.Filter(c => !c.ScheduleAsGroup).ToList();
|
||||
var toRemove = result.Filter(c => c.ScheduleAsGroup)
|
||||
.SelectMany(c => c.MediaItems.Map(i => i.Id))
|
||||
.Distinct()
|
||||
.ToList();
|
||||
|
||||
foreach (CollectionWithItems collection in toRemoveFrom)
|
||||
{
|
||||
collection.MediaItems.RemoveAll(mi => toRemove.Contains(mi.Id));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public Task<List<int>> PlayoutIdsUsingCollection(int collectionId) =>
|
||||
_dbConnection.QueryAsync<int>(
|
||||
@"SELECT DISTINCT p.Id
|
||||
FROM Playout p
|
||||
INNER JOIN ProgramSchedule PS on p.ProgramScheduleId = PS.Id
|
||||
INNER JOIN ProgramScheduleItem PSI on p.Anchor_NextScheduleItemId = PSI.Id
|
||||
WHERE PSI.CollectionId = @CollectionId",
|
||||
@"SELECT DISTINCT p.PlayoutId
|
||||
FROM PlayoutProgramScheduleAnchor p
|
||||
WHERE p.CollectionId = @CollectionId",
|
||||
new { CollectionId = collectionId })
|
||||
.Map(result => result.ToList());
|
||||
|
||||
public Task<List<int>> PlayoutIdsUsingMultiCollection(int multiCollectionId) =>
|
||||
_dbConnection.QueryAsync<int>(
|
||||
@"SELECT DISTINCT p.PlayoutId
|
||||
FROM PlayoutProgramScheduleAnchor p
|
||||
WHERE p.MultiCollectionId = @MultiCollectionId",
|
||||
new { MultiCollectionId = multiCollectionId })
|
||||
.Map(result => result.ToList());
|
||||
|
||||
public Task<bool> IsCustomPlaybackOrder(int collectionId) =>
|
||||
_dbConnection.QuerySingleAsync<bool>(
|
||||
@"SELECT IFNULL(MIN(UseCustomPlaybackOrder), 0) FROM Collection WHERE Id = @CollectionId",
|
||||
|
||||
@@ -58,6 +58,7 @@ namespace ErsatzTV.Infrastructure.Data
|
||||
public DbSet<EmbyEpisode> EmbyEpisodes { get; set; }
|
||||
public DbSet<Collection> Collections { get; set; }
|
||||
public DbSet<CollectionItem> CollectionItems { get; set; }
|
||||
public DbSet<MultiCollection> MultiCollections { get; set; }
|
||||
public DbSet<ProgramSchedule> ProgramSchedules { get; set; }
|
||||
public DbSet<ProgramScheduleItem> ProgramScheduleItems { get; set; }
|
||||
public DbSet<Playout> Playouts { get; set; }
|
||||
|
||||
+3064
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,125 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
namespace ErsatzTV.Infrastructure.Migrations
|
||||
{
|
||||
public partial class Add_MultiCollection : Migration
|
||||
{
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AddColumn<int>(
|
||||
name: "MultiCollectionId",
|
||||
table: "ProgramScheduleItem",
|
||||
type: "INTEGER",
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<int>(
|
||||
name: "MultiCollectionId",
|
||||
table: "PlayoutProgramScheduleAnchor",
|
||||
type: "INTEGER",
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "MultiCollection",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<int>(type: "INTEGER", nullable: false)
|
||||
.Annotation("Sqlite:Autoincrement", true),
|
||||
Name = table.Column<string>(type: "TEXT", nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_MultiCollection", x => x.Id);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "MultiCollectionItem",
|
||||
columns: table => new
|
||||
{
|
||||
MultiCollectionId = table.Column<int>(type: "INTEGER", nullable: false),
|
||||
CollectionId = table.Column<int>(type: "INTEGER", nullable: false),
|
||||
ScheduleAsGroup = table.Column<bool>(type: "INTEGER", nullable: false),
|
||||
PlaybackOrder = table.Column<int>(type: "INTEGER", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_MultiCollectionItem", x => new { x.MultiCollectionId, x.CollectionId });
|
||||
table.ForeignKey(
|
||||
name: "FK_MultiCollectionItem_Collection_CollectionId",
|
||||
column: x => x.CollectionId,
|
||||
principalTable: "Collection",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
table.ForeignKey(
|
||||
name: "FK_MultiCollectionItem_MultiCollection_MultiCollectionId",
|
||||
column: x => x.MultiCollectionId,
|
||||
principalTable: "MultiCollection",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_ProgramScheduleItem_MultiCollectionId",
|
||||
table: "ProgramScheduleItem",
|
||||
column: "MultiCollectionId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_PlayoutProgramScheduleAnchor_MultiCollectionId",
|
||||
table: "PlayoutProgramScheduleAnchor",
|
||||
column: "MultiCollectionId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_MultiCollectionItem_CollectionId",
|
||||
table: "MultiCollectionItem",
|
||||
column: "CollectionId");
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_PlayoutProgramScheduleAnchor_MultiCollection_MultiCollectionId",
|
||||
table: "PlayoutProgramScheduleAnchor",
|
||||
column: "MultiCollectionId",
|
||||
principalTable: "MultiCollection",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_ProgramScheduleItem_MultiCollection_MultiCollectionId",
|
||||
table: "ProgramScheduleItem",
|
||||
column: "MultiCollectionId",
|
||||
principalTable: "MultiCollection",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
}
|
||||
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_PlayoutProgramScheduleAnchor_MultiCollection_MultiCollectionId",
|
||||
table: "PlayoutProgramScheduleAnchor");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_ProgramScheduleItem_MultiCollection_MultiCollectionId",
|
||||
table: "ProgramScheduleItem");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "MultiCollectionItem");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "MultiCollection");
|
||||
|
||||
migrationBuilder.DropIndex(
|
||||
name: "IX_ProgramScheduleItem_MultiCollectionId",
|
||||
table: "ProgramScheduleItem");
|
||||
|
||||
migrationBuilder.DropIndex(
|
||||
name: "IX_PlayoutProgramScheduleAnchor_MultiCollectionId",
|
||||
table: "PlayoutProgramScheduleAnchor");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "MultiCollectionId",
|
||||
table: "ProgramScheduleItem");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "MultiCollectionId",
|
||||
table: "PlayoutProgramScheduleAnchor");
|
||||
}
|
||||
}
|
||||
}
|
||||
Generated
+3067
File diff suppressed because it is too large
Load Diff
+27
@@ -0,0 +1,27 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
namespace ErsatzTV.Infrastructure.Migrations
|
||||
{
|
||||
public partial class Add_ProgramScheduleItemPlaybackOrder : Migration
|
||||
{
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AddColumn<int>(
|
||||
name: "PlaybackOrder",
|
||||
table: "ProgramScheduleItem",
|
||||
type: "INTEGER",
|
||||
nullable: false,
|
||||
defaultValue: 0);
|
||||
|
||||
migrationBuilder.Sql(
|
||||
"UPDATE ProgramScheduleItem SET PlaybackOrder = (SELECT MediaCollectionPlaybackOrder FROM ProgramSchedule WHERE ProgramSchedule.Id = ProgramScheduleItem.ProgramScheduleId)");
|
||||
}
|
||||
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropColumn(
|
||||
name: "PlaybackOrder",
|
||||
table: "ProgramScheduleItem");
|
||||
}
|
||||
}
|
||||
}
|
||||
+3064
File diff suppressed because it is too large
Load Diff
+24
@@ -0,0 +1,24 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
namespace ErsatzTV.Infrastructure.Migrations
|
||||
{
|
||||
public partial class Remove_ProgramScheduleMediaCollectionPlaybackOrder : Migration
|
||||
{
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropColumn(
|
||||
name: "MediaCollectionPlaybackOrder",
|
||||
table: "ProgramSchedule");
|
||||
}
|
||||
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AddColumn<int>(
|
||||
name: "MediaCollectionPlaybackOrder",
|
||||
table: "ProgramSchedule",
|
||||
type: "INTEGER",
|
||||
nullable: false,
|
||||
defaultValue: 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -14,7 +14,7 @@ namespace ErsatzTV.Infrastructure.Migrations
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.HasAnnotation("ProductVersion", "5.0.7");
|
||||
.HasAnnotation("ProductVersion", "5.0.8");
|
||||
|
||||
modelBuilder.Entity("ErsatzTV.Core.Domain.Actor", b =>
|
||||
{
|
||||
@@ -944,6 +944,41 @@ namespace ErsatzTV.Infrastructure.Migrations
|
||||
b.ToTable("MovieMetadata");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("ErsatzTV.Core.Domain.MultiCollection", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("MultiCollection");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("ErsatzTV.Core.Domain.MultiCollectionItem", b =>
|
||||
{
|
||||
b.Property<int>("MultiCollectionId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("CollectionId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("PlaybackOrder")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<bool>("ScheduleAsGroup")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("MultiCollectionId", "CollectionId");
|
||||
|
||||
b.HasIndex("CollectionId");
|
||||
|
||||
b.ToTable("MultiCollectionItem");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("ErsatzTV.Core.Domain.MusicVideoMetadata", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
@@ -1062,6 +1097,9 @@ namespace ErsatzTV.Infrastructure.Migrations
|
||||
b.Property<int?>("MediaItemId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int?>("MultiCollectionId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("PlayoutId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
@@ -1074,6 +1112,8 @@ namespace ErsatzTV.Infrastructure.Migrations
|
||||
|
||||
b.HasIndex("MediaItemId");
|
||||
|
||||
b.HasIndex("MultiCollectionId");
|
||||
|
||||
b.HasIndex("PlayoutId");
|
||||
|
||||
b.HasIndex("ProgramScheduleId");
|
||||
@@ -1134,9 +1174,6 @@ namespace ErsatzTV.Infrastructure.Migrations
|
||||
b.Property<bool>("KeepMultiPartEpisodesTogether")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("MediaCollectionPlaybackOrder")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
@@ -1172,6 +1209,12 @@ namespace ErsatzTV.Infrastructure.Migrations
|
||||
b.Property<int?>("MediaItemId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int?>("MultiCollectionId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("PlaybackOrder")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("ProgramScheduleId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
@@ -1184,6 +1227,8 @@ namespace ErsatzTV.Infrastructure.Migrations
|
||||
|
||||
b.HasIndex("MediaItemId");
|
||||
|
||||
b.HasIndex("MultiCollectionId");
|
||||
|
||||
b.HasIndex("ProgramScheduleId");
|
||||
|
||||
b.ToTable("ProgramScheduleItem");
|
||||
@@ -2156,6 +2201,25 @@ namespace ErsatzTV.Infrastructure.Migrations
|
||||
b.Navigation("Movie");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("ErsatzTV.Core.Domain.MultiCollectionItem", b =>
|
||||
{
|
||||
b.HasOne("ErsatzTV.Core.Domain.Collection", "Collection")
|
||||
.WithMany("MultiCollectionItems")
|
||||
.HasForeignKey("CollectionId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("ErsatzTV.Core.Domain.MultiCollection", "MultiCollection")
|
||||
.WithMany("MultiCollectionItems")
|
||||
.HasForeignKey("MultiCollectionId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Collection");
|
||||
|
||||
b.Navigation("MultiCollection");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("ErsatzTV.Core.Domain.MusicVideoMetadata", b =>
|
||||
{
|
||||
b.HasOne("ErsatzTV.Core.Domain.MusicVideo", "MusicVideo")
|
||||
@@ -2257,6 +2321,11 @@ namespace ErsatzTV.Infrastructure.Migrations
|
||||
.HasForeignKey("MediaItemId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
b.HasOne("ErsatzTV.Core.Domain.MultiCollection", "MultiCollection")
|
||||
.WithMany()
|
||||
.HasForeignKey("MultiCollectionId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
b.HasOne("ErsatzTV.Core.Domain.Playout", "Playout")
|
||||
.WithMany("ProgramScheduleAnchors")
|
||||
.HasForeignKey("PlayoutId")
|
||||
@@ -2294,6 +2363,8 @@ namespace ErsatzTV.Infrastructure.Migrations
|
||||
|
||||
b.Navigation("MediaItem");
|
||||
|
||||
b.Navigation("MultiCollection");
|
||||
|
||||
b.Navigation("Playout");
|
||||
|
||||
b.Navigation("ProgramSchedule");
|
||||
@@ -2333,6 +2404,11 @@ namespace ErsatzTV.Infrastructure.Migrations
|
||||
.HasForeignKey("MediaItemId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
b.HasOne("ErsatzTV.Core.Domain.MultiCollection", "MultiCollection")
|
||||
.WithMany()
|
||||
.HasForeignKey("MultiCollectionId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
b.HasOne("ErsatzTV.Core.Domain.ProgramSchedule", "ProgramSchedule")
|
||||
.WithMany("Items")
|
||||
.HasForeignKey("ProgramScheduleId")
|
||||
@@ -2343,6 +2419,8 @@ namespace ErsatzTV.Infrastructure.Migrations
|
||||
|
||||
b.Navigation("MediaItem");
|
||||
|
||||
b.Navigation("MultiCollection");
|
||||
|
||||
b.Navigation("ProgramSchedule");
|
||||
});
|
||||
|
||||
@@ -2781,6 +2859,8 @@ namespace ErsatzTV.Infrastructure.Migrations
|
||||
modelBuilder.Entity("ErsatzTV.Core.Domain.Collection", b =>
|
||||
{
|
||||
b.Navigation("CollectionItems");
|
||||
|
||||
b.Navigation("MultiCollectionItems");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("ErsatzTV.Core.Domain.EpisodeMetadata", b =>
|
||||
@@ -2850,6 +2930,11 @@ namespace ErsatzTV.Infrastructure.Migrations
|
||||
b.Navigation("Writers");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("ErsatzTV.Core.Domain.MultiCollection", b =>
|
||||
{
|
||||
b.Navigation("MultiCollectionItems");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("ErsatzTV.Core.Domain.MusicVideoMetadata", b =>
|
||||
{
|
||||
b.Navigation("Actors");
|
||||
|
||||
@@ -51,37 +51,35 @@ namespace ErsatzTV.Infrastructure.Plex
|
||||
.Append(httpsResources.Filter(resource => resource.HttpsRequired))
|
||||
.ToList();
|
||||
|
||||
IEnumerable<PlexMediaSource> sources = await allResources
|
||||
IEnumerable<PlexResource> ownedResources = allResources
|
||||
.Filter(r => r.Provides.Split(",").Any(p => p == "server"))
|
||||
.Filter(r => r.Owned) // TODO: maybe support non-owned servers in the future
|
||||
.Map(
|
||||
async resource =>
|
||||
{
|
||||
var serverAuthToken = new PlexServerAuthToken(
|
||||
resource.ClientIdentifier,
|
||||
resource.AccessToken);
|
||||
.Filter(r => r.Owned); // TODO: maybe support non-owned servers in the future
|
||||
|
||||
await _plexSecretStore.UpsertServerAuthToken(serverAuthToken);
|
||||
List<PlexResourceConnection> sortedConnections = resource.HttpsRequired
|
||||
? resource.Connections
|
||||
: resource.Connections.OrderBy(c => c.Local ? 0 : 1).ToList();
|
||||
|
||||
var source = new PlexMediaSource
|
||||
{
|
||||
ServerName = resource.Name,
|
||||
ProductVersion = resource.ProductVersion,
|
||||
Platform = resource.Platform,
|
||||
PlatformVersion = resource.PlatformVersion,
|
||||
ClientIdentifier = resource.ClientIdentifier,
|
||||
Connections = sortedConnections
|
||||
.Map(c => new PlexConnection { Uri = c.Uri }).ToList()
|
||||
};
|
||||
foreach (PlexResource resource in ownedResources)
|
||||
{
|
||||
var serverAuthToken = new PlexServerAuthToken(
|
||||
resource.ClientIdentifier,
|
||||
resource.AccessToken);
|
||||
|
||||
return source;
|
||||
})
|
||||
.Sequence();
|
||||
await _plexSecretStore.UpsertServerAuthToken(serverAuthToken);
|
||||
List<PlexResourceConnection> sortedConnections = resource.HttpsRequired
|
||||
? resource.Connections
|
||||
: resource.Connections.OrderBy(c => c.Local ? 0 : 1).ToList();
|
||||
|
||||
result.AddRange(sources);
|
||||
var source = new PlexMediaSource
|
||||
{
|
||||
ServerName = resource.Name,
|
||||
ProductVersion = resource.ProductVersion,
|
||||
Platform = resource.Platform,
|
||||
PlatformVersion = resource.PlatformVersion,
|
||||
ClientIdentifier = resource.ClientIdentifier,
|
||||
Connections = sortedConnections
|
||||
.Map(c => new PlexConnection { Uri = c.Uri }).ToList()
|
||||
};
|
||||
|
||||
result.Add(source);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
Reference in New Issue
Block a user