Browse Source

sync subtitles from media server scanners (#744)

pull/746/head
Jason Dove 4 years ago committed by GitHub
parent
commit
d755d0ae29
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 50
      ErsatzTV.Core/Emby/EmbyMovieLibraryScanner.cs
  2. 50
      ErsatzTV.Core/Emby/EmbyTelevisionLibraryScanner.cs
  3. 50
      ErsatzTV.Core/Jellyfin/JellyfinMovieLibraryScanner.cs
  4. 50
      ErsatzTV.Core/Jellyfin/JellyfinTelevisionLibraryScanner.cs
  5. 46
      ErsatzTV.Core/Plex/PlexMovieLibraryScanner.cs
  6. 43
      ErsatzTV.Core/Plex/PlexTelevisionLibraryScanner.cs

50
ErsatzTV.Core/Emby/EmbyMovieLibraryScanner.cs

@ -1,4 +1,5 @@ @@ -1,4 +1,5 @@
using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Extensions;
using ErsatzTV.Core.Interfaces.Emby;
using ErsatzTV.Core.Interfaces.Metadata;
using ErsatzTV.Core.Interfaces.Repositories;
@ -17,6 +18,7 @@ public class EmbyMovieLibraryScanner : IEmbyMovieLibraryScanner @@ -17,6 +18,7 @@ public class EmbyMovieLibraryScanner : IEmbyMovieLibraryScanner
private readonly ILocalStatisticsProvider _localStatisticsProvider;
private readonly ILogger<EmbyMovieLibraryScanner> _logger;
private readonly IMediaSourceRepository _mediaSourceRepository;
private readonly IMetadataRepository _metadataRepository;
private readonly IMediator _mediator;
private readonly IMovieRepository _movieRepository;
private readonly IEmbyPathReplacementService _pathReplacementService;
@ -31,6 +33,7 @@ public class EmbyMovieLibraryScanner : IEmbyMovieLibraryScanner @@ -31,6 +33,7 @@ public class EmbyMovieLibraryScanner : IEmbyMovieLibraryScanner
ISearchRepository searchRepository,
IEmbyPathReplacementService pathReplacementService,
IMediaSourceRepository mediaSourceRepository,
IMetadataRepository metadataRepository,
ILocalFileSystem localFileSystem,
ILocalStatisticsProvider localStatisticsProvider,
ILogger<EmbyMovieLibraryScanner> logger)
@ -42,6 +45,7 @@ public class EmbyMovieLibraryScanner : IEmbyMovieLibraryScanner @@ -42,6 +45,7 @@ public class EmbyMovieLibraryScanner : IEmbyMovieLibraryScanner
_searchRepository = searchRepository;
_pathReplacementService = pathReplacementService;
_mediaSourceRepository = mediaSourceRepository;
_metadataRepository = metadataRepository;
_localFileSystem = localFileSystem;
_localStatisticsProvider = localStatisticsProvider;
_logger = logger;
@ -179,6 +183,11 @@ public class EmbyMovieLibraryScanner : IEmbyMovieLibraryScanner @@ -179,6 +183,11 @@ public class EmbyMovieLibraryScanner : IEmbyMovieLibraryScanner
incomingMovie,
localPath);
if (refreshResult.Map(t => t).IfLeft(false))
{
refreshResult = await UpdateSubtitles(incomingMovie);
}
await refreshResult.Match(
async _ =>
{
@ -229,4 +238,45 @@ public class EmbyMovieLibraryScanner : IEmbyMovieLibraryScanner @@ -229,4 +238,45 @@ public class EmbyMovieLibraryScanner : IEmbyMovieLibraryScanner
_searchIndex.Commit();
return Unit.Default;
}
private async Task<Either<BaseError, bool>> UpdateSubtitles(EmbyMovie movie)
{
try
{
foreach (MovieMetadata metadata in movie.MovieMetadata)
{
MediaVersion version = movie.GetHeadVersion();
var subtitleStreams = version.Streams
.Filter(s => s.MediaStreamKind == MediaStreamKind.Subtitle)
.ToList();
var subtitles = new List<Subtitle>();
foreach (MediaStream stream in subtitleStreams)
{
var subtitle = new Subtitle
{
Codec = stream.Codec,
Default = stream.Default,
Forced = stream.Forced,
Language = stream.Language,
StreamIndex = stream.Index,
SubtitleKind = SubtitleKind.Embedded,
DateAdded = DateTime.UtcNow,
DateUpdated = DateTime.UtcNow
};
subtitles.Add(subtitle);
}
return await _metadataRepository.UpdateSubtitles(metadata, subtitles);
}
}
catch (Exception ex)
{
return BaseError.New(ex.ToString());
}
return false;
}
}

