Browse Source

plex scanner improvement (#1193)

* fix crash with some plex multi-episode files

* comments cleanup
pull/1195/head
Jason Dove 2 years ago committed by GitHub
parent
commit
4d84fc242b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      CHANGELOG.md
  2. 8
      ErsatzTV.Infrastructure/Data/Repositories/PlexTelevisionRepository.cs
  3. 37
      ErsatzTV.Infrastructure/Plex/PlexServerApiClient.cs
  4. 27
      ErsatzTV.Scanner/Core/Metadata/MediaServerMovieLibraryScanner.cs
  5. 2
      ErsatzTV.Scanner/Core/Plex/PlexMovieLibraryScanner.cs

1
CHANGELOG.md

@ -14,6 +14,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). @@ -14,6 +14,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- Improve VAAPI encoder capability detection on newer hardware
- Fix trash page to properly display episodes with missing metadata or titles
- Fix playback of content with yuv444p10le pixel format
- Fix case where some multi-episode files from Plex would crash the scanner
### Changed
- Upgrade all docker images and windows builds to ffmpeg 6.0

8
ErsatzTV.Infrastructure/Data/Repositories/PlexTelevisionRepository.cs

@ -486,10 +486,6 @@ public class PlexTelevisionRepository : IPlexTelevisionRepository @@ -486,10 +486,6 @@ public class PlexTelevisionRepository : IPlexTelevisionRepository
version.Name = incomingVersion.Name;
version.DateAdded = incomingVersion.DateAdded;
await dbContext.Connection.ExecuteAsync(
@"UPDATE MediaVersion SET Name = @Name, DateAdded = @DateAdded WHERE Id = @Id",
new { version.Name, version.DateAdded, version.Id });
// media file
MediaFile file = version.MediaFiles.Head();
MediaFile incomingFile = incomingVersion.MediaFiles.Head();
@ -502,6 +498,10 @@ public class PlexTelevisionRepository : IPlexTelevisionRepository @@ -502,6 +498,10 @@ public class PlexTelevisionRepository : IPlexTelevisionRepository
file.Path = incomingFile.Path;
await dbContext.Connection.ExecuteAsync(
@"UPDATE MediaVersion SET Name = @Name, DateAdded = @DateAdded WHERE Id = @Id",
new { version.Name, version.DateAdded, version.Id });
await dbContext.Connection.ExecuteAsync(
@"UPDATE MediaFile SET Path = @Path WHERE Id = @Id",
new { file.Path, file.Id });

37
ErsatzTV.Infrastructure/Plex/PlexServerApiClient.cs

