Browse Source

regularly delete orphaned artwork from db (#223)

pull/224/head
Jason Dove 5 years ago committed by GitHub
parent
commit
95cceb95b9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 7
      ErsatzTV.Application/Maintenance/Commands/DeleteOrphanedArtwork.cs
  2. 23
      ErsatzTV.Application/Maintenance/Commands/DeleteOrphanedArtworkHandler.cs
  3. 13
      ErsatzTV.Core/Interfaces/Repositories/IArtworkRepository.cs
  4. 65
      ErsatzTV.Infrastructure/Data/Repositories/ArtworkRepository.cs
  5. 5
      ErsatzTV/Services/SchedulerService.cs
  6. 5
      ErsatzTV/Services/WorkerService.cs
  7. 1
      ErsatzTV/Startup.cs

7
ErsatzTV.Application/Maintenance/Commands/DeleteOrphanedArtwork.cs

@ -0,0 +1,7 @@ @@ -0,0 +1,7 @@
using ErsatzTV.Core;
using LanguageExt;
namespace ErsatzTV.Application.Maintenance.Commands
{
public record DeleteOrphanedArtwork : MediatR.IRequest<Either<BaseError, Unit>>, IBackgroundServiceRequest;
}

23
ErsatzTV.Application/Maintenance/Commands/DeleteOrphanedArtworkHandler.cs

@ -0,0 +1,23 @@ @@ -0,0 +1,23 @@
using System.Threading;
using System.Threading.Tasks;
using ErsatzTV.Core;
using ErsatzTV.Core.Interfaces.Repositories;
using LanguageExt;
using static LanguageExt.Prelude;
namespace ErsatzTV.Application.Maintenance.Commands
{
public class DeleteOrphanedArtworkHandler : MediatR.IRequestHandler<DeleteOrphanedArtwork, Either<BaseError, Unit>>
{
private readonly IArtworkRepository _artworkRepository;
public DeleteOrphanedArtworkHandler(IArtworkRepository artworkRepository) =>
_artworkRepository = artworkRepository;
public Task<Either<BaseError, Unit>>
Handle(DeleteOrphanedArtwork request, CancellationToken cancellationToken) =>
_artworkRepository.GetOrphanedArtwork()
.Bind(_artworkRepository.Delete)
.Map(_ => Right<BaseError, Unit>(Unit.Default));
}
}

13
ErsatzTV.Core/Interfaces/Repositories/IArtworkRepository.cs

@ -0,0 +1,13 @@ @@ -0,0 +1,13 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using ErsatzTV.Core.Domain;
using LanguageExt;
namespace ErsatzTV.Core.Interfaces.Repositories
{
public interface IArtworkRepository
{
Task<List<Artwork>> GetOrphanedArtwork();
Task<Unit> Delete(List<Artwork> artwork);
}
}

65
ErsatzTV.Infrastructure/Data/Repositories/ArtworkRepository.cs

@ -0,0 +1,65 @@ @@ -0,0 +1,65 @@
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Threading.Tasks;
using Dapper;
using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Interfaces.Repositories;
using LanguageExt;
namespace ErsatzTV.Infrastructure.Data.Repositories
{
public class ArtworkRepository : IArtworkRepository
{
private readonly IDbConnection _dbConnection;
public ArtworkRepository(IDbConnection dbConnection) => _dbConnection = dbConnection;
public Task<List<Artwork>> GetOrphanedArtwork() =>
_dbConnection.QueryAsync<Artwork>(
@"SELECT Artwork.Id, Artwork.Path FROM Artwork
LEFT OUTER JOIN Actor A on Artwork.Id = A.ArtworkId
LEFT OUTER JOIN ArtistMetadata AM on A.ArtistMetadataId = AM.Id
LEFT OUTER JOIN EpisodeMetadata EM on A.EpisodeMetadataId = EM.Id
LEFT OUTER JOIN SeasonMetadata SM on A.SeasonMetadataId = SM.Id
LEFT OUTER JOIN ShowMetadata S on A.ShowMetadataId = S.Id
LEFT OUTER JOIN MovieMetadata MM on A.MovieMetadataId = MM.Id
LEFT OUTER JOIN MusicVideoMetadata MVM on A.MusicVideoMetadataId = MVM.Id
WHERE A.Id IS NULL AND AM.Id IS NULL AND EM.Id IS NULL AND SM.Id IS NULL
AND S.Id IS NULL AND MM.Id IS NULL AND MVM.Id IS NULL")
.Map(result => result.ToList());
public async Task<Unit> Delete(List<Artwork> artwork)
{
IEnumerable<List<int>> chunks = Chunk(artwork.Map(a => a.Id), 100);
foreach (List<int> chunk in chunks)
{
await _dbConnection.ExecuteAsync(
"DELETE FROM Artwork WHERE Id IN @Ids",
new { Ids = chunk });
}
return Unit.Default;
}
private static IEnumerable<List<T>> Chunk<T>(IEnumerable<T> collection, int size)
{
var count = 0;
var chunk = new List<T>(size);
foreach (T element in collection)
{
if (count++ == size)
{
yield return chunk;
chunk = new List<T>(size);
count = 1;
}
chunk.Add(element);
}
yield return chunk;
}
}
}

5
ErsatzTV/Services/SchedulerService.cs

@ -5,6 +5,7 @@ using System.Threading; @@ -5,6 +5,7 @@ using System.Threading;
using System.Threading.Channels;
using System.Threading.Tasks;
using ErsatzTV.Application;
using ErsatzTV.Application.Maintenance.Commands;
using ErsatzTV.Application.MediaSources.Commands;
using ErsatzTV.Application.Playouts.Commands;
using ErsatzTV.Application.Plex.Commands;
@ -58,6 +59,7 @@ namespace ErsatzTV.Services @@ -58,6 +59,7 @@ namespace ErsatzTV.Services
{
try
{
await DeleteOrphanedArtwork(cancellationToken);
await RebuildSearchIndex(cancellationToken);
await BuildPlayouts(cancellationToken);
await ScanLocalMediaSources(cancellationToken);
@ -124,5 +126,8 @@ namespace ErsatzTV.Services @@ -124,5 +126,8 @@ namespace ErsatzTV.Services
private ValueTask RebuildSearchIndex(CancellationToken cancellationToken) =>
_workerChannel.WriteAsync(new RebuildSearchIndex(), cancellationToken);
private ValueTask DeleteOrphanedArtwork(CancellationToken cancellationToken) =>
_workerChannel.WriteAsync(new DeleteOrphanedArtwork(), cancellationToken);
}
}

5
ErsatzTV/Services/WorkerService.cs

@ -3,6 +3,7 @@ using System.Threading; @@ -3,6 +3,7 @@ using System.Threading;
using System.Threading.Channels;
using System.Threading.Tasks;
using ErsatzTV.Application;
using ErsatzTV.Application.Maintenance.Commands;
using ErsatzTV.Application.MediaSources.Commands;
using ErsatzTV.Application.Playouts.Commands;
using ErsatzTV.Application.Search.Commands;
@ -72,6 +73,10 @@ namespace ErsatzTV.Services @@ -72,6 +73,10 @@ namespace ErsatzTV.Services
case RebuildSearchIndex rebuildSearchIndex:
await mediator.Send(rebuildSearchIndex, cancellationToken);
break;
case DeleteOrphanedArtwork deleteOrphanedArtwork:
_logger.LogInformation("Deleting orphaned artwork from the database");
await mediator.Send(deleteOrphanedArtwork, cancellationToken);
break;
}
}
catch (Exception ex)

1
ErsatzTV/Startup.cs

@ -214,6 +214,7 @@ namespace ErsatzTV @@ -214,6 +214,7 @@ namespace ErsatzTV
services.AddScoped<IMusicVideoRepository, MusicVideoRepository>();
services.AddScoped<ILibraryRepository, LibraryRepository>();
services.AddScoped<IMetadataRepository, MetadataRepository>();
services.AddScoped<IArtworkRepository, ArtworkRepository>();
services.AddScoped<IFFmpegLocator, FFmpegLocator>();
services.AddScoped<ILocalMetadataProvider, LocalMetadataProvider>();
services.AddScoped<IFallbackMetadataProvider, FallbackMetadataProvider>();

Loading…
Cancel
Save