50
ErsatzTV.Core/Emby/EmbyTelevisionLibraryScanner.cs

@ -1,4 +1,5 @@ @@ -1,4 +1,5 @@
using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Extensions;
using ErsatzTV.Core.Interfaces.Emby;
using ErsatzTV.Core.Interfaces.Metadata;
using ErsatzTV.Core.Interfaces.Repositories;
@ -19,6 +20,7 @@ public class EmbyTelevisionLibraryScanner : IEmbyTelevisionLibraryScanner @@ -19,6 +20,7 @@ public class EmbyTelevisionLibraryScanner : IEmbyTelevisionLibraryScanner
private readonly IMediaSourceRepository _mediaSourceRepository;
private readonly IMediator _mediator;
private readonly IEmbyPathReplacementService _pathReplacementService;
private readonly IMetadataRepository _metadataRepository;
private readonly ISearchIndex _searchIndex;
private readonly ISearchRepository _searchRepository;
private readonly IEmbyTelevisionRepository _televisionRepository;
@ -30,6 +32,7 @@ public class EmbyTelevisionLibraryScanner : IEmbyTelevisionLibraryScanner @@ -30,6 +32,7 @@ public class EmbyTelevisionLibraryScanner : IEmbyTelevisionLibraryScanner
ISearchIndex searchIndex,
ISearchRepository searchRepository,
IEmbyPathReplacementService pathReplacementService,
IMetadataRepository metadataRepository,
ILocalFileSystem localFileSystem,
ILocalStatisticsProvider localStatisticsProvider,
IMediator mediator,
@ -41,6 +44,7 @@ public class EmbyTelevisionLibraryScanner : IEmbyTelevisionLibraryScanner @@ -41,6 +44,7 @@ public class EmbyTelevisionLibraryScanner : IEmbyTelevisionLibraryScanner
_searchIndex = searchIndex;
_searchRepository = searchRepository;
_pathReplacementService = pathReplacementService;
_metadataRepository = metadataRepository;
_localFileSystem = localFileSystem;
_localStatisticsProvider = localStatisticsProvider;
_mediator = mediator;
@ -426,6 +430,11 @@ public class EmbyTelevisionLibraryScanner : IEmbyTelevisionLibraryScanner @@ -426,6 +430,11 @@ public class EmbyTelevisionLibraryScanner : IEmbyTelevisionLibraryScanner
incomingEpisode,
localPath);
if (refreshResult.Map(t => t).IfLeft(false))
{
refreshResult = await UpdateSubtitles(incomingEpisode);
}
refreshResult.Match(
_ => { },
error => _logger.LogWarning(
@ -436,4 +445,45 @@ public class EmbyTelevisionLibraryScanner : IEmbyTelevisionLibraryScanner @@ -436,4 +445,45 @@ public class EmbyTelevisionLibraryScanner : IEmbyTelevisionLibraryScanner
}
}
}
private async Task<Either<BaseError, bool>> UpdateSubtitles(EmbyEpisode episode)
{
try
{
foreach (EpisodeMetadata metadata in episode.EpisodeMetadata)
{
MediaVersion version = episode.GetHeadVersion();
var subtitleStreams = version.Streams
.Filter(s => s.MediaStreamKind == MediaStreamKind.Subtitle)
.ToList();
var subtitles = new List<Subtitle>();
foreach (MediaStream stream in subtitleStreams)
{
var subtitle = new Subtitle
{
Codec = stream.Codec,
Default = stream.Default,
Forced = stream.Forced,
Language = stream.Language,
StreamIndex = stream.Index,
SubtitleKind = SubtitleKind.Embedded,
DateAdded = DateTime.UtcNow,
DateUpdated = DateTime.UtcNow
};
subtitles.Add(subtitle);
}
return await _metadataRepository.UpdateSubtitles(metadata, subtitles);
}
}
catch (Exception ex)
{
return BaseError.New(ex.ToString());
}
return false;
}
}

