bug fixes and logging (#786)
This commit is contained in:
@@ -9,6 +9,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
|||||||
- Fix processing local movie fallback metadata
|
- Fix processing local movie fallback metadata
|
||||||
- Fix search edge case where very recently added items (hours) would not be returned by relative date queries
|
- Fix search edge case where very recently added items (hours) would not be returned by relative date queries
|
||||||
- Fix search index validation on startup; improper validation was causing a rebuild with every startup
|
- Fix search index validation on startup; improper validation was causing a rebuild with every startup
|
||||||
|
- Block library scanning until search index has been recreated/upgraded
|
||||||
|
- Fix occasional erroneous log messages when HLS channel playback times out because all clients have left
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
- Add `show_genre` and `show_tag` to search index for seasons and episodes
|
- Add `show_genre` and `show_tag` to search index for seasons and episodes
|
||||||
|
|||||||
@@ -276,7 +276,7 @@ public class HlsSessionWorker : IHlsSessionWorker
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (TaskCanceledException)
|
catch (Exception ex) when (ex is TaskCanceledException or OperationCanceledException)
|
||||||
{
|
{
|
||||||
_logger.LogInformation("Terminating HLS process for channel {Channel}", _channelNumber);
|
_logger.LogInformation("Terminating HLS process for channel {Channel}", _channelNumber);
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
+11
-1
@@ -14,6 +14,7 @@ using ErsatzTV.Core.Scheduling;
|
|||||||
using ErsatzTV.Infrastructure.Data;
|
using ErsatzTV.Infrastructure.Data;
|
||||||
using ErsatzTV.Infrastructure.Extensions;
|
using ErsatzTV.Infrastructure.Extensions;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
namespace ErsatzTV.Application.Streaming;
|
namespace ErsatzTV.Application.Streaming;
|
||||||
|
|
||||||
@@ -24,6 +25,7 @@ public class GetPlayoutItemProcessByChannelNumberHandler : FFmpegProcessHandler<
|
|||||||
private readonly IFFmpegProcessService _ffmpegProcessService;
|
private readonly IFFmpegProcessService _ffmpegProcessService;
|
||||||
private readonly IJellyfinPathReplacementService _jellyfinPathReplacementService;
|
private readonly IJellyfinPathReplacementService _jellyfinPathReplacementService;
|
||||||
private readonly ILocalFileSystem _localFileSystem;
|
private readonly ILocalFileSystem _localFileSystem;
|
||||||
|
private readonly ILogger<GetPlayoutItemProcessByChannelNumberHandler> _logger;
|
||||||
private readonly IMediaCollectionRepository _mediaCollectionRepository;
|
private readonly IMediaCollectionRepository _mediaCollectionRepository;
|
||||||
private readonly IPlexPathReplacementService _plexPathReplacementService;
|
private readonly IPlexPathReplacementService _plexPathReplacementService;
|
||||||
private readonly ISongVideoGenerator _songVideoGenerator;
|
private readonly ISongVideoGenerator _songVideoGenerator;
|
||||||
@@ -39,7 +41,8 @@ public class GetPlayoutItemProcessByChannelNumberHandler : FFmpegProcessHandler<
|
|||||||
IMediaCollectionRepository mediaCollectionRepository,
|
IMediaCollectionRepository mediaCollectionRepository,
|
||||||
ITelevisionRepository televisionRepository,
|
ITelevisionRepository televisionRepository,
|
||||||
IArtistRepository artistRepository,
|
IArtistRepository artistRepository,
|
||||||
ISongVideoGenerator songVideoGenerator)
|
ISongVideoGenerator songVideoGenerator,
|
||||||
|
ILogger<GetPlayoutItemProcessByChannelNumberHandler> logger)
|
||||||
: base(dbContextFactory)
|
: base(dbContextFactory)
|
||||||
{
|
{
|
||||||
_ffmpegProcessService = ffmpegProcessService;
|
_ffmpegProcessService = ffmpegProcessService;
|
||||||
@@ -51,6 +54,7 @@ public class GetPlayoutItemProcessByChannelNumberHandler : FFmpegProcessHandler<
|
|||||||
_televisionRepository = televisionRepository;
|
_televisionRepository = televisionRepository;
|
||||||
_artistRepository = artistRepository;
|
_artistRepository = artistRepository;
|
||||||
_songVideoGenerator = songVideoGenerator;
|
_songVideoGenerator = songVideoGenerator;
|
||||||
|
_logger = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override async Task<Either<BaseError, PlayoutItemProcessModel>> GetProcess(
|
protected override async Task<Either<BaseError, PlayoutItemProcessModel>> GetProcess(
|
||||||
@@ -201,6 +205,12 @@ public class GetPlayoutItemProcessByChannelNumberHandler : FFmpegProcessHandler<
|
|||||||
|
|
||||||
DateTimeOffset finish = maybeDuration.Match(d => now.Add(d), () => now);
|
DateTimeOffset finish = maybeDuration.Match(d => now.Add(d), () => now);
|
||||||
|
|
||||||
|
_logger.LogWarning(
|
||||||
|
"Error locating playout item {@Error}. Will display error from {Start} to {Finish}",
|
||||||
|
error,
|
||||||
|
now,
|
||||||
|
finish);
|
||||||
|
|
||||||
switch (error)
|
switch (error)
|
||||||
{
|
{
|
||||||
case UnableToLocatePlayoutItem:
|
case UnableToLocatePlayoutItem:
|
||||||
|
|||||||
@@ -155,7 +155,7 @@ public class ExtractEmbeddedSubtitlesHandler : IRequestHandler<ExtractEmbeddedSu
|
|||||||
|
|
||||||
return Unit.Default;
|
return Unit.Default;
|
||||||
}
|
}
|
||||||
catch (TaskCanceledException)
|
catch (Exception ex) when (ex is TaskCanceledException or OperationCanceledException)
|
||||||
{
|
{
|
||||||
return Unit.Default;
|
return Unit.Default;
|
||||||
}
|
}
|
||||||
@@ -210,7 +210,7 @@ public class ExtractEmbeddedSubtitlesHandler : IRequestHandler<ExtractEmbeddedSu
|
|||||||
.ToListAsync(cancellationToken);
|
.ToListAsync(cancellationToken);
|
||||||
result.AddRange(otherVideoIds);
|
result.AddRange(otherVideoIds);
|
||||||
}
|
}
|
||||||
catch (TaskCanceledException)
|
catch (Exception ex) when (ex is TaskCanceledException or OperationCanceledException)
|
||||||
{
|
{
|
||||||
// do nothing
|
// do nothing
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -121,22 +121,19 @@ public class ImageCache : IImageCache
|
|||||||
string targetFile = GetPathForImage(fileName, artworkKind, Option<int>.None);
|
string targetFile = GetPathForImage(fileName, artworkKind, Option<int>.None);
|
||||||
|
|
||||||
// ReSharper disable once ConvertToUsingDeclaration
|
// ReSharper disable once ConvertToUsingDeclaration
|
||||||
using (FileStream fs = File.OpenRead(targetFile))
|
using (var image = await Image.LoadAsync<Rgba32>(targetFile))
|
||||||
{
|
{
|
||||||
using (var image = await Image.LoadAsync<Rgba32>(fs))
|
// resize before calculating blur hash; it doesn't need giant images
|
||||||
|
if (image.Height > 200)
|
||||||
{
|
{
|
||||||
// resize before calculating blur hash; it doesn't need giant images
|
image.Mutate(i => i.Resize(0, 200));
|
||||||
if (image.Height > 200)
|
|
||||||
{
|
|
||||||
image.Mutate(i => i.Resize(0, 200));
|
|
||||||
}
|
|
||||||
else if (image.Width > 200)
|
|
||||||
{
|
|
||||||
image.Mutate(i => i.Resize(200, 0));
|
|
||||||
}
|
|
||||||
|
|
||||||
return Blurhasher.Encode(image, x, y);
|
|
||||||
}
|
}
|
||||||
|
else if (image.Width > 200)
|
||||||
|
{
|
||||||
|
image.Mutate(i => i.Resize(200, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
return Blurhasher.Encode(image, x, y);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -151,6 +148,7 @@ public class ImageCache : IImageCache
|
|||||||
_localFileSystem.EnsureFolderExists(folder);
|
_localFileSystem.EnsureFolderExists(folder);
|
||||||
|
|
||||||
// ReSharper disable once ConvertToUsingDeclaration
|
// ReSharper disable once ConvertToUsingDeclaration
|
||||||
|
// ReSharper disable once UseAwaitUsing
|
||||||
using (FileStream fs = File.OpenWrite(targetFile))
|
using (FileStream fs = File.OpenWrite(targetFile))
|
||||||
{
|
{
|
||||||
using (Image<Rgb24> image = Blurhasher.Decode(blurHash, targetSize.Width, targetSize.Height))
|
using (Image<Rgb24> image = Blurhasher.Decode(blurHash, targetSize.Width, targetSize.Height))
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
using ErsatzTV.Application.Search;
|
||||||
|
using MediatR;
|
||||||
|
|
||||||
|
namespace ErsatzTV.Services.RunOnce;
|
||||||
|
|
||||||
|
public class RebuildSearchIndexService : IHostedService
|
||||||
|
{
|
||||||
|
private readonly IServiceScopeFactory _serviceScopeFactory;
|
||||||
|
|
||||||
|
public RebuildSearchIndexService(IServiceScopeFactory serviceScopeFactory) =>
|
||||||
|
_serviceScopeFactory = serviceScopeFactory;
|
||||||
|
|
||||||
|
public async Task StartAsync(CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
using IServiceScope scope = _serviceScopeFactory.CreateScope();
|
||||||
|
IMediator mediator = scope.ServiceProvider.GetRequiredService<IMediator>();
|
||||||
|
await mediator.Send(new RebuildSearchIndex(), cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask;
|
||||||
|
}
|
||||||
@@ -8,7 +8,6 @@ using ErsatzTV.Application.MediaCollections;
|
|||||||
using ErsatzTV.Application.MediaSources;
|
using ErsatzTV.Application.MediaSources;
|
||||||
using ErsatzTV.Application.Playouts;
|
using ErsatzTV.Application.Playouts;
|
||||||
using ErsatzTV.Application.Plex;
|
using ErsatzTV.Application.Plex;
|
||||||
using ErsatzTV.Application.Search;
|
|
||||||
using ErsatzTV.Core.Domain;
|
using ErsatzTV.Core.Domain;
|
||||||
using ErsatzTV.Core.Interfaces.Locking;
|
using ErsatzTV.Core.Interfaces.Locking;
|
||||||
using ErsatzTV.Core.Scheduling;
|
using ErsatzTV.Core.Scheduling;
|
||||||
@@ -93,7 +92,6 @@ public class SchedulerService : BackgroundService
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
await DeleteOrphanedArtwork(cancellationToken);
|
await DeleteOrphanedArtwork(cancellationToken);
|
||||||
await RebuildSearchIndex(cancellationToken);
|
|
||||||
await BuildPlayouts(cancellationToken);
|
await BuildPlayouts(cancellationToken);
|
||||||
await ScanLocalMediaSources(cancellationToken);
|
await ScanLocalMediaSources(cancellationToken);
|
||||||
await ScanPlexMediaSources(cancellationToken);
|
await ScanPlexMediaSources(cancellationToken);
|
||||||
@@ -266,9 +264,6 @@ public class SchedulerService : BackgroundService
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private ValueTask RebuildSearchIndex(CancellationToken cancellationToken) =>
|
|
||||||
_workerChannel.WriteAsync(new RebuildSearchIndex(), cancellationToken);
|
|
||||||
|
|
||||||
private ValueTask DeleteOrphanedArtwork(CancellationToken cancellationToken) =>
|
private ValueTask DeleteOrphanedArtwork(CancellationToken cancellationToken) =>
|
||||||
_workerChannel.WriteAsync(new DeleteOrphanedArtwork(), cancellationToken);
|
_workerChannel.WriteAsync(new DeleteOrphanedArtwork(), cancellationToken);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -418,11 +418,15 @@ public class Startup
|
|||||||
|
|
||||||
// services.AddTransient(typeof(IRequestHandler<,>), typeof(GetRecentLogEntriesHandler<>));
|
// services.AddTransient(typeof(IRequestHandler<,>), typeof(GetRecentLogEntriesHandler<>));
|
||||||
|
|
||||||
|
// run-once/blocking startup services
|
||||||
services.AddHostedService<EndpointValidatorService>();
|
services.AddHostedService<EndpointValidatorService>();
|
||||||
services.AddHostedService<DatabaseMigratorService>();
|
services.AddHostedService<DatabaseMigratorService>();
|
||||||
services.AddHostedService<CacheCleanerService>();
|
services.AddHostedService<CacheCleanerService>();
|
||||||
services.AddHostedService<ResourceExtractorService>();
|
services.AddHostedService<ResourceExtractorService>();
|
||||||
services.AddHostedService<PlatformSettingsService>();
|
services.AddHostedService<PlatformSettingsService>();
|
||||||
|
services.AddHostedService<RebuildSearchIndexService>();
|
||||||
|
|
||||||
|
// background services
|
||||||
services.AddHostedService<EmbyService>();
|
services.AddHostedService<EmbyService>();
|
||||||
services.AddHostedService<JellyfinService>();
|
services.AddHostedService<JellyfinService>();
|
||||||
services.AddHostedService<PlexService>();
|
services.AddHostedService<PlexService>();
|
||||||
|
|||||||
Reference in New Issue
Block a user