@ -78,7 +78,7 @@ public class PlexServerApiClient : IPlexServerApiClient @@ -78,7 +78,7 @@ public class PlexServerApiClient : IPlexServerApiClient
{
return jsonService
.GetLibrarySectionContents(library.Key, skip, pageSize, token.AuthToken)
.Map(r => r.MediaContainer.Metadata.Filter(m => m.Media.Count > 0 && m.Media[0].Part.Count > 0))
.Map(r => r.MediaContainer.Metadata.Filter(m => m.Media.Count > 0 && m.Media.Any(media => media.Part.Count > 0)))
.Map(list => list.Map(metadata => ProjectToMovie(metadata, library.MediaSourceId)));
}
@ -179,13 +179,14 @@ public class PlexServerApiClient : IPlexServerApiClient @@ -179,13 +179,14 @@ public class PlexServerApiClient : IPlexServerApiClient
Task<IEnumerable<PlexEpisode>> GetItems(IPlexServerApi xmlService, IPlexServerApi _, int skip, int pageSize)
{
return xmlService.GetSeasonChildren(seasonMetadataKey, skip, pageSize, token.AuthToken)
.Map(r => r.Metadata.Filter(m => m.Media.Count > 0 && m.Media[0].Part.Count > 0))
.Map(list => list.Bind(metadata => ProjectToEpisodes(metadata, library.MediaSourceId)));
.Map(r => r.Metadata.Filter(m => m.Media.Count > 0 && m.Media.Any(media => media.Part.Count > 0)))
.Map(list => list.Map(metadata => ProjectToEpisode(metadata, library.MediaSourceId)));
}
return GetPagedLibraryContents(connection, CountItems, GetItems);
}
// this shouldn't be called anymore
public async Task<Either<BaseError, MovieMetadata>> GetMovieMetadata(
PlexLibrary library,
string key,
@ -197,7 +198,7 @@ public class PlexServerApiClient : IPlexServerApiClient @@ -197,7 +198,7 @@ public class PlexServerApiClient : IPlexServerApiClient
IPlexServerApi service = XmlServiceFor(connection.Uri);
return await service.GetVideoMetadata(key, token.AuthToken)
.Map(Optional)
.Map(r => r.Filter(m => m.Metadata.Media.Count > 0 && m.Metadata.Media[0].Part.Count > 0))
.Map(r => r.Filter(m => m.Metadata.Media.Count > 0 && m.Metadata.Media.Any(media => media.Part.Count > 0)))
.MapT(response => ProjectToMovieMetadata(response.Metadata, library.MediaSourceId))
.Map(o => o.ToEither<BaseError>("Unable to locate metadata"));
}
@ -239,7 +240,7 @@ public class PlexServerApiClient : IPlexServerApiClient @@ -239,7 +240,7 @@ public class PlexServerApiClient : IPlexServerApiClient
Option<PlexXmlVideoMetadataResponseContainer> maybeResponse = await service
.GetVideoMetadata(key, token.AuthToken)
.Map(Optional)
.Map(r => r.Filter(m => m.Metadata.Media.Count > 0 && m.Metadata.Media[0].Part.Count > 0));
.Map(r => r.Filter(m => m.Metadata.Media.Count > 0 && m.Metadata.Media.Any(media => media.Part.Count > 0)));
return maybeResponse.Match(
response =>
{
@ -268,7 +269,7 @@ public class PlexServerApiClient : IPlexServerApiClient @@ -268,7 +269,7 @@ public class PlexServerApiClient : IPlexServerApiClient
Option<PlexXmlVideoMetadataResponseContainer> maybeResponse = await service
.GetVideoMetadata(key, token.AuthToken)
.Map(Optional)
.Map(r => r.Filter(m => m.Metadata.Media.Count > 0 && m.Metadata.Media[0].Part.Count > 0));
.Map(r => r.Filter(m => m.Metadata.Media.Count > 0 && m.Metadata.Media.Any(media => media.Part.Count > 0)));
return maybeResponse.Match(
response =>
{
@ -401,7 +402,10 @@ public class PlexServerApiClient : IPlexServerApiClient @@ -401,7 +402,10 @@ public class PlexServerApiClient : IPlexServerApiClient
private PlexMovie ProjectToMovie(PlexMetadataResponse response, int mediaSourceId)
{
PlexMediaResponse<PlexPartResponse> media = response.Media.Head();
PlexMediaResponse<PlexPartResponse> media = response.Media
.Filter(media => media.Part.Any())
.MaxBy(media => media.Id);
PlexPartResponse part = media.Part.Head();
DateTime dateAdded = DateTimeOffset.FromUnixTimeSeconds(response.AddedAt).DateTime;
DateTime lastWriteTime = DateTimeOffset.FromUnixTimeSeconds(response.UpdatedAt).DateTime;
@ -541,7 +545,10 @@ public class PlexServerApiClient : IPlexServerApiClient @@ -541,7 +545,10 @@ public class PlexServerApiClient : IPlexServerApiClient
private Option<MediaVersion> ProjectToMediaVersion(PlexXmlMetadataResponse response)
{
PlexMediaResponse<PlexXmlPartResponse> media = response.Media.Head();
PlexMediaResponse<PlexXmlPartResponse> media = response.Media
.Filter(media => media.Part.Any())
.MaxBy(media => media.Id);
List<PlexStreamResponse> streams = media.Part.Head().Stream;
DateTime dateUpdated = DateTimeOffset.FromUnixTimeSeconds(response.UpdatedAt).DateTime;
Option<PlexStreamResponse> maybeVideoStream = streams.Find(s => s.StreamType == 1);
@ -814,13 +821,12 @@ public class PlexServerApiClient : IPlexServerApiClient @@ -814,13 +821,12 @@ public class PlexServerApiClient : IPlexServerApiClient
return season;
}
private IEnumerable<PlexEpisode> ProjectToEpisodes(PlexXmlMetadataResponse response, int mediaSourceId)
private PlexEpisode ProjectToEpisode(PlexXmlMetadataResponse response, int mediaSourceId)
{
var result = new List<PlexEpisode>();
PlexMediaResponse<PlexXmlPartResponse> media = response.Media
.Filter(media => media.Part.Any())
.MaxBy(media => media.Id);
// TODO: actually use all media records
foreach (PlexMediaResponse<PlexXmlPartResponse> media in response.Media.HeadOrNone())
{
PlexXmlPartResponse part = media.Part.Head();
DateTime dateAdded = DateTimeOffset.FromUnixTimeSeconds(response.AddedAt).DateTime;
DateTime lastWriteTime = DateTimeOffset.FromUnixTimeSeconds(response.UpdatedAt).DateTime;
@ -856,10 +862,7 @@ public class PlexServerApiClient : IPlexServerApiClient @@ -856,10 +862,7 @@ public class PlexServerApiClient : IPlexServerApiClient
TraktListItems = new List<TraktListItem>()
};
result.Add(episode);
}
return result;
return episode;
}
private EpisodeMetadata ProjectToEpisodeMetadata(PlexMetadataResponse response, int mediaSourceId)

27
ErsatzTV.Scanner/Core/Metadata/MediaServerMovieLibraryScanner.cs

@ -449,32 +449,6 @@ public abstract class MediaServerMovieLibraryScanner<TConnectionParameters, TLib @@ -449,32 +449,6 @@ public abstract class MediaServerMovieLibraryScanner<TConnectionParameters, TLib
if (deepScan || result.IsAdded || MediaServerEtag(existing) != MediaServerEtag(incoming) ||
existing.MediaVersions.Head().Streams.Count == 0)
{
// if (maybeMediaVersion.IsNone && _localFileSystem.FileExists(result.LocalPath))
// {
// _logger.LogDebug("Refreshing {Attribute} for {Path}", "Statistics", result.LocalPath);
// Either<BaseError, bool> refreshResult =
// await _localStatisticsProvider.RefreshStatistics(
// ffmpegPath,
// ffprobePath,
// existing,
// result.LocalPath);
//
// foreach (BaseError error in refreshResult.LeftToSeq())
// {
// _logger.LogWarning(
// "Unable to refresh {Attribute} for media item {Path}. Error: {Error}",
// "Statistics",
// result.LocalPath,
// error.Value);
// }
//
// foreach (bool _ in refreshResult.RightToSeq())
// {
// result.IsUpdated = true;
// }
// }
// else
// {
if (maybeMediaVersion.IsNone)
{
maybeMediaVersion = await GetMediaServerStatistics(
@ -491,7 +465,6 @@ public abstract class MediaServerMovieLibraryScanner<TConnectionParameters, TLib @@ -491,7 +465,6 @@ public abstract class MediaServerMovieLibraryScanner<TConnectionParameters, TLib
result.IsUpdated = true;
}
}
// }
}
return result;

2
ErsatzTV.Scanner/Core/Plex/PlexMovieLibraryScanner.cs

@ -107,6 +107,7 @@ public class PlexMovieLibraryScanner : @@ -107,6 +107,7 @@ public class PlexMovieLibraryScanner :
connectionParameters.Connection,
connectionParameters.Token);
// this shouldn't be called anymore
protected override async Task<Option<MovieMetadata>> GetFullMetadata(
PlexConnectionParameters connectionParameters,
PlexLibrary library,
@ -133,6 +134,7 @@ public class PlexMovieLibraryScanner : @@ -133,6 +134,7 @@ public class PlexMovieLibraryScanner :
return None;
}
// this shouldn't be called anymore
protected override async Task<Option<MediaVersion>> GetMediaServerStatistics(
PlexConnectionParameters connectionParameters,
PlexLibrary library,

Loading…
Cancel
Save