50
ErsatzTV.Core/Jellyfin/JellyfinMovieLibraryScanner.cs

@ -1,4 +1,5 @@ @@ -1,4 +1,5 @@
using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Extensions;
using ErsatzTV.Core.Interfaces.Jellyfin;
using ErsatzTV.Core.Interfaces.Metadata;
using ErsatzTV.Core.Interfaces.Repositories;
@ -17,6 +18,7 @@ public class JellyfinMovieLibraryScanner : IJellyfinMovieLibraryScanner @@ -17,6 +18,7 @@ public class JellyfinMovieLibraryScanner : IJellyfinMovieLibraryScanner
private readonly ILocalStatisticsProvider _localStatisticsProvider;
private readonly ILogger<JellyfinMovieLibraryScanner> _logger;
private readonly IMediaSourceRepository _mediaSourceRepository;
private readonly IMetadataRepository _metadataRepository;
private readonly IMediator _mediator;
private readonly IMovieRepository _movieRepository;
private readonly IJellyfinPathReplacementService _pathReplacementService;
@ -31,6 +33,7 @@ public class JellyfinMovieLibraryScanner : IJellyfinMovieLibraryScanner @@ -31,6 +33,7 @@ public class JellyfinMovieLibraryScanner : IJellyfinMovieLibraryScanner
ISearchRepository searchRepository,
IJellyfinPathReplacementService pathReplacementService,
IMediaSourceRepository mediaSourceRepository,
IMetadataRepository metadataRepository,
ILocalFileSystem localFileSystem,
ILocalStatisticsProvider localStatisticsProvider,
ILogger<JellyfinMovieLibraryScanner> logger)
@ -42,6 +45,7 @@ public class JellyfinMovieLibraryScanner : IJellyfinMovieLibraryScanner @@ -42,6 +45,7 @@ public class JellyfinMovieLibraryScanner : IJellyfinMovieLibraryScanner
_searchRepository = searchRepository;
_pathReplacementService = pathReplacementService;
_mediaSourceRepository = mediaSourceRepository;
_metadataRepository = metadataRepository;
_localFileSystem = localFileSystem;
_localStatisticsProvider = localStatisticsProvider;
_logger = logger;
@ -179,6 +183,11 @@ public class JellyfinMovieLibraryScanner : IJellyfinMovieLibraryScanner @@ -179,6 +183,11 @@ public class JellyfinMovieLibraryScanner : IJellyfinMovieLibraryScanner
incomingMovie,
localPath);
if (refreshResult.Map(t => t).IfLeft(false))
{
refreshResult = await UpdateSubtitles(incomingMovie);
}
await refreshResult.Match(
async _ =>
{
@ -229,4 +238,45 @@ public class JellyfinMovieLibraryScanner : IJellyfinMovieLibraryScanner @@ -229,4 +238,45 @@ public class JellyfinMovieLibraryScanner : IJellyfinMovieLibraryScanner
_searchIndex.Commit();
return Unit.Default;
}
private async Task<Either<BaseError, bool>> UpdateSubtitles(JellyfinMovie movie)
{
try
{
foreach (MovieMetadata metadata in movie.MovieMetadata)
{
MediaVersion version = movie.GetHeadVersion();
var subtitleStreams = version.Streams
.Filter(s => s.MediaStreamKind == MediaStreamKind.Subtitle)
.ToList();
var subtitles = new List<Subtitle>();
foreach (MediaStream stream in subtitleStreams)
{
var subtitle = new Subtitle
{
Codec = stream.Codec,
Default = stream.Default,
Forced = stream.Forced,
Language = stream.Language,
StreamIndex = stream.Index,
SubtitleKind = SubtitleKind.Embedded,
DateAdded = DateTime.UtcNow,
DateUpdated = DateTime.UtcNow
};
subtitles.Add(subtitle);
}
return await _metadataRepository.UpdateSubtitles(metadata, subtitles);
}
}
catch (Exception ex)
{
return BaseError.New(ex.ToString());
}
return false;
}
}

50
ErsatzTV.Core/Jellyfin/JellyfinTelevisionLibraryScanner.cs

