add preferred language (#109)
* add explicit warning for zero/invalid duration media items * set dateadded on plex media versions * add media stream table * save local media streams to db * save plex media streams to db * add preferred language settings (no validation) * use preferred language if possible * code cleanup * proper language code validation * force scan of all libraries to pull in media streams
This commit is contained in:
@@ -0,0 +1,11 @@
|
||||
using ErsatzTV.Core.Domain;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Metadata.Builders;
|
||||
|
||||
namespace ErsatzTV.Infrastructure.Data.Configurations
|
||||
{
|
||||
public class MediaStreamConfiguration : IEntityTypeConfiguration<MediaStream>
|
||||
{
|
||||
public void Configure(EntityTypeBuilder<MediaStream> builder) => builder.ToTable("MediaStream");
|
||||
}
|
||||
}
|
||||
@@ -14,6 +14,11 @@ namespace ErsatzTV.Infrastructure.Data.Configurations
|
||||
.WithOne(f => f.MediaVersion)
|
||||
.HasForeignKey(f => f.MediaVersionId)
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
builder.HasMany(v => v.Streams)
|
||||
.WithOne(s => s.MediaVersion)
|
||||
.HasForeignKey(s => s.MediaVersionId)
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
using System;
|
||||
using System.Data;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Dapper;
|
||||
using ErsatzTV.Core.Domain;
|
||||
using ErsatzTV.Core.Interfaces.Repositories;
|
||||
using LanguageExt;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using static LanguageExt.Prelude;
|
||||
|
||||
namespace ErsatzTV.Infrastructure.Data.Repositories
|
||||
{
|
||||
@@ -44,15 +46,66 @@ namespace ErsatzTV.Infrastructure.Data.Repositories
|
||||
return await dbContext.SaveChangesAsync() > 0;
|
||||
}
|
||||
|
||||
public async Task<bool> UpdateLocalStatistics(MediaVersion mediaVersion)
|
||||
public async Task<bool> UpdateLocalStatistics(
|
||||
int mediaVersionId,
|
||||
MediaVersion incoming,
|
||||
bool updateVersion = true)
|
||||
{
|
||||
await using TvContext dbContext = _dbContextFactory.CreateDbContext();
|
||||
dbContext.Entry(mediaVersion).State = EntityState.Modified;
|
||||
return await dbContext.SaveChangesAsync() > 0;
|
||||
Option<MediaVersion> maybeVersion = await dbContext.MediaVersions
|
||||
.Include(v => v.Streams)
|
||||
.OrderBy(v => v.Id)
|
||||
.SingleOrDefaultAsync(v => v.Id == mediaVersionId)
|
||||
.Map(Optional);
|
||||
|
||||
return await maybeVersion.Match(
|
||||
async existing =>
|
||||
{
|
||||
if (updateVersion)
|
||||
{
|
||||
existing.DateUpdated = incoming.DateUpdated;
|
||||
existing.Duration = incoming.Duration;
|
||||
existing.SampleAspectRatio = incoming.SampleAspectRatio;
|
||||
existing.DisplayAspectRatio = incoming.DisplayAspectRatio;
|
||||
existing.Width = incoming.Width;
|
||||
existing.Height = incoming.Height;
|
||||
existing.VideoScanKind = incoming.VideoScanKind;
|
||||
}
|
||||
|
||||
var toAdd = incoming.Streams.Filter(s => existing.Streams.All(es => es.Index != s.Index)).ToList();
|
||||
var toRemove = existing.Streams.Filter(es => incoming.Streams.All(s => s.Index != es.Index))
|
||||
.ToList();
|
||||
var toUpdate = incoming.Streams.Except(toAdd).ToList();
|
||||
|
||||
// add
|
||||
existing.Streams.AddRange(toAdd);
|
||||
|
||||
// remove
|
||||
existing.Streams.RemoveAll(s => toRemove.Contains(s));
|
||||
|
||||
// update
|
||||
foreach (MediaStream incomingStream in toUpdate)
|
||||
{
|
||||
MediaStream existingStream = existing.Streams.First(s => s.Index == incomingStream.Index);
|
||||
|
||||
existingStream.Codec = incomingStream.Codec;
|
||||
existingStream.Profile = incomingStream.Profile;
|
||||
existingStream.MediaStreamKind = incomingStream.MediaStreamKind;
|
||||
existingStream.Language = incomingStream.Language;
|
||||
existingStream.Channels = incomingStream.Channels;
|
||||
existingStream.Title = incomingStream.Title;
|
||||
existingStream.Default = incomingStream.Default;
|
||||
existingStream.Forced = incomingStream.Forced;
|
||||
}
|
||||
|
||||
return await dbContext.SaveChangesAsync() > 0;
|
||||
},
|
||||
() => Task.FromResult(false));
|
||||
}
|
||||
|
||||
public Task<bool> UpdatePlexStatistics(MediaVersion mediaVersion) =>
|
||||
_dbConnection.ExecuteAsync(
|
||||
public async Task<bool> UpdatePlexStatistics(int mediaVersionId, MediaVersion incoming)
|
||||
{
|
||||
bool updatedVersion = await _dbConnection.ExecuteAsync(
|
||||
@"UPDATE MediaVersion SET
|
||||
SampleAspectRatio = @SampleAspectRatio,
|
||||
VideoScanKind = @VideoScanKind,
|
||||
@@ -60,12 +113,15 @@ namespace ErsatzTV.Infrastructure.Data.Repositories
|
||||
WHERE Id = @MediaVersionId",
|
||||
new
|
||||
{
|
||||
mediaVersion.SampleAspectRatio,
|
||||
mediaVersion.VideoScanKind,
|
||||
mediaVersion.DateUpdated,
|
||||
MediaVersionId = mediaVersion.Id
|
||||
incoming.SampleAspectRatio,
|
||||
incoming.VideoScanKind,
|
||||
incoming.DateUpdated,
|
||||
MediaVersionId = mediaVersionId
|
||||
}).Map(result => result > 0);
|
||||
|
||||
return await UpdateLocalStatistics(mediaVersionId, incoming, false) || updatedVersion;
|
||||
}
|
||||
|
||||
public Task<Unit> UpdateArtworkPath(Artwork artwork) =>
|
||||
_dbConnection.ExecuteAsync(
|
||||
"UPDATE Artwork SET Path = @Path, DateUpdated = @DateUpdated WHERE Id = @Id",
|
||||
|
||||
@@ -64,6 +64,8 @@ namespace ErsatzTV.Infrastructure.Data.Repositories
|
||||
.ThenInclude(lp => lp.Library)
|
||||
.Include(i => i.MediaVersions)
|
||||
.ThenInclude(mv => mv.MediaFiles)
|
||||
.Include(i => i.MediaVersions)
|
||||
.ThenInclude(mv => mv.Streams)
|
||||
.OrderBy(i => i.MediaVersions.First().MediaFiles.First().Path)
|
||||
.SingleOrDefaultAsync(i => i.MediaVersions.First().MediaFiles.First().Path == path);
|
||||
|
||||
@@ -91,6 +93,8 @@ namespace ErsatzTV.Infrastructure.Data.Repositories
|
||||
.ThenInclude(mm => mm.Artwork)
|
||||
.Include(i => i.MediaVersions)
|
||||
.ThenInclude(mv => mv.MediaFiles)
|
||||
.Include(i => i.MediaVersions)
|
||||
.ThenInclude(mv => mv.Streams)
|
||||
.Include(i => i.LibraryPath)
|
||||
.ThenInclude(lp => lp.Library)
|
||||
.OrderBy(i => i.Key)
|
||||
@@ -223,7 +227,8 @@ namespace ErsatzTV.Infrastructure.Data.Repositories
|
||||
MediaFiles = new List<MediaFile>
|
||||
{
|
||||
new() { Path = path }
|
||||
}
|
||||
},
|
||||
Streams = new List<MediaStream>()
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -57,8 +57,14 @@ namespace ErsatzTV.Infrastructure.Data.Repositories
|
||||
.ThenInclude(mi => (mi as Episode).MediaVersions)
|
||||
.ThenInclude(mv => mv.MediaFiles)
|
||||
.Include(i => i.MediaItem)
|
||||
.ThenInclude(mi => (mi as Episode).MediaVersions)
|
||||
.ThenInclude(mv => mv.Streams)
|
||||
.Include(i => i.MediaItem)
|
||||
.ThenInclude(mi => (mi as Movie).MediaVersions)
|
||||
.ThenInclude(mv => mv.MediaFiles)
|
||||
.Include(i => i.MediaItem)
|
||||
.ThenInclude(mi => (mi as Movie).MediaVersions)
|
||||
.ThenInclude(mv => mv.Streams)
|
||||
.AsNoTracking()
|
||||
.SingleOrDefaultAsync()
|
||||
.Map(Optional);
|
||||
|
||||
@@ -283,6 +283,8 @@ namespace ErsatzTV.Infrastructure.Data.Repositories
|
||||
.ThenInclude(em => em.Artwork)
|
||||
.Include(i => i.MediaVersions)
|
||||
.ThenInclude(mv => mv.MediaFiles)
|
||||
.Include(i => i.MediaVersions)
|
||||
.ThenInclude(mv => mv.Streams)
|
||||
.OrderBy(i => i.MediaVersions.First().MediaFiles.First().Path)
|
||||
.SingleOrDefaultAsync(i => i.MediaVersions.First().MediaFiles.First().Path == path);
|
||||
|
||||
@@ -414,6 +416,8 @@ namespace ErsatzTV.Infrastructure.Data.Repositories
|
||||
.ThenInclude(mm => mm.Artwork)
|
||||
.Include(i => i.MediaVersions)
|
||||
.ThenInclude(mv => mv.MediaFiles)
|
||||
.Include(i => i.MediaVersions)
|
||||
.ThenInclude(mv => mv.Streams)
|
||||
.OrderBy(i => i.Key)
|
||||
.SingleOrDefaultAsync(i => i.Key == item.Key);
|
||||
|
||||
@@ -582,7 +586,8 @@ namespace ErsatzTV.Infrastructure.Data.Repositories
|
||||
MediaFiles = new List<MediaFile>
|
||||
{
|
||||
new() { Path = path }
|
||||
}
|
||||
},
|
||||
Streams = new List<MediaStream>()
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user