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);
 }
示例#10
0
		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);
 }
示例#13
0
 /// <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));
示例#14
0
    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);
 }
示例#16
0
 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
             });
 }
示例#17
0
 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
             });
 }
示例#18
0
 public static TResult GetOrThrow <TResult>(this Either <TResult, Exception> either)
 => either.Match(r => r, e => throw e);
示例#19
0
文件: Config.cs 项目: arturaz/pzd.lib
 public static Either <ConfigLookupError, A> parseErrorEFor <A>(
     ConfigPath path, object node, string extraInfo = null
     ) => Either <ConfigLookupError, A> .Left(parseErrorFor <A>(path, node, extraInfo));
示例#20
0
文件: Config.cs 项目: essess5/tlplib
 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());
示例#21
0
 public static void OnError <TResult, TError>(this Either <TResult, TError> either, Action <TError> err)
 => either.Match(_ => { }, err);
示例#22
0
        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));
        }
示例#23
0
        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();
                },
            });
        }
示例#24
0
        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));
        }
示例#25
0
 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);
示例#26
0
文件: Config.cs 项目: arturaz/pzd.lib
 /// 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));
 }
示例#28
0
文件: Config.cs 项目: arturaz/pzd.lib
 /// Parser that always fails and returns constant.
 public static Parser <object, A> constantErrorParser <A>(ConfigLookupError error) =>
 (path, _) => Either <ConfigLookupError, A> .Left(error);
示例#29
0
 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
             });
 }
示例#30
0
文件: Config.cs 项目: arturaz/pzd.lib
 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);
 }
示例#32
0
 void IObserver <Either <Notification <TLeft>, Notification <TRight> > > .OnNext(Either <Notification <TLeft>, Notification <TRight> > value)
 {
     value.Switch(left => left.Accept(LeftObserver), right => right.Accept(RightObserver));
 }
示例#33
0
    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);
示例#36
0
 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;
                                 });
 }
示例#38
0
 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()));
        }
示例#40
0
 public static bool HasRight <L, R>(this Either <L, R> e) => e().HasRight;
 protected override int GetId(Either <Error, int> newObj)
 {
     return(newObj.RightContent());
 }
示例#42
0
 public RiakGetOptions()
 {
     R = new Either<uint, string>(RiakConstants.QuorumOptions.Default);
     Pr = new Either<uint, string>(RiakConstants.QuorumOptions.Default);
 }
示例#43
0
 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();
 }
示例#47
0
        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;
        }
示例#48
0
 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);
示例#49
0
 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
             });
 }
示例#50
0
    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);
    }
示例#51
0
 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
             });
 }
示例#52
0
    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);
    }
示例#53
0
 public static L Left <L, R>(this Either <L, R> e) => e().Left;
示例#54
0
    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;
 }
示例#56
0
 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());
 }
示例#58
0
 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());
 }
示例#60
0
 protected abstract int GetId(Either <Error, TId> newObj);