@ -1,4 +1,5 @@ @@ -1,4 +1,5 @@
using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Extensions;
using ErsatzTV.Core.Interfaces.Jellyfin;
using ErsatzTV.Core.Interfaces.Metadata;
using ErsatzTV.Core.Interfaces.Repositories;
@ -19,6 +20,7 @@ public class JellyfinTelevisionLibraryScanner : IJellyfinTelevisionLibraryScanne @@ -19,6 +20,7 @@ public class JellyfinTelevisionLibraryScanner : IJellyfinTelevisionLibraryScanne
private readonly IMediaSourceRepository _mediaSourceRepository;
private readonly IMediator _mediator;
private readonly IJellyfinPathReplacementService _pathReplacementService;
private readonly IMetadataRepository _metadataRepository;
private readonly ISearchIndex _searchIndex;
private readonly ISearchRepository _searchRepository;
private readonly IJellyfinTelevisionRepository _televisionRepository;
@ -30,6 +32,7 @@ public class JellyfinTelevisionLibraryScanner : IJellyfinTelevisionLibraryScanne @@ -30,6 +32,7 @@ public class JellyfinTelevisionLibraryScanner : IJellyfinTelevisionLibraryScanne
ISearchIndex searchIndex,
ISearchRepository searchRepository,
IJellyfinPathReplacementService pathReplacementService,
IMetadataRepository metadataRepository,
ILocalFileSystem localFileSystem,
ILocalStatisticsProvider localStatisticsProvider,
IMediator mediator,
@ -41,6 +44,7 @@ public class JellyfinTelevisionLibraryScanner : IJellyfinTelevisionLibraryScanne @@ -41,6 +44,7 @@ public class JellyfinTelevisionLibraryScanner : IJellyfinTelevisionLibraryScanne
_searchIndex = searchIndex;
_searchRepository = searchRepository;
_pathReplacementService = pathReplacementService;
_metadataRepository = metadataRepository;
_localFileSystem = localFileSystem;
_localStatisticsProvider = localStatisticsProvider;
_mediator = mediator;
@ -428,6 +432,11 @@ public class JellyfinTelevisionLibraryScanner : IJellyfinTelevisionLibraryScanne @@ -428,6 +432,11 @@ public class JellyfinTelevisionLibraryScanner : IJellyfinTelevisionLibraryScanne
incomingEpisode,
localPath);
if (refreshResult.Map(t => t).IfLeft(false))
{
refreshResult = await UpdateSubtitles(incomingEpisode);
}
refreshResult.Match(
_ => { },
error => _logger.LogWarning(
@ -438,4 +447,45 @@ public class JellyfinTelevisionLibraryScanner : IJellyfinTelevisionLibraryScanne @@ -438,4 +447,45 @@ public class JellyfinTelevisionLibraryScanner : IJellyfinTelevisionLibraryScanne
}
}
}
private async Task<Either<BaseError, bool>> UpdateSubtitles(JellyfinEpisode episode)
{
try
{
foreach (EpisodeMetadata metadata in episode.EpisodeMetadata)
{
MediaVersion version = episode.GetHeadVersion();
var subtitleStreams = version.Streams
.Filter(s => s.MediaStreamKind == MediaStreamKind.Subtitle)
.ToList();
var subtitles = new List<Subtitle>();
foreach (MediaStream stream in subtitleStreams)
{
var subtitle = new Subtitle
{
Codec = stream.Codec,
Default = stream.Default,
Forced = stream.Forced,
Language = stream.Language,
StreamIndex = stream.Index,
SubtitleKind = SubtitleKind.Embedded,
DateAdded = DateTime.UtcNow,
DateUpdated = DateTime.UtcNow
};
subtitles.Add(subtitle);
}
return await _metadataRepository.UpdateSubtitles(metadata, subtitles);
}
}
catch (Exception ex)
{
return BaseError.New(ex.ToString());
}
return false;
}
}

46
ErsatzTV.Core/Plex/PlexMovieLibraryScanner.cs

