* flag local movies as file not found * show warning icon on cards * unflag movie that is found during scan * skip missing files when building playouts * add state to search index * add file not found health check * link to search from file not found health check * support flagging other media kinds as file not found * continue to schedule missing items * support episode files not found * wip trash page * fix trash url * trash page is functional * update changelog * fix changelog merge
76 lines
3.0 KiB
C#
76 lines
3.0 KiB
C#
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Threading.Tasks;
|
|
using ErsatzTV.Core.Domain;
|
|
using ErsatzTV.Core.Extensions;
|
|
using ErsatzTV.Core.Health;
|
|
using ErsatzTV.Core.Health.Checks;
|
|
using ErsatzTV.Infrastructure.Data;
|
|
using Microsoft.EntityFrameworkCore;
|
|
|
|
namespace ErsatzTV.Infrastructure.Health.Checks;
|
|
|
|
public class FileNotFoundHealthCheck : BaseHealthCheck, IFileNotFoundHealthCheck
|
|
{
|
|
private readonly IDbContextFactory<TvContext> _dbContextFactory;
|
|
|
|
public FileNotFoundHealthCheck(IDbContextFactory<TvContext> dbContextFactory) =>
|
|
_dbContextFactory = dbContextFactory;
|
|
|
|
protected override string Title => "File Not Found";
|
|
|
|
public async Task<HealthCheckResult> Check()
|
|
{
|
|
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
|
|
|
|
List<Episode> episodes = await dbContext.Episodes
|
|
.Filter(e => e.State == MediaItemState.FileNotFound)
|
|
.Include(e => e.MediaVersions)
|
|
.ThenInclude(mv => mv.MediaFiles)
|
|
.ToListAsync();
|
|
|
|
List<Movie> movies = await dbContext.Movies
|
|
.Filter(m => m.State == MediaItemState.FileNotFound)
|
|
.Include(m => m.MediaVersions)
|
|
.ThenInclude(mv => mv.MediaFiles)
|
|
.ToListAsync();
|
|
|
|
List<MusicVideo> musicVideos = await dbContext.MusicVideos
|
|
.Filter(mv => mv.State == MediaItemState.FileNotFound)
|
|
.Include(mv => mv.MediaVersions)
|
|
.ThenInclude(mv => mv.MediaFiles)
|
|
.ToListAsync();
|
|
|
|
List<OtherVideo> otherVideos = await dbContext.OtherVideos
|
|
.Filter(ov => ov.State == MediaItemState.FileNotFound)
|
|
.Include(ov => ov.MediaVersions)
|
|
.ThenInclude(mv => mv.MediaFiles)
|
|
.ToListAsync();
|
|
|
|
List<Song> songs = await dbContext.Songs
|
|
.Filter(s => s.State == MediaItemState.FileNotFound)
|
|
.Include(s => s.MediaVersions)
|
|
.ThenInclude(mv => mv.MediaFiles)
|
|
.ToListAsync();
|
|
|
|
var all = movies.Map(m => m.MediaVersions.Head().MediaFiles.Head().Path)
|
|
.Append(episodes.Map(e => e.MediaVersions.Head().MediaFiles.Head().Path))
|
|
.Append(musicVideos.Map(mv => mv.GetHeadVersion().MediaFiles.Head().Path))
|
|
.Append(otherVideos.Map(ov => ov.GetHeadVersion().MediaFiles.Head().Path))
|
|
.Append(songs.Map(s => s.GetHeadVersion().MediaFiles.Head().Path))
|
|
.ToList();
|
|
|
|
if (all.Any())
|
|
{
|
|
var paths = all.Take(5).ToList();
|
|
|
|
var files = string.Join(", ", paths);
|
|
|
|
return WarningResult(
|
|
$"There are {all.Count} files that do not exist on disk, including the following: {files}",
|
|
$"/search?query=state%3AFileNotFound");
|
|
}
|
|
|
|
return OkResult();
|
|
}
|
|
} |