Browse Source

fix seeking into extracted text subtitles (#2326)

pull/2327/head
Jason Dove 12 months ago committed by GitHub
parent
commit
330195d5e3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 3
      CHANGELOG.md
  2. 69
      ErsatzTV.Application/Subtitles/Queries/GetSubtitlePathByIdHandler.cs
  3. 10
      ErsatzTV.Core/FFmpeg/FFmpegLibraryProcessService.cs

3
CHANGELOG.md

@ -74,6 +74,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- Fix bug where multiple Plex servers would mix their episodes - Fix bug where multiple Plex servers would mix their episodes
- Fix incorrect media item counts after removing paths from local libraries - Fix incorrect media item counts after removing paths from local libraries
- Fix song playback in playback troubleshooting - Fix song playback in playback troubleshooting
- Fix seeking into extracted text subtitles
### Changed ### Changed
- Allow multiple watermarks in playback troubleshooting - Allow multiple watermarks in playback troubleshooting
@ -2719,4 +2720,4 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
[0.0.5-prealpha]: https://github.com/ErsatzTV/ErsatzTV/compare/v0.0.4-prealpha...v0.0.5-prealpha [0.0.5-prealpha]: https://github.com/ErsatzTV/ErsatzTV/compare/v0.0.4-prealpha...v0.0.5-prealpha
[0.0.4-prealpha]: https://github.com/ErsatzTV/ErsatzTV/compare/v0.0.3-prealpha...v0.0.4-prealpha [0.0.4-prealpha]: https://github.com/ErsatzTV/ErsatzTV/compare/v0.0.3-prealpha...v0.0.4-prealpha
[0.0.3-prealpha]: https://github.com/ErsatzTV/ErsatzTV/compare/v0.0.1-prealpha...v0.0.3-prealpha [0.0.3-prealpha]: https://github.com/ErsatzTV/ErsatzTV/compare/v0.0.1-prealpha...v0.0.3-prealpha
[0.0.1-prealpha]: https://github.com/ErsatzTV/ErsatzTV/releases/tag/v0.0.1-prealpha [0.0.1-prealpha]: https://github.com/ErsatzTV/ErsatzTV/releases/tag/v0.0.1-prealpha

69
ErsatzTV.Application/Subtitles/Queries/GetSubtitlePathByIdHandler.cs

@ -8,43 +8,48 @@ using Microsoft.EntityFrameworkCore;
namespace ErsatzTV.Application.Subtitles.Queries; namespace ErsatzTV.Application.Subtitles.Queries;
public class GetSubtitlePathByIdHandler : IRequestHandler<GetSubtitlePathById, Either<BaseError, string>> public class GetSubtitlePathByIdHandler(IDbContextFactory<TvContext> dbContextFactory)
: IRequestHandler<GetSubtitlePathById, Either<BaseError, string>>
{ {
private readonly IDbContextFactory<TvContext> _dbContextFactory;
public GetSubtitlePathByIdHandler(IDbContextFactory<TvContext> dbContextFactory) =>
_dbContextFactory = dbContextFactory;
public async Task<Either<BaseError, string>> Handle( public async Task<Either<BaseError, string>> Handle(
GetSubtitlePathById request, GetSubtitlePathById request,
CancellationToken cancellationToken) CancellationToken cancellationToken)
{ {
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync(cancellationToken); await using TvContext dbContext = await dbContextFactory.CreateDbContextAsync(cancellationToken);
Option<Subtitle> maybeSubtitle = await dbContext.Subtitles Option<Subtitle> maybeSubtitle = await dbContext.Subtitles
.AsNoTracking()
.SelectOneAsync(s => s.Id, s => s.Id == request.Id); .SelectOneAsync(s => s.Id, s => s.Id == request.Id);
foreach (string plexUrl in await GetPlexUrl(request, dbContext, maybeSubtitle)) foreach (var subtitle in maybeSubtitle)
{ {
return plexUrl; if (subtitle is { SubtitleKind: SubtitleKind.Embedded, IsExtracted: true })
} {
return Path.Combine(FileSystemLayout.SubtitleCacheFolder, subtitle.Path);
}
foreach (string jellyfinUrl in await GetJellyfinUrl(request, dbContext, maybeSubtitle)) foreach (string plexUrl in await GetPlexUrl(request.Id, dbContext, maybeSubtitle))
{ {
return jellyfinUrl; return plexUrl;
} }
foreach (string embyUrl in await GetEmbyUrl(request, dbContext, maybeSubtitle)) foreach (string jellyfinUrl in await GetJellyfinUrl(request.Id, dbContext, maybeSubtitle))
{ {
return embyUrl; return jellyfinUrl;
}
foreach (string embyUrl in await GetEmbyUrl(request.Id, dbContext, maybeSubtitle))
{
return embyUrl;
}
return subtitle.Path;
} }
return maybeSubtitle return BaseError.New($"Unable to locate subtitle with id {request.Id}");
.Map(s => s.Path)
.ToEither(BaseError.New($"Unable to locate subtitle with id {request.Id}"));
} }
private static async Task<Option<string>> GetPlexUrl( protected static async Task<Option<string>> GetPlexUrl(
GetSubtitlePathById request, int subtitleId,
TvContext dbContext, TvContext dbContext,
Option<Subtitle> maybeSubtitle) Option<Subtitle> maybeSubtitle)
{ {
@ -57,7 +62,7 @@ public class GetSubtitlePathByIdHandler : IRequestHandler<GetSubtitlePathById, E
inner join EpisodeMetadata EM on EM.EpisodeId = MI.Id inner join EpisodeMetadata EM on EM.EpisodeId = MI.Id
inner join Subtitle S on EM.Id = S.EpisodeMetadataId inner join Subtitle S on EM.Id = S.EpisodeMetadataId
where S.Id = @SubtitleId", where S.Id = @SubtitleId",
new { SubtitleId = request.Id }) new { SubtitleId = subtitleId })
.Map(Optional); .Map(Optional);
// check for plex movie // check for plex movie
@ -71,7 +76,7 @@ public class GetSubtitlePathByIdHandler : IRequestHandler<GetSubtitlePathById, E
inner join MovieMetadata MM on MM.MovieId = MI.Id inner join MovieMetadata MM on MM.MovieId = MI.Id
inner join Subtitle S on MM.Id = S.MovieMetadataId inner join Subtitle S on MM.Id = S.MovieMetadataId
where S.Id = @SubtitleId", where S.Id = @SubtitleId",
new { SubtitleId = request.Id }) new { SubtitleId = subtitleId })
.Map(Optional); .Map(Optional);
} }
@ -86,8 +91,8 @@ public class GetSubtitlePathByIdHandler : IRequestHandler<GetSubtitlePathById, E
return Option<string>.None; return Option<string>.None;
} }
private static async Task<Option<string>> GetJellyfinUrl( protected static async Task<Option<string>> GetJellyfinUrl(
GetSubtitlePathById request, int subtitleId,
TvContext dbContext, TvContext dbContext,
Option<Subtitle> maybeSubtitle) Option<Subtitle> maybeSubtitle)
{ {
@ -97,7 +102,7 @@ public class GetSubtitlePathByIdHandler : IRequestHandler<GetSubtitlePathById, E
inner join EpisodeMetadata EM on EM.EpisodeId = JE.Id inner join EpisodeMetadata EM on EM.EpisodeId = JE.Id
inner join Subtitle S on EM.Id = S.EpisodeMetadataId inner join Subtitle S on EM.Id = S.EpisodeMetadataId
where S.Id = @SubtitleId", where S.Id = @SubtitleId",
new { SubtitleId = request.Id }) new { SubtitleId = subtitleId })
.Map(Optional); .Map(Optional);
// check for jellyfin movie // check for jellyfin movie
@ -108,7 +113,7 @@ public class GetSubtitlePathByIdHandler : IRequestHandler<GetSubtitlePathById, E
inner join MovieMetadata MM on MM.MovieId = JM.Id inner join MovieMetadata MM on MM.MovieId = JM.Id
inner join Subtitle S on MM.Id = S.MovieMetadataId inner join Subtitle S on MM.Id = S.MovieMetadataId
where S.Id = @SubtitleId", where S.Id = @SubtitleId",
new { SubtitleId = request.Id }) new { SubtitleId = subtitleId })
.Map(Optional); .Map(Optional);
} }
@ -127,8 +132,8 @@ public class GetSubtitlePathByIdHandler : IRequestHandler<GetSubtitlePathById, E
return Option<string>.None; return Option<string>.None;
} }
private static async Task<Option<string>> GetEmbyUrl( protected static async Task<Option<string>> GetEmbyUrl(
GetSubtitlePathById request, int subtitleId,
TvContext dbContext, TvContext dbContext,
Option<Subtitle> maybeSubtitle) Option<Subtitle> maybeSubtitle)
{ {
@ -138,7 +143,7 @@ public class GetSubtitlePathByIdHandler : IRequestHandler<GetSubtitlePathById, E
inner join EpisodeMetadata EM on EM.EpisodeId = EE.Id inner join EpisodeMetadata EM on EM.EpisodeId = EE.Id
inner join Subtitle S on EM.Id = S.EpisodeMetadataId inner join Subtitle S on EM.Id = S.EpisodeMetadataId
where S.Id = @SubtitleId", where S.Id = @SubtitleId",
new { SubtitleId = request.Id }) new { SubtitleId = subtitleId })
.Map(Optional); .Map(Optional);
// check for emby movie // check for emby movie
@ -149,7 +154,7 @@ public class GetSubtitlePathByIdHandler : IRequestHandler<GetSubtitlePathById, E
inner join MovieMetadata MM on MM.MovieId = EM.Id inner join MovieMetadata MM on MM.MovieId = EM.Id
inner join Subtitle S on MM.Id = S.MovieMetadataId inner join Subtitle S on MM.Id = S.MovieMetadataId
where S.Id = @SubtitleId", where S.Id = @SubtitleId",
new { SubtitleId = request.Id }) new { SubtitleId = subtitleId })
.Map(Optional); .Map(Optional);
} }