@ -1,4 +1,5 @@ @@ -1,4 +1,5 @@
using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Extensions;
using ErsatzTV.Core.Interfaces.Metadata;
using ErsatzTV.Core.Interfaces.Plex;
using ErsatzTV.Core.Interfaces.Repositories;
@ -97,6 +98,7 @@ public class PlexMovieLibraryScanner : PlexLibraryScanner, IPlexMovieLibraryScan @@ -97,6 +98,7 @@ public class PlexMovieLibraryScanner : PlexLibraryScanner, IPlexMovieLibraryScan
.BindT(
existing => UpdateStatistics(pathReplacements, existing, incoming, ffmpegPath, ffprobePath))
.BindT(existing => UpdateMetadata(existing, incoming, library, connection, token))
.BindT(UpdateSubtitles)
.BindT(existing => UpdateArtwork(existing, incoming));
await maybeMovie.Match(
@ -406,6 +408,50 @@ public class PlexMovieLibraryScanner : PlexLibraryScanner, IPlexMovieLibraryScan @@ -406,6 +408,50 @@ public class PlexMovieLibraryScanner : PlexLibraryScanner, IPlexMovieLibraryScan
return result;
}
private async Task<Either<BaseError, MediaItemScanResult<PlexMovie>>> UpdateSubtitles(
MediaItemScanResult<PlexMovie> result)
{
try
{
Movie movie = result.Item;
foreach (MovieMetadata metadata in movie.MovieMetadata)
{
MediaVersion version = movie.GetHeadVersion();
var subtitleStreams = version.Streams
.Filter(s => s.MediaStreamKind == MediaStreamKind.Subtitle)
.ToList();
var subtitles = new List<Subtitle>();
foreach (MediaStream stream in subtitleStreams)
{
var subtitle = new Subtitle
{
Codec = stream.Codec,
Default = stream.Default,
Forced = stream.Forced,
Language = stream.Language,
StreamIndex = stream.Index,
SubtitleKind = SubtitleKind.Embedded,
DateAdded = DateTime.UtcNow,
DateUpdated = DateTime.UtcNow
};
subtitles.Add(subtitle);
}
await _metadataRepository.UpdateSubtitles(metadata, subtitles);
}
return result;
}
catch (Exception ex)
{
return BaseError.New(ex.ToString());
}
}
private async Task<Either<BaseError, MediaItemScanResult<PlexMovie>>> UpdateArtwork(
MediaItemScanResult<PlexMovie> result,
PlexMovie incoming)

43
ErsatzTV.Core/Plex/PlexTelevisionLibraryScanner.cs

@ -1,4 +1,5 @@ @@ -1,4 +1,5 @@
using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Extensions;
using ErsatzTV.Core.Interfaces.Metadata;
using ErsatzTV.Core.Interfaces.Plex;
using ErsatzTV.Core.Interfaces.Repositories;
@ -444,6 +445,7 @@ public class PlexTelevisionLibraryScanner : PlexLibraryScanner, IPlexTelevisionL @@ -444,6 +445,7 @@ public class PlexTelevisionLibraryScanner : PlexLibraryScanner, IPlexTelevisionL
token,
ffmpegPath,
ffprobePath))
.BindT(UpdateSubtitles)
.BindT(existing => UpdateArtwork(existing, incoming));
await maybeEpisode.Match(
@ -616,6 +618,47 @@ public class PlexTelevisionLibraryScanner : PlexLibraryScanner, IPlexTelevisionL @@ -616,6 +618,47 @@ public class PlexTelevisionLibraryScanner : PlexLibraryScanner, IPlexTelevisionL
return Right<BaseError, PlexEpisode>(existing);
}
private async Task<Either<BaseError, PlexEpisode>> UpdateSubtitles(PlexEpisode episode)
{
try
{
foreach (EpisodeMetadata metadata in episode.EpisodeMetadata)
{
MediaVersion version = episode.GetHeadVersion();
var subtitleStreams = version.Streams
.Filter(s => s.MediaStreamKind == MediaStreamKind.Subtitle)
.ToList();
var subtitles = new List<Subtitle>();
foreach (MediaStream stream in subtitleStreams)
{
var subtitle = new Subtitle
{
Codec = stream.Codec,
Default = stream.Default,
Forced = stream.Forced,
Language = stream.Language,
StreamIndex = stream.Index,
SubtitleKind = SubtitleKind.Embedded,
DateAdded = DateTime.UtcNow,
DateUpdated = DateTime.UtcNow
};
subtitles.Add(subtitle);
}
await _metadataRepository.UpdateSubtitles(metadata, subtitles);
}
return episode;
}
catch (Exception ex)
{
return BaseError.New(ex.ToString());
}
}
private async Task<Either<BaseError, PlexEpisode>> UpdateArtwork(PlexEpisode existing, PlexEpisode incoming)
{
foreach (EpisodeMetadata incomingMetadata in incoming.EpisodeMetadata)

Loading…
Cancel
Save