public static TvShowDirectoryLayout CreateDownloadLayoutTvShow(PlexTvShow show, ApplicationOptions settings, int layout) { var dirLayout = new TvShowDirectoryLayout(); if (layout == MF_PLEX_STANDARD_LAYOUT) { var basePath = settings.Generic.DownloadDirectory + @"\TV\"; var season = show.Season; var title = show.TvShowName.ToClean(); var seasonPath = basePath + title + @"\" + season; var titlePath = basePath + title; if (!Directory.Exists(basePath)) { Directory.CreateDirectory(basePath); } if (!Directory.Exists(titlePath)) { Directory.CreateDirectory(titlePath); } if (!Directory.Exists(seasonPath)) { Directory.CreateDirectory(seasonPath); } dirLayout.TitlePath = titlePath; dirLayout.SeasonPath = seasonPath; dirLayout.BasePath = basePath; } return(dirLayout); }
public async Task <IReadOnlyCollection <Season> > GetSeasonsAsync(PlexTvShow tvShow, PlexServer server) { var seasonMetadata = await _plexClient.GetChildrenMetadata( server.AccessToken, server.Host, int.Parse(tvShow.Key)); return(await Task.WhenAll(seasonMetadata.MediaContainer.Metadata.Select(GetSeasonsFromMetadataAsync))); async Task <Season> GetSeasonsFromMetadataAsync(Metadata metadata) { var episodesMetadata = await _plexClient.GetChildrenMetadata( server.AccessToken, server.Host, int.Parse(metadata.RatingKey)); var episodes = episodesMetadata.MediaContainer.Metadata.Select( m => new Episode { Title = m.Title, SeasonNumber = m.ParentIndex, EpisodeNumber = m.Index }); return(new Season { SeasonNumber = metadata.Index, Episodes = episodes.ToList() }); } }
public static DataTable TvAttributesFromObject(PlexTvShow content, bool silent = false) { var table = new DataTable("TvAttributes"); var columnAttributeName = new DataColumn("Name", typeof(string)); var columnAttributeValue = new DataColumn("Value"); table.Columns.AddRange( new[] { columnAttributeName, columnAttributeValue }); try { var season = new[] { "Season Name", content.Season }; var episodeCount = new[] { "Episode Count", content.EpisodesInSeason.ToString() }; var seasonNumber = new[] { "Season #", content.SeasonNumber.ToString() }; var episodeNumber = new[] { "Episode #", content.EpisodeNumber.ToString() }; var genre = new[] { "Genre", content.ContentGenre }; var runtime = new[] { "Runtime", Methods.CalculateTime(content.StreamInformation.ContentDuration) }; var resolution = new[] { "Resolution", content.StreamResolution.ResolutionString() }; var frameRate = new[] { "Frame-rate", FormatFramerate(content) }; var size = new[] { "File size", Methods.FormatBytes(content.StreamInformation.ByteLength) }; var container = new[] { "Container", content.StreamInformation.Container }; var newRows = new[] { season, episodeCount, seasonNumber, episodeNumber, genre, runtime, resolution, frameRate, size, container }; foreach (object[] row in newRows) { table.Rows.Add(row); } } catch (Exception ex) { LoggingHelpers.RecordException(ex.Message, "AttributeTableError"); if (!silent) { UIMessages.Error("Error occurred whilst building content attribute table:\n\n" + ex, @"Data Error"); } } return(table); }
public async Task <List <PlexTvShowSeason> > GetSeasonsAsync(string serverAuthToken, string plexFullHost, PlexTvShow plexTvShow) { var result = await _plexApi.GetSeasonsAsync(serverAuthToken, plexFullHost, plexTvShow.Key); return(result != null?_mapper.Map <List <PlexTvShowSeason> >(result.MediaContainer.Metadata) : new List <PlexTvShowSeason>()); }
//TV OBJECT BUILDER public static PlexTvShow GetTvObjectFromIndex(int index, bool waitWindow = true) { try { if (waitWindow) { return((PlexTvShow)WaitWindow.WaitWindow.Show(GetTvObjectFromIndex_Callback, @"Getting metadata", index)); } var obj = new PlexTvShow(); LoggingHelpers.RecordGeneralEntry(@"Content Parse Started"); LoggingHelpers.RecordGeneralEntry(@"Grabbing Titles"); var metadata = XmlMetadataContent.GetEpisodeMetadata(index); LoggingHelpers.RecordGeneralEntry(@"Checking XML validity"); if (Methods.PlexXmlValid(metadata.Xml)) { LoggingHelpers.RecordGeneralEntry(@"XML Valid"); var dlInfo = DownloadInfoGatherers.GetContentDownloadInfo(metadata.Xml); if (dlInfo != null) { LoggingHelpers.RecordGeneralEntry(@"Assembling Object"); obj.ApiUri = metadata.ApiUri; obj.ContentGenre = XmlMetadataStrings.GetContentGenre(metadata.Xml); var s = XmlMetadataIntegers.GetParentIndex(metadata.Xml); var e = XmlMetadataIntegers.GetIndex(metadata.Xml); obj.Season = XmlMetadataStrings.GetParentTitle(metadata.Xml); obj.EpisodesInSeason = DataProvider.EpisodesProvider.GetRawTable().Rows.Count; obj.EpisodeNumber = e > 0 ? e : 1; //episode numbers start at 1, not 0; enforce this. obj.SeasonNumber = s > 0 ? s : 1; //season numbers start at 1, not 0; enforce this. obj.TvShowName = XmlMetadataStrings.GetGrandparentTitle(metadata.Xml); obj.StreamResolution = XmlMetadataObjects.GetContentResolution(metadata.Xml); obj.Actors = XmlMetadataObjects.GetActorsFromMetadata(metadata.Xml); obj.StreamIndex = index; obj.Synopsis = XmlMetadataStrings.GetContentSynopsis(metadata.Xml); obj.StreamInformation = dlInfo; //apply the raw metadata to the object (it won't get serialised) obj.RawMetadata = metadata.Xml; //This works, but it shouldn't - I feel like it shouldn't. //Check if the season information is valid (must have a number). //Sometimes, seasons don't get named correctly. For example, 'Specials' rather than 'Season 1'. //This is one method of validation for a correctly named 'Season' of a show. //In addition, if the verification method fails for a season number check, it returns -1 (season numbers start at 1+), //so it makes sense to check for above zero season indices as well. var valid = obj.Season.ToLower().StartsWith(@"season") && s > 0; var notation = valid ? obj.Notation : obj.Season; //apply default notation only if it's a valid season name, otherwise just use the name itself. var fileName = $"{obj.TvShowName} - {notation} - {obj.StreamInformation.ContentTitle}.{dlInfo.Container}"; //override the filename generated above with the correct Plex formatting generated by the PlexTvShow object. obj.StreamInformation.FileName = fileName.ToClean(); } else { UIMessages.Error( @"Failed to get contextual information; an unknown error occurred. Check the exception log for more information.", @"Data Error"); LoggingHelpers.RecordException( "DownloadInfo invalid. This may be an internal error; please report this issue on GitHub.", "ContextDownloadInfoNull"); LoggingHelpers.RecordGeneralEntry( "DownloadInfo is invalid (no stream contextual information)"); } } else { LoggingHelpers.RecordGeneralEntry("XML Invalid"); } LoggingHelpers.RecordGeneralEntry("Returned assembled TV object"); return(obj); } catch (ThreadAbortException) { //literally nothing; this gets raised when a cancellation happens. return(null); } catch (Exception ex) { UIMessages.Error("Content metadata error:\n\n" + ex, @"Data Error"); LoggingHelpers.RecordException(ex.Message, "TVObjectError"); return(null); } }