10
ErsatzTV.Core/FFmpeg/FFmpegLibraryProcessService.cs

@ -149,7 +149,8 @@ public class FFmpegLibraryProcessService : IFFmpegProcessService
foreach (Subtitle subtitle in maybeSubtitle) foreach (Subtitle subtitle in maybeSubtitle)
{ {
if (subtitle.SubtitleKind == SubtitleKind.Sidecar) if (subtitle.SubtitleKind == SubtitleKind.Sidecar || subtitle is
{ SubtitleKind: SubtitleKind.Embedded, IsImage: false, IsExtracted: true })
{ {
// proxy to avoid dealing with escaping // proxy to avoid dealing with escaping
subtitle.Path = $"http://localhost:{Settings.StreamingPort}/media/subtitle/{subtitle.Id}"; subtitle.Path = $"http://localhost:{Settings.StreamingPort}/media/subtitle/{subtitle.Id}";
@ -276,12 +277,7 @@ public class FFmpegLibraryProcessService : IFFmpegProcessService
subtitle.Codec, subtitle.Codec,
StreamKind.Video); StreamKind.Video);
string path = subtitle.IsImage switch string path = subtitle.IsImage ? videoPath : subtitle.Path;
{
true => videoPath,
false when subtitle.SubtitleKind == SubtitleKind.Sidecar => subtitle.Path,
_ => Path.Combine(FileSystemLayout.SubtitleCacheFolder, subtitle.Path)
};
SubtitleMethod method = SubtitleMethod.Burn; SubtitleMethod method = SubtitleMethod.Burn;
if (channel.StreamingMode == StreamingMode.HttpLiveStreamingDirect) if (channel.StreamingMode == StreamingMode.HttpLiveStreamingDirect)

Loading…
Cancel
Save