protected Validation <BaseError, ProgramSchedule> CollectionTypeMustBeValid( IProgramScheduleItemRequest item, ProgramSchedule programSchedule) { switch (item.CollectionType) { case ProgramScheduleItemCollectionType.Collection: if (item.CollectionId is null) { return(BaseError.New("[Collection] is required for collection type 'Collection'")); } break; case ProgramScheduleItemCollectionType.TelevisionShow: if (item.MediaItemId is null) { return(BaseError.New("[MediaItem] is required for collection type 'TelevisionShow'")); } break; case ProgramScheduleItemCollectionType.TelevisionSeason: if (item.MediaItemId is null) { return(BaseError.New("[MediaItem] is required for collection type 'TelevisionSeason'")); } break; case ProgramScheduleItemCollectionType.Artist: if (item.MediaItemId is null) { return(BaseError.New("[MediaItem] is required for collection type 'Artist'")); } break; case ProgramScheduleItemCollectionType.MultiCollection: if (item.MultiCollectionId is null) { return(BaseError.New("[MultiCollection] is required for collection type 'MultiCollection'")); } break; case ProgramScheduleItemCollectionType.SmartCollection: if (item.SmartCollectionId is null) { return(BaseError.New("[SmartCollection] is required for collection type 'SmartCollection'")); } break; default: return(BaseError.New("[CollectionType] is invalid")); } return(programSchedule); }
public async Task <Either <BaseError, List <JellyfinMovie> > > GetMovieLibraryItems( string address, string apiKey, int mediaSourceId, string libraryId) { try { if (_memoryCache.TryGetValue($"jellyfin_admin_user_id.{mediaSourceId}", out string userId)) { IJellyfinApi service = RestService.For <IJellyfinApi>(address); JellyfinLibraryItemsResponse items = await service.GetMovieLibraryItems(apiKey, userId, libraryId); return(items.Items .Map(ProjectToMovie) .Somes() .ToList()); } return(BaseError.New("Jellyfin admin user id is not available")); } catch (Exception ex) { _logger.LogError(ex, "Error getting jellyfin movie library items"); return(BaseError.New(ex.Message)); } }
protected static async Task <Either <BaseError, ProgramSchedule> > FillerConfigurationMustBeValid( TvContext dbContext, IProgramScheduleItemRequest item, ProgramSchedule programSchedule) { var allFillerIds = Optional(item.PreRollFillerId) .Append(Optional(item.MidRollFillerId)) .Append(Optional(item.PostRollFillerId)) .ToList(); List <FillerPreset> allFiller = await dbContext.FillerPresets .Filter(fp => allFillerIds.Contains(fp.Id)) .ToListAsync(); if (allFiller.Count(f => f.PadToNearestMinute.HasValue) > 1) { return(BaseError.New("Schedule may only contain one filler preset that is configured to pad")); } if (allFiller.Any(fp => fp.PadToNearestMinute.HasValue) && !item.FallbackFillerId.HasValue) { return(BaseError.New("Fallback filler is required when padding")); } return(programSchedule); }
public async Task <Either <BaseError, List <JellyfinCollection> > > GetCollectionLibraryItems( string address, string apiKey, int mediaSourceId) { try { if (_memoryCache.TryGetValue($"jellyfin_admin_user_id.{mediaSourceId}", out string userId)) { // TODO: should we enumerate collection libraries here? if (_memoryCache.TryGetValue("jellyfin_collections_library_item_id", out string itemId)) { IJellyfinApi service = RestService.For <IJellyfinApi>(address); JellyfinLibraryItemsResponse items = await service.GetCollectionLibraryItems(apiKey, userId, itemId); return(items.Items .Map(ProjectToCollection) .Somes() .ToList()); } return(BaseError.New("Jellyfin collection item id is not available")); } return(BaseError.New("Jellyfin admin user id is not available")); } catch (Exception ex) { _logger.LogError(ex, "Error getting jellyfin collection library items"); return(BaseError.New(ex.Message)); } }
private async Task <Either <BaseError, MediaItemScanResult <Song> > > UpdateMetadata( MediaItemScanResult <Song> result, string ffprobePath) { try { Song song = result.Item; string path = song.GetHeadVersion().MediaFiles.Head().Path; bool shouldUpdate = Optional(song.SongMetadata).Flatten().HeadOrNone().Match( m => m.MetadataKind == MetadataKind.Fallback || m.DateUpdated != _localFileSystem.GetLastWriteTime(path), true); if (shouldUpdate) { song.SongMetadata ??= new List <SongMetadata>(); _logger.LogDebug("Refreshing {Attribute} for {Path}", "Metadata", path); if (await _localMetadataProvider.RefreshTagMetadata(song, ffprobePath)) { result.IsUpdated = true; } } return(result); } catch (Exception ex) { _client.Notify(ex); return(BaseError.New(ex.ToString())); } }
private static async Task <Either <BaseError, Season> > AddSeason( TvContext dbContext, Show show, int libraryPathId, int seasonNumber) { try { var season = new Season { LibraryPathId = libraryPathId, ShowId = show.Id, SeasonNumber = seasonNumber, Episodes = new List <Episode>(), SeasonMetadata = new List <SeasonMetadata> { new() { DateAdded = DateTime.UtcNow } } }; await dbContext.Seasons.AddAsync(season); await dbContext.SaveChangesAsync(); return(season); } catch (Exception ex) { return(BaseError.New(ex.Message)); } }
private async Task <Either <BaseError, Episode> > UpdateThumbnail(Episode episode, CancellationToken cancellationToken) { try { Option <string> maybeThumbnail = LocateThumbnail(episode); foreach (string thumbnailFile in maybeThumbnail) { foreach (EpisodeMetadata metadata in episode.EpisodeMetadata) { await RefreshArtwork( thumbnailFile, metadata, ArtworkKind.Thumbnail, None, None, cancellationToken); } } return(episode); } catch (Exception ex) { _client.Notify(ex); return(BaseError.New(ex.ToString())); } }
private Task <Either <BaseError, FFprobe> > GetProbeOutput(string ffprobePath, string filePath) { var startInfo = new ProcessStartInfo { FileName = ffprobePath, RedirectStandardOutput = true, RedirectStandardError = true, UseShellExecute = false }; startInfo.ArgumentList.Add("-v"); startInfo.ArgumentList.Add("quiet"); startInfo.ArgumentList.Add("-print_format"); startInfo.ArgumentList.Add("json"); startInfo.ArgumentList.Add("-show_format"); startInfo.ArgumentList.Add("-show_streams"); startInfo.ArgumentList.Add("-i"); startInfo.ArgumentList.Add(filePath); var probe = new Process { StartInfo = startInfo }; probe.Start(); return(probe.StandardOutput.ReadToEndAsync().MapAsync <string, Either <BaseError, FFprobe> >( async output => { await probe.WaitForExitAsync(); return probe.ExitCode == 0 ? JsonConvert.DeserializeObject <FFprobe>(output) : BaseError.New($"FFprobe at {ffprobePath} exited with code {probe.ExitCode}"); })); }
public async Task <Either <BaseError, List <EmbyCollection> > > GetCollectionLibraryItems(string address, string apiKey) { try { // TODO: should we enumerate collection libraries here? if (_memoryCache.TryGetValue("emby_collections_library_item_id", out string itemId)) { IEmbyApi service = RestService.For <IEmbyApi>(address); EmbyLibraryItemsResponse items = await service.GetCollectionLibraryItems(apiKey, itemId); return(items.Items .Map(ProjectToCollection) .Somes() .ToList()); } return(BaseError.New("Emby collection item id is not available")); } catch (Exception ex) { _logger.LogError(ex, "Error getting Emby collection library items"); return(BaseError.New(ex.Message)); } }
public async Task <Either <BaseError, List <PlexLibrary> > > GetLibraries( PlexConnection connection, PlexServerAuthToken token) { try { IPlexServerApi service = RestService.For <IPlexServerApi>( new HttpClient { BaseAddress = new Uri(connection.Uri), Timeout = TimeSpan.FromSeconds(10) }); List <PlexLibraryResponse> directory = await service.GetLibraries(token.AuthToken).Map(r => r.MediaContainer.Directory); return(directory // .Filter(l => l.Hidden == 0) .Filter(l => l.Type.ToLowerInvariant() is "movie" or "show") .Map(Project) .Somes() .ToList()); } catch (Exception ex) { return(BaseError.New(ex.ToString())); } }
public async Task <Either <BaseError, bool> > RefreshStatistics(string ffprobePath, MediaItem mediaItem) { try { string filePath = mediaItem switch { Movie m => m.MediaVersions.Head().MediaFiles.Head().Path, Episode e => e.MediaVersions.Head().MediaFiles.Head().Path, _ => throw new ArgumentOutOfRangeException(nameof(mediaItem)) }; Either <BaseError, FFprobe> maybeProbe = await GetProbeOutput(ffprobePath, filePath); return(await maybeProbe.Match( async ffprobe => { MediaVersion version = ProjectToMediaVersion(ffprobe); bool result = await ApplyVersionUpdate(mediaItem, version, filePath); return Right <BaseError, bool>(result); }, error => Task.FromResult(Left <BaseError, bool>(error)))); } catch (Exception ex) { _logger.LogWarning(ex, "Failed to refresh statistics for media item {Id}", mediaItem.Id); return(BaseError.New(ex.Message)); } }
public async Task <Either <BaseError, Tuple <EpisodeMetadata, MediaVersion> > > GetEpisodeMetadataAndStatistics( PlexLibrary library, string key, PlexConnection connection, PlexServerAuthToken token) { try { IPlexServerApi service = XmlServiceFor(connection.Uri); 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)); return(maybeResponse.Match( response => { Option <MediaVersion> maybeVersion = ProjectToMediaVersion(response.Metadata); return maybeVersion.Match <Either <BaseError, Tuple <EpisodeMetadata, MediaVersion> > >( version => Tuple( ProjectToEpisodeMetadata(response.Metadata, library.MediaSourceId), version), () => BaseError.New("Unable to locate metadata")); }, () => BaseError.New("Unable to locate metadata"))); } catch (Exception ex) { return(BaseError.New(ex.ToString())); } }
private async Task <Either <BaseError, MediaItemScanResult <PlexMovie> > > AddPlexMovie( TvContext context, PlexLibrary library, PlexMovie item) { try { item.LibraryPathId = library.Paths.Head().Id; await context.PlexMovies.AddAsync(item); await context.SaveChangesAsync(); await context.Entry(item).Reference(i => i.LibraryPath).LoadAsync(); await context.Entry(item.LibraryPath).Reference(lp => lp.Library).LoadAsync(); return(new MediaItemScanResult <PlexMovie>(item) { IsAdded = true }); } catch (Exception ex) { return(BaseError.New(ex.ToString())); } }
private async Task <Either <BaseError, MediaItemScanResult <OtherVideo> > > UpdateMetadata( MediaItemScanResult <OtherVideo> result) { try { OtherVideo otherVideo = result.Item; if (!Optional(otherVideo.OtherVideoMetadata).Flatten().Any()) { otherVideo.OtherVideoMetadata ??= new List <OtherVideoMetadata>(); string path = otherVideo.MediaVersions.Head().MediaFiles.Head().Path; _logger.LogDebug("Refreshing {Attribute} for {Path}", "Fallback Metadata", path); if (await _localMetadataProvider.RefreshFallbackMetadata(otherVideo)) { result.IsUpdated = true; } } return(result); } catch (Exception ex) { _client.Notify(ex); return(BaseError.New(ex.ToString())); } }
public async Task <Either <BaseError, TraktList> > GetUserList(string user, string list) { try { TraktListResponse response = await JsonService().GetUserList( _traktConfiguration.Value.ClientId, user, list); return(new TraktList { TraktId = response.Ids.Trakt, User = response.User.Username, List = response.Ids.Slug, Name = response.Name, Description = response.Description, ItemCount = response.ItemCount, Items = new List <TraktListItem>() }); } catch (Exception ex) { _logger.LogError(ex, "Error getting trakt list"); return(BaseError.New(ex.Message)); } }
public async Task <Either <BaseError, bool> > RefreshStatistics( string ffmpegPath, string ffprobePath, MediaItem mediaItem, string mediaItemPath) { try { Either <BaseError, FFprobe> maybeProbe = await GetProbeOutput(ffprobePath, mediaItemPath); return(await maybeProbe.Match( async ffprobe => { MediaVersion version = ProjectToMediaVersion(mediaItemPath, ffprobe); if (version.Duration.TotalSeconds < 1) { await AnalyzeDuration(ffmpegPath, mediaItemPath, version); } bool result = await ApplyVersionUpdate(mediaItem, version, mediaItemPath); return Right <BaseError, bool>(result); }, error => Task.FromResult(Left <BaseError, bool>(error)))); } catch (Exception ex) { _logger.LogWarning(ex, "Failed to refresh statistics for media item {Id}", mediaItem.Id); _client.Notify(ex); return(BaseError.New(ex.Message)); } }
private static async Task CreateResponseAsync(HttpContext context, BaseError error) { error.ActivityId = context.TraceIdentifier; var response = JsonConvert.SerializeObject(new ErrorResponse <BaseError>(error)); context.Response.StatusCode = error.ErrorCode; await context.Response.WriteAsync(response); }
protected static Validation <BaseError, ProgramSchedule> PlayoutModeMustBeValid( IProgramScheduleItemRequest item, ProgramSchedule programSchedule) { if (item.MultiCollectionId.HasValue) { switch (item.PlaybackOrder) { case PlaybackOrder.Chronological: case PlaybackOrder.Random: return(BaseError.New($"Invalid playback order for multi collection: '{item.PlaybackOrder}'")); case PlaybackOrder.Shuffle: case PlaybackOrder.ShuffleInOrder: break; } } switch (item.PlayoutMode) { case PlayoutMode.Flood: case PlayoutMode.One: break; case PlayoutMode.Multiple: if (item.MultipleCount.GetValueOrDefault() < 0) { return(BaseError.New( "[MultipleCount] must be greater than or equal to 0 for playout mode 'multiple'")); } break; case PlayoutMode.Duration: if (item.PlayoutDuration is null) { return(BaseError.New("[PlayoutDuration] is required for playout mode 'duration'")); } if (item.TailMode == TailMode.Filler && item.TailFillerId == null) { return(BaseError.New("Tail Filler is required with tail mode Filler")); } if (item.TailFillerId != null && item.TailMode != TailMode.Filler) { return(BaseError.New("Tail Filler will not be used unless tail mode is set to Filler")); } break; default: return(BaseError.New("[PlayoutMode] is invalid")); } return(programSchedule); }
/// <inheritdoc/> public virtual BaseError Handle(Exception exception) { if (!CanHandle(exception)) { throw new NotSupportedException($"Cannot handle exception of type {exception.GetType()}"); } BaseError error = HandleException(exception as TException); return(error); }
private async Task <Either <BaseError, bool> > UpdateSubtitles(EmbyEpisode episode, string localPath) { try { return(await _localSubtitlesProvider.UpdateSubtitles(episode, localPath, false)); } catch (Exception ex) { return(BaseError.New(ex.ToString())); } }
/// <summary> /// </summary> /// <param name="baseError"></param> /// <returns></returns> public Task <HttpResponseMessage> CreateErrorResponse(BaseError baseError) { ResponseMessage = Request.CreateResponse( new { Status = DefaultResponseStatus.Failure.ToString(), ErrorMessage = new BaseErrorResponse((int)baseError.HttpStatusCode, baseError.Message), }); ResponseMessage.StatusCode = baseError.HttpStatusCode; return(Task.FromResult(ResponseMessage)); }
public async Task <Either <BaseError, string> > GetLatestReleaseNotes(CancellationToken cancellationToken) { try { IGitHubApi service = RestService.For <IGitHubApi>("https://api.github.com"); return(await service.GetReleases(cancellationToken).Map(releases => releases.Head().Body)); } catch (Exception ex) { return(BaseError.New(ex.ToString())); } }
public ProceesResultErrorType GetErrorType(BaseError error) { KeyValuePair <Type, ProceesResultErrorType>?err = ERROR2ENUM_DIC.FirstOrDefault(x => x.Key == error.GetType()); if (err == null) { return(ProceesResultErrorType.Unknown); } else { return(err.Value.Value); } }
public static CustomActionResult GetErrorResponse(BaseError error, string uri, string message) { return(new CustomActionResult { Response = new ErrorResponse { Errors = new List <BaseError> { error }, Uri = uri, Message = message, } }); }
private async Task <Either <BaseError, MediaItemScanResult <Movie> > > UpdateSubtitles(MediaItemScanResult <Movie> result) { try { await _localSubtitlesProvider.UpdateSubtitles(result.Item, None, true); return(result); } catch (Exception ex) { _client.Notify(ex); return(BaseError.New(ex.ToString())); } }
private async Task <Either <BaseError, Episode> > UpdateSubtitles(Episode episode) { try { await _localSubtitlesProvider.UpdateSubtitles(episode, None, true); return(episode); } catch (Exception ex) { _client.Notify(ex); return(BaseError.New(ex.ToString())); } }
private async Task <Either <BaseError, MediaItemScanResult <MusicVideo> > > UpdateMetadata( MediaItemScanResult <MusicVideo> result) { try { MusicVideo musicVideo = result.Item; Option <string> maybeNfoFile = LocateNfoFile(musicVideo); if (maybeNfoFile.IsNone) { if (!Optional(musicVideo.MusicVideoMetadata).Flatten().Any()) { musicVideo.MusicVideoMetadata ??= new List <MusicVideoMetadata>(); string path = musicVideo.MediaVersions.Head().MediaFiles.Head().Path; _logger.LogDebug("Refreshing {Attribute} for {Path}", "Fallback Metadata", path); if (await _localMetadataProvider.RefreshFallbackMetadata(musicVideo)) { result.IsUpdated = true; } } } foreach (string nfoFile in maybeNfoFile) { bool shouldUpdate = Optional(musicVideo.MusicVideoMetadata).Flatten().HeadOrNone().Match( m => m.MetadataKind == MetadataKind.Fallback || m.DateUpdated != _localFileSystem.GetLastWriteTime(nfoFile), true); if (shouldUpdate) { _logger.LogDebug("Refreshing {Attribute} from {Path}", "Sidecar Metadata", nfoFile); if (await _localMetadataProvider.RefreshSidecarMetadata(musicVideo, nfoFile)) { result.IsUpdated = true; } } } return(result); } catch (Exception ex) { _client.Notify(ex); return(BaseError.New(ex.ToString())); } }
public async Task <Either <BaseError, PlexAuthPin> > StartPinFlow() { try { string clientIdentifier = await _plexSecretStore.GetClientIdentifier(); PlexPinResponse pinResponse = await _plexTvApi.StartPinFlow(AppName, clientIdentifier); return(new PlexAuthPin(pinResponse.Id, pinResponse.Code, clientIdentifier)); } catch (Exception ex) { _logger.LogError(ex, "Error starting plex pin flow"); return(BaseError.New(ex.Message)); } }
public static async Task <BaseResult> SendEmail(string email, string subject, string emailTemplate) { var result = new BaseResult(); //ToDo: Template logic!!! MailAddress addr; try { addr = new MailAddress(email); } catch (Exception e) { result.ResultStatus = false; var error = new BaseError() { StatusCode = null, ErrorDescription = "Faild Email address!", ExceptionMessage = e.Message }; result.Errors.Add(error); return(result); } var status = await SendEmailCore(email, subject, emailTemplate); if (status != HttpStatusCode.Accepted) { result.ResultStatus = false; var error = new BaseError { StatusCode = status, ErrorDescription = "Check SendEmailCore, Send fails", ExceptionMessage = null }; result.Errors.Add(error); return(result); } return(new BaseResult { ResultStatus = true }); }
private async Task <Either <BaseError, MediaItemScanResult <Song> > > UpdateThumbnail( MediaItemScanResult <Song> result, string ffmpegPath, CancellationToken cancellationToken) { try { // reload the song from the database at this point if (result.IsAdded) { LibraryPath libraryPath = result.Item.LibraryPath; string path = result.Item.GetHeadVersion().MediaFiles.Head().Path; foreach (MediaItemScanResult <Song> s in (await _songRepository.GetOrAdd(libraryPath, path)) .RightToSeq()) { result.Item = s.Item; } } Song song = result.Item; Option <string> maybeThumbnail = LocateThumbnail(song); if (maybeThumbnail.IsNone) { await ExtractEmbeddedArtwork(song, ffmpegPath, cancellationToken); } foreach (string thumbnailFile in maybeThumbnail) { SongMetadata metadata = song.SongMetadata.Head(); await RefreshArtwork( thumbnailFile, metadata, ArtworkKind.Thumbnail, ffmpegPath, None, cancellationToken); } return(result); } catch (Exception ex) { _client.Notify(ex); return(BaseError.New(ex.ToString())); } }