public void ActShouldNotCallIfFirstWhenEitherHasASecondValue() { var called = false; var target = new Either<int, string>("1"); target.Act(_ => called = true, _ => { }); Assert.That(!called); }
public void ActShouldCallIfFirstWhenEitherHasAFirstValue() { var called = false; var target = new Either<int, string>(1); target.Act(_ => called = true, _ => { }); Assert.That(called); }
public void HandleShouldNotCallIfSecondWhenEitherHasAFirstValue() { var called = false; var target = new Either<int, string>(1); target.Handle(_ => true, _ => called = true); Assert.That(!called); }
public void ActOneArgumentShouldNotCallIfSecondWhenEitherHasAFirstValue() { var called = false; var target = new Either<int, string>(1); target.Act(ifSecond: _ => { called = true; }); Assert.That(!called); }
public RiakPutOptions() { ReturnBody = true; W = new Either<uint, string>(RiakConstants.QuorumOptions.Default); Dw = new Either<uint, string>(RiakConstants.QuorumOptions.Default); Pw = new Either<uint, string>(RiakConstants.QuorumOptions.Default); }
public void DifferentFirstValuesShouldNotBeEqual() { const uint value0 = 0x6a09e667; const uint value1 = 0xbb67ae85; var target0 = new Either<uint, string>(value0); var target1 = new Either<uint, string>(value1); Assert.That(target0, Is.Not.EqualTo(target1)); }
public void DifferentSecondValuesShouldNotBeEqual() { const string value0 = "6a09e667"; const string value1 = "bb67ae85"; var target0 = new Either<uint, string>(value0); var target1 = new Either<uint, string>(value1); Assert.That(target0, Is.Not.EqualTo(target1)); }
public RiakDeleteOptions() { Rw = new Either<uint, string>(RiakConstants.QuorumOptions.Default); R = new Either<uint, string>(RiakConstants.QuorumOptions.Default); W = new Either<uint, string>(RiakConstants.QuorumOptions.Default); Pr = new Either<uint, string>(RiakConstants.QuorumOptions.Default); Pw = new Either<uint, string>(RiakConstants.QuorumOptions.Default); Dw = new Either<uint, string>(RiakConstants.QuorumOptions.Default); }
public void HandleShouldPassThroughFirstValueToIfFirst() { const uint value = 0x6a09e667; var target = new Either<uint, string>(value); target.Handle(f => { Assert.That(f, Is.EqualTo(value)); return true; }, _ => true); }
private Stream Search( Either<Type> doType, Stream data, Either<Type> specType, string limit, string offset, string order, string count) { int? intLimit, intOffset; Utility.ParseLimitOffset(limit, offset, out intLimit, out intOffset); var ordDict = Utility.ParseOrder(order); var spec = Utility.ParseObject(Serialization, specType, data, true, Locator); if (doType.IsFailure || specType.IsFailure || spec.IsFailure) return doType.Error ?? specType.Error ?? spec.Error; var additionalCommands = EmptyCommands; if (intLimit != null && (count == "yes" || ThreadContext.Request.GetHeader("IncludeCount") == "yes")) { additionalCommands = new[] { new AdditionalCommand { Argument = new CountDomainObject.Argument<object> { Name = doType.Result.FullName, SpecificationName = specType.Result != null ? specType.Result.FullName : null, Specification = spec.Result }, CommandType = typeof(CountDomainObject), ToHeader = "Total-Results" } }; } var accept = (ThreadContext.Request.Accept ?? "application/json").ToLowerInvariant(); return Converter.PassThrough<SearchDomainObject, SearchDomainObject.Argument<object>>( new SearchDomainObject.Argument<object> { Name = doType.Result.FullName, SpecificationName = specType.Result != null ? specType.Result.FullName : null, Specification = spec.Result, Limit = intLimit, Offset = intOffset, Order = ordDict }, accept, additionalCommands); }
public void SwappedEitherValuesShouldNotBeEqual() { const uint value = 0x6a09e667; var target0 = new Either<uint, string>(value); var target1 = new Either<string, uint>(value); Assert.That(target0, Is.Not.EqualTo(target1)); }
public RiakBucketProperties SetWVal(uint value) { return WriteQuorum(value, v => WVal = v); }
/// <summary> /// Creates a new <see cref="PropertyNode"/> from a property, value and the object they apply to. /// </summary> /// <param name="parentOrId">The object or ID of the object the property applies to.</param> /// <param name="property">The name of the property.</param> /// <param name="value">The value of the property.</param> /// <returns>A node containing the specified property.</returns> public static PropertyNode Property(Either <IPrtgObject, int> parentOrId, Either <ObjectProperty, string> property, object value) => Property(new PropertyValuePair(parentOrId, property, value));
private async Task <Either <BaseError, MediaItemScanResult <PlexEpisode> > > UpdateStatistics( List <PlexPathReplacement> pathReplacements, MediaItemScanResult <PlexEpisode> result, PlexEpisode incoming, PlexLibrary library, PlexConnection connection, PlexServerAuthToken token, string ffmpegPath, string ffprobePath, bool deepScan) { PlexEpisode existing = result.Item; MediaVersion existingVersion = existing.MediaVersions.Head(); MediaVersion incomingVersion = incoming.MediaVersions.Head(); if (result.IsAdded || existing.Etag != incoming.Etag || deepScan || existingVersion.Streams.Count == 0) { foreach (MediaFile incomingFile in incomingVersion.MediaFiles.HeadOrNone()) { foreach (MediaFile existingFile in existingVersion.MediaFiles.HeadOrNone()) { if (incomingFile.Path != existingFile.Path) { _logger.LogDebug( "Plex episode has moved from {OldPath} to {NewPath}", existingFile.Path, incomingFile.Path); existingFile.Path = incomingFile.Path; await _televisionRepository.UpdatePath(existingFile.Id, incomingFile.Path); } } } Either <BaseError, bool> refreshResult = true; string localPath = _plexPathReplacementService.GetReplacementPlexPath( pathReplacements, incoming.MediaVersions.Head().MediaFiles.Head().Path, false); if ((existing.Etag != incoming.Etag || existingVersion.Streams.Count == 0) && _localFileSystem.FileExists(localPath)) { _logger.LogDebug("Refreshing {Attribute} for {Path}", "Statistics", localPath); refreshResult = await _localStatisticsProvider.RefreshStatistics( ffmpegPath, ffprobePath, existing, localPath); } foreach (BaseError error in refreshResult.LeftToSeq()) { _logger.LogWarning( "Unable to refresh {Attribute} for media item {Path}. Error: {Error}", "Statistics", localPath, error.Value); } foreach (var _ in refreshResult.RightToSeq()) { foreach (MediaItem updated in await _searchRepository.GetItemToIndex(incoming.Id)) { await _searchIndex.UpdateItems( _searchRepository, new List <MediaItem> { updated }); } Either <BaseError, Tuple <EpisodeMetadata, MediaVersion> > maybeStatistics = await _plexServerApiClient.GetEpisodeMetadataAndStatistics( library, incoming.Key.Split("/").Last(), connection, token); foreach (Tuple <EpisodeMetadata, MediaVersion> tuple in maybeStatistics.RightToSeq()) { (EpisodeMetadata incomingMetadata, MediaVersion mediaVersion) = tuple; Option <EpisodeMetadata> maybeExisting = existing.EpisodeMetadata .Find(em => em.EpisodeNumber == incomingMetadata.EpisodeNumber); foreach (EpisodeMetadata existingMetadata in maybeExisting) { foreach (MetadataGuid guid in existingMetadata.Guids .Filter(g => incomingMetadata.Guids.All(g2 => g2.Guid != g.Guid)) .ToList()) { existingMetadata.Guids.Remove(guid); await _metadataRepository.RemoveGuid(guid); } foreach (MetadataGuid guid in incomingMetadata.Guids .Filter(g => existingMetadata.Guids.All(g2 => g2.Guid != g.Guid)) .ToList()) { existingMetadata.Guids.Add(guid); await _metadataRepository.AddGuid(existingMetadata, guid); } foreach (Tag tag in existingMetadata.Tags .Filter(g => incomingMetadata.Tags.All(g2 => g2.Name != g.Name)) .ToList()) { existingMetadata.Tags.Remove(tag); await _metadataRepository.RemoveTag(tag); } foreach (Tag tag in incomingMetadata.Tags .Filter(g => existingMetadata.Tags.All(g2 => g2.Name != g.Name)) .ToList()) { existingMetadata.Tags.Add(tag); await _televisionRepository.AddTag(existingMetadata, tag); } } existingVersion.SampleAspectRatio = mediaVersion.SampleAspectRatio; existingVersion.VideoScanKind = mediaVersion.VideoScanKind; existingVersion.DateUpdated = mediaVersion.DateUpdated; await _metadataRepository.UpdatePlexStatistics(existingVersion.Id, mediaVersion); } } } return(result); }
public RiakDeleteOptions SetW(uint value) { return WriteQuorum(value, var => W = var); }
private Stream OlapCube( Either<Type> cubeType, string templater, string dimensions, string facts, string order, Either<object> spec, string limit, string offset) { var templaterType = Utility.CheckDomainObject(DomainModel, cubeType, templater); if (templaterType.IsFailure || spec.IsFailure) return templaterType.Error ?? spec.Error; var dimArr = string.IsNullOrEmpty(dimensions) ? new string[0] : dimensions.Split(','); var factArr = string.IsNullOrEmpty(facts) ? new string[0] : facts.Split(','); if (dimArr.Length == 0 && factArr.Length == 0) return Either<object>.BadRequest("At least one dimension or fact must be specified").Error; var ordDict = Utility.ParseOrder(order); int? intLimit, intOffset; Utility.ParseLimitOffset(limit, offset, out intLimit, out intOffset); return Converter.PassThrough<OlapCubeReport, OlapCubeReport.Argument<object>>( new OlapCubeReport.Argument<object> { CubeName = cubeType.Result.FullName, TemplaterName = templater, SpecificationName = null, Specification = spec.Result, Dimensions = dimArr, Facts = factArr, Order = ordDict, Limit = intLimit, Offset = intOffset }); }
private Stream Search( Either<Type> doType, Stream data, Either<Type> specType, string limit, string offset, string order) { int? intLimit, intOffset; Utility.ParseLimitOffset(limit, offset, out intLimit, out intOffset); var ordDict = Utility.ParseOrder(order); var spec = Utility.ParseObject(Serialization, specType, data, true, Locator); if (doType.IsFailure || specType.IsFailure || spec.IsFailure) return doType.Error ?? specType.Error ?? spec.Error; return Converter.PassThrough<SearchDomainObject, SearchDomainObject.Argument<object>>( new SearchDomainObject.Argument<object> { Name = doType.Result.FullName, SpecificationName = specType.Result != null ? specType.Result.FullName : null, Specification = spec.Result, Limit = intLimit, Offset = intOffset, Order = ordDict }); }
public static TResult GetOrThrow <TResult>(this Either <TResult, Exception> either) => either.Match(r => r, e => throw e);
public static Either <ConfigLookupError, A> parseErrorEFor <A>( ConfigPath path, object node, string extraInfo = null ) => Either <ConfigLookupError, A> .Left(parseErrorFor <A>(path, node, extraInfo));
public static Parser <From, Option <A> > opt <From, A>(Parser <From, A> parser) => (path, o) => o == null ? Either <ConfigLookupError, Option <A> > .Right(Option <A> .None) : parser(path, o).mapRight(_ => _.some());
public static void OnError <TResult, TError>(this Either <TResult, TError> either, Action <TError> err) => either.Match(_ => { }, err);
public SimpleUndoPair ClearLocalizationAction(Id <LocalizedText> guid) { Either <LocalizationElement, Null> oldValue = Either.Create(m_data.LocalizationExists(guid), () => m_data.GetLocalized(guid), Null.Func); return(InnerSetLocalizationAction(guid, Null.Func(), oldValue)); }
private SimpleUndoPair InnerSetLocalizationAction(Id <LocalizedText> guid, Either <LocalizationElement, Null> newValue, Either <LocalizationElement, Null> oldValue) { object change = new object(); return(new SimpleUndoPair { Redo = () => { newValue.Do(a => m_data.SetLocalized(guid, a), b => m_data.ClearLocaliation(guid)); m_currentChanges.Add(change); m_file.Change(); }, Undo = () => { oldValue.Do(a => m_data.SetLocalized(guid, a), b => m_data.ClearLocaliation(guid)); m_currentChanges.Remove(change); m_file.Change(); }, }); }
public SimpleUndoPair SetLocalizationAction(Id <LocalizedText> guid, string p) { Either <LocalizationElement, Null> oldValue = Either.Create(m_data.LocalizationExists(guid), () => m_data.GetLocalized(guid), Null.Func); return(InnerSetLocalizationAction(guid, new LocalizationElement(DateTime.Now, p), oldValue)); }
public static Either <L, B> Apply <L, A, B>(this Func <A, B> fab, Either <L, A> fa) => ApplEither <L, A, B> .Inst.Apply(fab, fa);
/// Parser that always succeeds and returns constant. public static Parser <object, A> constantParser <A>(A a) => (path, _) => Either <ConfigLookupError, A> .Right(a);
public void HandleShouldPassThroughIfFirstResult() { var target = new Either<uint, string>(0x6a09e667); const decimal expected = 5m; Assert.That(target.Handle(_ => expected, _ => 0m), Is.EqualTo(expected)); }
/// Parser that always fails and returns constant. public static Parser <object, A> constantErrorParser <A>(ConfigLookupError error) => (path, _) => Either <ConfigLookupError, A> .Left(error);
private Stream Count( string domainObject, Stream data, Either<Type> specType) { var spec = Utility.ParseObject(Serialization, specType, data, true, Locator); if (spec.IsFailure) return spec.Error; return Converter.PassThrough<CountDomainObject, CountDomainObject.Argument<object>>( new CountDomainObject.Argument<object> { Name = domainObject, SpecificationName = specType.Result != null ? specType.Result.FullName : null, Specification = spec.Result }); }
public static Parser <From, Option <A> > opt <From, A>(Parser <From, A> parser) => (path, o) => o == null ? Either <ConfigLookupError, Option <A> > .Right(None._) : parser(path, o).mapRight(Some.a);
public RiakPutOptions SetW(string value) { return WriteQuorum(value, var => W = var); }
void IObserver <Either <Notification <TLeft>, Notification <TRight> > > .OnNext(Either <Notification <TLeft>, Notification <TRight> > value) { value.Switch(left => left.Accept(LeftObserver), right => right.Accept(RightObserver)); }
private async Task <Either <BaseError, Unit> > ScanLibrary( PlexConnection connection, PlexServerAuthToken token, PlexLibrary library, string ffmpegPath, string ffprobePath, bool deepScan, List <PlexShow> showEntries, CancellationToken cancellationToken) { List <PlexItemEtag> existingShows = await _plexTelevisionRepository.GetExistingPlexShows(library); List <PlexPathReplacement> pathReplacements = await _mediaSourceRepository .GetPlexPathReplacements(library.MediaSourceId); foreach (PlexShow incoming in showEntries) { if (cancellationToken.IsCancellationRequested) { return(new ScanCanceled()); } decimal percentCompletion = (decimal)showEntries.IndexOf(incoming) / showEntries.Count; await _mediator.Publish(new LibraryScanProgress(library.Id, percentCompletion), cancellationToken); // TODO: figure out how to rebuild playlists Either <BaseError, MediaItemScanResult <PlexShow> > maybeShow = await _televisionRepository .GetOrAddPlexShow(library, incoming) .BindT(existing => UpdateMetadata(existing, incoming, library, connection, token, deepScan)) .BindT(existing => UpdateArtwork(existing, incoming)); if (maybeShow.IsLeft) { foreach (BaseError error in maybeShow.LeftToSeq()) { _logger.LogWarning( "Error processing plex show at {Key}: {Error}", incoming.Key, error.Value); } continue; } foreach (MediaItemScanResult <PlexShow> result in maybeShow.RightToSeq()) { Either <BaseError, Unit> scanResult = await ScanSeasons( library, pathReplacements, result.Item, connection, token, ffmpegPath, ffprobePath, deepScan, cancellationToken); foreach (ScanCanceled error in scanResult.LeftToSeq().OfType <ScanCanceled>()) { return(error); } await _plexTelevisionRepository.SetPlexEtag(result.Item, incoming.Etag); // TODO: if any seasons are unavailable or not found, flag show as unavailable/not found if (result.IsAdded) { await _searchIndex.AddItems(_searchRepository, new List <MediaItem> { result.Item }); } else if (result.IsUpdated) { await _searchIndex.UpdateItems( _searchRepository, new List <MediaItem> { result.Item }); } } } // trash items that are no longer present on the media server var fileNotFoundKeys = existingShows.Map(m => m.Key).Except(showEntries.Map(m => m.Key)).ToList(); List <int> ids = await _plexTelevisionRepository.FlagFileNotFoundShows(library, fileNotFoundKeys); await _searchIndex.RebuildItems(_searchRepository, ids); await _mediator.Publish(new LibraryScanProgress(library.Id, 0), cancellationToken); return(Unit.Default); }
public static Either <TLeft, TResult> Select <TLeft, TRight, TResult>( this Either <TLeft, TRight> @this, Func <TRight, TResult> func ) => @this.Map(func);
/// <summary> /// Converts a <see cref="Either{L, R}"/> to an <see cref="IActionResult"/>. /// Default right case conversion will convert units to NoContent and all other values to Ok. /// Default left case conversion will convert values to an InternalServerError. /// </summary> /// <typeparam name="L">The left <see cref="Either{L, R}"/> parameter type.</typeparam> /// <typeparam name="R">The right <see cref="Either{L, R}"/> parameter type.</typeparam> /// <param name="this">The <see cref="Either{L, R}"/> to convert to an <see cref="IActionResult"/>.</param> /// <param name="Right">Optionally, a custom conversion for the right case.</param> /// <param name="Left">Optionally, a custom conversion for the left case.</param> /// <returns>An <see cref="IActionResult"/> which can be returned from a controller.</returns> public static IActionResult ToActionResult <L, R>(this Either <L, R> @this, Func <R, IActionResult> Right = null, Func <L, IActionResult> Left = null) => @this.Match(Right: Right ?? GetGenericSuccessResult, Left: Left ?? GetGenericErrorResult);
public static Either <L, S> Select <L, R, S>(this Either <L, R> e, Func <R, S> func) => e.HasLeft() ? (() => e.Left()) : new Either <L, S>(() => func(e.Right()));
public void HandleShouldPassThroughSecondValueToIfSecond() { const string value = "6a09e667"; var target = new Either<uint, string>(value); target.Handle(_ => true, s => { Assert.That(s, Is.EqualTo(value)); return true; }); }
public static bool HasLeft <L, R>(this Either <L, R> e) => e().HasLeft;
public void IdenticalEitherValuesShouldHaveTheSameHashCode() { const uint value = 0x6a09e667; var target0 = new Either<uint, string>(value); var target1 = new Either<uint, string>(value); if (ReferenceEquals(target0, target1)) { Assert.Inconclusive(); } Assert.That(target0.GetHashCode(), Is.EqualTo(target1.GetHashCode())); }
public static bool HasRight <L, R>(this Either <L, R> e) => e().HasRight;
protected override int GetId(Either <Error, int> newObj) { return(newObj.RightContent()); }
public RiakGetOptions() { R = new Either<uint, string>(RiakConstants.QuorumOptions.Default); Pr = new Either<uint, string>(RiakConstants.QuorumOptions.Default); }
public static Either <L, R> Divide <NUM, L, R>(this Either <L, R> x, Either <L, R> y) where NUM : struct, Num <R> => from a in x from b in y select default(NUM).Divide(a, b);
public override void Because() { mbResult1 = Catcher.Catching<NullReferenceException>().ToOption(() => myVariable.Length); mbResult2 = Catcher.Catching<NullReferenceException>().ToEither(() => myVariable.Length); }
public void HandleShouldPassThroughIfSecondResult() { var target = new Either<uint, string>("1"); const decimal expected = 5m; Assert.That(target.Handle(_ => 0m, _ => expected), Is.EqualTo(expected)); }
public override void Because() { joined = eitherEither.JoinRight(); }
private Stream SearchTemplater( string file, string domainObject, Either<object> spec) { if (spec.IsFailure) return spec.Error; var requestPdf = ThreadContext.Request.Accept == "application/pdf"; var result = Converter.PassThrough<TemplaterProcessDocument, TemplaterProcessDocument.Argument<object>>( new TemplaterProcessDocument.Argument<object> { File = Path.GetFileName(file), SearchSources = new[] { new SearchDomainObject.Argument<object> { SpecificationName = null, Specification = spec.Result, Name = domainObject }}, ToPdf = requestPdf }, "application/octet-stream"); ThreadContext.Response.ContentType = requestPdf ? "application/pdf" : "application/octet-stream"; return result; }
public static Either <L, R> Subtract <NUM, L, R>(this Either <L, R> x, Either <L, R> y) where NUM : struct, Num <R> => from a in x from b in y select default(NUM).Subtract(a, b);
private Stream Count(Either<Type> domainType, Either<object> specification) { if (domainType.IsFailure || specification.IsFailure) return domainType.Error ?? specification.Error; return Converter.PassThrough<CountDomainObject, CountDomainObject.Argument<object>>( new CountDomainObject.Argument<object> { Name = domainType.Result.FullName, SpecificationName = null, Specification = specification.Result }); }
private async Task <Either <BaseError, Unit> > ScanSeasons( PlexLibrary library, List <PlexPathReplacement> pathReplacements, PlexShow show, PlexConnection connection, PlexServerAuthToken token, string ffmpegPath, string ffprobePath, bool deepScan, CancellationToken cancellationToken) { List <PlexItemEtag> existingSeasons = await _plexTelevisionRepository.GetExistingPlexSeasons(library, show); Either <BaseError, List <PlexSeason> > entries = await _plexServerApiClient.GetShowSeasons( library, show, connection, token); foreach (BaseError error in entries.LeftToSeq()) { return(error); } var seasonEntries = entries.RightToSeq().Flatten().ToList(); foreach (PlexSeason incoming in seasonEntries) { incoming.ShowId = show.Id; // TODO: figure out how to rebuild playlists Either <BaseError, PlexSeason> maybeSeason = await _televisionRepository .GetOrAddPlexSeason(library, incoming) .BindT(existing => UpdateMetadataAndArtwork(existing, incoming, deepScan)); foreach (BaseError error in maybeSeason.LeftToSeq()) { _logger.LogWarning( "Error processing plex season at {Key}: {Error}", incoming.Key, error.Value); return(error); } foreach (PlexSeason season in maybeSeason.RightToSeq()) { Either <BaseError, Unit> scanResult = await ScanEpisodes( library, pathReplacements, season, connection, token, ffmpegPath, ffprobePath, deepScan, cancellationToken); foreach (ScanCanceled error in scanResult.LeftToSeq().OfType <ScanCanceled>()) { return(error); } await _plexTelevisionRepository.SetPlexEtag(season, incoming.Etag); season.Show = show; // TODO: if any seasons are unavailable or not found, flag show as unavailable/not found await _searchIndex.AddItems(_searchRepository, new List <MediaItem> { season }); } } var fileNotFoundKeys = existingSeasons.Map(m => m.Key).Except(seasonEntries.Map(m => m.Key)).ToList(); List <int> ids = await _plexTelevisionRepository.FlagFileNotFoundSeasons(library, fileNotFoundKeys); await _searchIndex.RebuildItems(_searchRepository, ids); return(Unit.Default); }
private Stream Search( Either<Type> domainType, string limit, string offset, string order, Either<object> specification) { if (domainType.IsFailure || specification.IsFailure) return domainType.Error ?? specification.Error; int? intLimit, intOffset; Utility.ParseLimitOffset(limit, offset, out intLimit, out intOffset); var ordDict = Utility.ParseOrder(order); return Converter.PassThrough<SearchDomainObject, SearchDomainObject.Argument<object>>( new SearchDomainObject.Argument<object> { Name = domainType.Result.FullName, SpecificationName = null, Specification = specification.Result, Limit = intLimit, Offset = intOffset, Order = ordDict }); }
private async Task <Either <BaseError, MediaItemScanResult <PlexShow> > > UpdateMetadata( MediaItemScanResult <PlexShow> result, PlexShow incoming, PlexLibrary library, PlexConnection connection, PlexServerAuthToken token, bool deepScan) { PlexShow existing = result.Item; ShowMetadata existingMetadata = existing.ShowMetadata.Head(); if (result.IsAdded || existing.Etag != incoming.Etag || deepScan) { Either <BaseError, ShowMetadata> maybeMetadata = await _plexServerApiClient.GetShowMetadata( library, incoming.Key.Replace("/children", string.Empty).Split("/").Last(), connection, token); await maybeMetadata.Match( async fullMetadata => { if (existingMetadata.MetadataKind != MetadataKind.External) { existingMetadata.MetadataKind = MetadataKind.External; await _metadataRepository.MarkAsExternal(existingMetadata); } if (existingMetadata.ContentRating != fullMetadata.ContentRating) { existingMetadata.ContentRating = fullMetadata.ContentRating; await _metadataRepository.SetContentRating(existingMetadata, fullMetadata.ContentRating); result.IsUpdated = true; } foreach (Genre genre in existingMetadata.Genres .Filter(g => fullMetadata.Genres.All(g2 => g2.Name != g.Name)) .ToList()) { existingMetadata.Genres.Remove(genre); if (await _metadataRepository.RemoveGenre(genre)) { result.IsUpdated = true; } } foreach (Genre genre in fullMetadata.Genres .Filter(g => existingMetadata.Genres.All(g2 => g2.Name != g.Name)) .ToList()) { existingMetadata.Genres.Add(genre); if (await _televisionRepository.AddGenre(existingMetadata, genre)) { result.IsUpdated = true; } } foreach (Studio studio in existingMetadata.Studios .Filter(s => fullMetadata.Studios.All(s2 => s2.Name != s.Name)) .ToList()) { existingMetadata.Studios.Remove(studio); if (await _metadataRepository.RemoveStudio(studio)) { result.IsUpdated = true; } } foreach (Studio studio in fullMetadata.Studios .Filter(s => existingMetadata.Studios.All(s2 => s2.Name != s.Name)) .ToList()) { existingMetadata.Studios.Add(studio); if (await _televisionRepository.AddStudio(existingMetadata, studio)) { result.IsUpdated = true; } } foreach (Actor actor in existingMetadata.Actors .Filter( a => fullMetadata.Actors.All( a2 => a2.Name != a.Name || a.Artwork == null && a2.Artwork != null)) .ToList()) { existingMetadata.Actors.Remove(actor); if (await _metadataRepository.RemoveActor(actor)) { result.IsUpdated = true; } } foreach (Actor actor in fullMetadata.Actors .Filter(a => existingMetadata.Actors.All(a2 => a2.Name != a.Name)) .ToList()) { existingMetadata.Actors.Add(actor); if (await _televisionRepository.AddActor(existingMetadata, actor)) { result.IsUpdated = true; } } foreach (MetadataGuid guid in existingMetadata.Guids .Filter(g => fullMetadata.Guids.All(g2 => g2.Guid != g.Guid)) .ToList()) { existingMetadata.Guids.Remove(guid); if (await _metadataRepository.RemoveGuid(guid)) { result.IsUpdated = true; } } foreach (MetadataGuid guid in fullMetadata.Guids .Filter(g => existingMetadata.Guids.All(g2 => g2.Guid != g.Guid)) .ToList()) { existingMetadata.Guids.Add(guid); if (await _metadataRepository.AddGuid(existingMetadata, guid)) { result.IsUpdated = true; } } foreach (Tag tag in existingMetadata.Tags .Filter(g => fullMetadata.Tags.All(g2 => g2.Name != g.Name)) .ToList()) { existingMetadata.Tags.Remove(tag); if (await _metadataRepository.RemoveTag(tag)) { result.IsUpdated = true; } } foreach (Tag tag in fullMetadata.Tags .Filter(g => existingMetadata.Tags.All(g2 => g2.Name != g.Name)) .ToList()) { existingMetadata.Tags.Add(tag); if (await _televisionRepository.AddTag(existingMetadata, tag)) { result.IsUpdated = true; } } if (result.IsUpdated) { await _metadataRepository.MarkAsUpdated(existingMetadata, fullMetadata.DateUpdated); } }, _ => Task.CompletedTask); } return(result); }
public static L Left <L, R>(this Either <L, R> e) => e().Left;
private async Task <Either <BaseError, Unit> > ScanEpisodes( PlexLibrary library, List <PlexPathReplacement> pathReplacements, PlexSeason season, PlexConnection connection, PlexServerAuthToken token, string ffmpegPath, string ffprobePath, bool deepScan, CancellationToken cancellationToken) { List <PlexItemEtag> existingEpisodes = await _plexTelevisionRepository.GetExistingPlexEpisodes(library, season); Either <BaseError, List <PlexEpisode> > entries = await _plexServerApiClient.GetSeasonEpisodes( library, season, connection, token); foreach (BaseError error in entries.LeftToSeq()) { return(error); } var episodeEntries = entries.RightToSeq().Flatten().ToList(); foreach (PlexEpisode incoming in episodeEntries) { if (cancellationToken.IsCancellationRequested) { return(new ScanCanceled()); } if (await ShouldScanItem(library, pathReplacements, existingEpisodes, incoming, deepScan) == false) { continue; } incoming.SeasonId = season.Id; // TODO: figure out how to rebuild playlists Either <BaseError, MediaItemScanResult <PlexEpisode> > maybeEpisode = await _televisionRepository .GetOrAddPlexEpisode(library, incoming) .BindT(existing => UpdateMetadata(existing, incoming)) .BindT( existing => UpdateStatistics( pathReplacements, existing, incoming, library, connection, token, ffmpegPath, ffprobePath, deepScan)) .BindT(existing => UpdateSubtitles(pathReplacements, existing, incoming)) .BindT(existing => UpdateArtwork(existing, incoming)); foreach (BaseError error in maybeEpisode.LeftToSeq()) { switch (error) { case ScanCanceled: return(error); default: _logger.LogWarning( "Error processing plex episode at {Key}: {Error}", incoming.Key, error.Value); break; } } foreach (MediaItemScanResult <PlexEpisode> result in maybeEpisode.RightToSeq()) { await _plexTelevisionRepository.SetPlexEtag(result.Item, incoming.Etag); string plexPath = incoming.MediaVersions.Head().MediaFiles.Head().Path; string localPath = _plexPathReplacementService.GetReplacementPlexPath( pathReplacements, plexPath, false); if (_localFileSystem.FileExists(localPath)) { await _plexTelevisionRepository.FlagNormal(library, result.Item); } else { await _plexTelevisionRepository.FlagUnavailable(library, result.Item); } if (result.IsAdded) { await _searchIndex.AddItems(_searchRepository, new List <MediaItem> { result.Item }); } else { await _searchIndex.UpdateItems(_searchRepository, new List <MediaItem> { result.Item }); } } } var fileNotFoundKeys = existingEpisodes.Map(m => m.Key).Except(episodeEntries.Map(m => m.Key)).ToList(); List <int> ids = await _plexTelevisionRepository.FlagFileNotFoundEpisodes(library, fileNotFoundKeys); await _searchIndex.RebuildItems(_searchRepository, ids); _searchIndex.Commit(); return(Unit.Default); }
public SubscriptionFailure(Either<ResponseError, IDictionary<string, ResponseError>> error) { Error = error; }
public static R Right <L, R>(this Either <L, R> e) => e().Right;
public override void Given() { Either<string, double> either = "Some ol' blah".ToLeft(); eitherEither = either.ProjectLeft().Map<Either<int, double>>(str => str.Length.ToLeft()); }
public static Either <L, B> Bind <L, R, B>(this Either <L, R> e, Func <R, Either <L, B> > func) => e.HasLeft() ? (() => e.Left()) : func(e.Right());
public override void Given() { Either<double, string> either = "Some ol' blah".ToRight(); eitherEither = either.ProjectRight().Map<Either<double, int>>(str => str.Length.ToRight()); }
protected abstract int GetId(Either <Error, TId> newObj);