public static string GetSectionKey(XmlDocument doc) { var key = ""; LoggingHelpers.RecordGeneralEntry("Parsing XML Reply"); using (XmlReader reader = new XmlNodeReader(doc)) { while (reader.Read()) { if (reader.IsStartElement()) { LoggingHelpers.RecordGeneralEntry("Checking for directories"); switch (reader.Name) { case "Directory": if (reader.GetAttribute("title") == "Library Sections") { var localKey = reader.GetAttribute("key"); key = localKey; LoggingHelpers.RecordGeneralEntry("Found " + key); } break; } } } return(key); } }
public static int GetTableIndexFromDgv(DataGridView dgv, DataTable table = null) { //MessageBox.Show(@"Hello!"); LoggingHelpers.RecordGeneralEntry($"Table-to-Grid match has been requested on '{dgv.Name}'"); //if the table's null we can't do anything with it, because there's no data to work with. if (table == null) { //set the table object to the default table, log it, and keep going. table = ReturnCorrectTable(); LoggingHelpers.RecordGeneralEntry( "Table-to-Grid match was not given a table; defaulting to the standard table selector."); } var selRow = ((DataRowView)dgv.SelectedRows[0].DataBoundItem).Row .ItemArray; //array of cell values from the selected row var val = 0; //value to return back to the caller //go through every row in the TABLE foreach (DataRow r in table.Rows) { //get the index number of the row we're currently processing //NOTE: This is the index inside of the TABLE NOT THE GRID var i = table.Rows.IndexOf(r); //represents the total matches so far (how many cells in the current //TABLE row match the selected GRID row) var m = 0; //cycle through each cell value in the currently selected GRID row foreach (var o in selRow) { //does the TABLE row contain the current cell value of the GRID row? if (r.ItemArray.Contains(o)) { m++; //increment the match counter } else { break; //if one wrong match is encountered, break immediately. This will drastically improve lookup speeds. } } //ALL column values must match, so the match count will be equal to the cell length. if (m != selRow.Length) { continue; } val = i; //set the return value to the current TABLE row index break; //ONLY triggered if the match counter equals the selected row's cell count. } return(val); }
public static void LaunchPvs(PlexObject stream) { if (stream != null) { try { if (!Methods.StreamAdultContentCheck(stream)) { return; } //downloads won't work properly if you're streaming at the same time if (!Flags.IsDownloadRunning && !Flags.IsEngineRunning) { var frm = new UI.Forms.Player { StreamingContent = stream }; LoggingHelpers.RecordGeneralEntry("Started streaming " + stream.StreamInformation.ContentTitle + " (PVS)"); frm.ShowDialog(); } else { UIMessages.Warning( "You cannot stream \n" + stream.StreamInformation.ContentTitle + "\n because a download is already running. Cancel the download before attempting to stream within PlexDL.", @"Validation Error"); LoggingHelpers.RecordGeneralEntry( "Tried to stream content via PVS, but a download is running."); } } catch (Exception ex) { UIMessages.Error("Error occurred whilst trying to launch VLC\n\n" + ex, @"Launch Error"); LoggingHelpers.RecordException(ex.Message, "VLCLaunchError"); } } else { LoggingHelpers.RecordGeneralEntry("Tried to stream content via PVS, but one or more values were null."); } }
public static void LaunchBrowser(PlexObject stream) { try { if (Methods.StreamAdultContentCheck(stream)) { Process.Start(stream.StreamInformation.Links .View); //normal MP4 stream (this won't trigger a browser download if it's a supported file) LoggingHelpers.RecordGeneralEntry("Started streaming " + stream.StreamInformation.ContentTitle + " (Browser)"); } } catch (Exception ex) { UIMessages.Error("Error occurred whilst trying to launch the default browser\n\n" + ex, @"Launch Error"); LoggingHelpers.RecordException(ex.Message, "BrowserLaunchError"); } }
public static XmlMetadata GetContentMetadata(int index) { XmlMetadata obj; try { LoggingHelpers.RecordGeneralEntry("Getting movie metadata XML"); var result = RowGet.GetDataRowContent(index); obj = XmlMetadataHelpers.GetMetadata(result); } catch (Exception ex) { LoggingHelpers.RecordException(ex.Message, "GetMovieMetadataError"); obj = new XmlMetadata(); } return(obj); }
public static XmlMetadata GetTracksListXml(int index) { XmlMetadata obj; try { LoggingHelpers.RecordGeneralEntry("Getting track list XML"); var result = RowGet.GetDataRowAlbums(index); obj = XmlMetadataHelpers.GetMetadata(result); } catch (Exception ex) { LoggingHelpers.RecordException(ex.Message, "GetTrackListError"); obj = new XmlMetadata(); } return(obj); }
//another method to handle testing a connection //this one's here for logging purposes and such, and is used //solely by the Server Manager private static WebCheck TestConnection(Server svr) { var value = new WebCheck(); try { var uri = ConnectionLink(svr); //UIMessages.Info(uri); var testUrl = WebCheck.TestUrl(uri); value = testUrl; } catch (Exception ex) { LoggingHelpers.RecordGeneralEntry($"Couldn't connect to \"{svr.address}:{svr.port}\""); LoggingHelpers.RecordException(ex.Message, "ConnectionTestError"); } return(value); }
public void ToFile(string fileName = "plex.account") { try { var xsSubmit = new XmlSerializer(typeof(CachedPlexLogin)); var xmlSettings = new XmlWriterSettings(); var sww = new StringWriter(); xmlSettings.Indent = true; xmlSettings.IndentChars = "\t"; xmlSettings.OmitXmlDeclaration = false; xsSubmit.Serialize(sww, this); File.WriteAllText(fileName, sww.ToString()); LoggingHelpers.RecordGeneralEntry("Saved PlexLogin data to '" + fileName + "'"); } catch (Exception ex) { LoggingHelpers.RecordException(ex.Message, "PlexLoginSaveError"); } }
public static XmlMetadata GetMetadata(DataRow result, string msgNoKey = "Error occurred whilst getting the unique content key", string logNoKeyMsg = "Error occurred whilst getting the unique content key", string logNoKeyType = "NoUnqKeyError", string column = "key") { var obj = new XmlMetadata(); XmlDocument reply = null; var key = ""; if (result[column] != null) { if (!Equals(result[column], string.Empty)) { key = result[column].ToString(); } } if (string.IsNullOrEmpty(key)) { UIMessages.Error(msgNoKey, @"Data Error"); LoggingHelpers.RecordGeneralEntry("Unique key error"); LoggingHelpers.RecordException(logNoKeyMsg, logNoKeyType); } else { var baseUri = Strings.GetBaseUri(false); key = key.TrimStart('/'); var uri = baseUri + key + "/?X-Plex-Token="; LoggingHelpers.RecordGeneralEntry("Contacting the API"); reply = XmlGet.GetXmlTransaction(uri); } obj.Xml = reply; obj.ApiUri = $"/{key}"; return(obj); }
//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); } }
//MUSIC OBJECT BUILDER public static PlexMusic GetMusicObjectFromIndex(int index, bool waitWindow = true) { try { if (waitWindow) { return((PlexMusic)WaitWindow.WaitWindow.Show(GetMusicObjectFromIndex_Callback, @"Getting metadata", index)); } var obj = new PlexMusic(); LoggingHelpers.RecordGeneralEntry(@"Content Parse Started"); LoggingHelpers.RecordGeneralEntry(@"Grabbing Titles"); var metadata = XmlMetadataContent.GetTrackMetadata(index); LoggingHelpers.RecordGeneralEntry(@"Checking XML validity"); if (Methods.PlexXmlValid(metadata.Xml)) { LoggingHelpers.RecordGeneralEntry(@"XML Valid"); //UIMessages.Info(ObjectProvider.CurrentContentType.ToString()); var dlInfo = DownloadInfoGatherers.GetContentDownloadInfo(metadata.Xml); if (dlInfo != null) { LoggingHelpers.RecordGeneralEntry(@"Assembling Object"); obj.ApiUri = metadata.ApiUri; obj.ContentGenre = XmlMetadataStrings.GetContentGenre(metadata.Xml); obj.StreamInformation = dlInfo; obj.StreamResolution = new Resolution(); //audio doesn't have video-type resolution obj.Actors = new List <PlexActor>(); //Plex audio does not contain the "<Role>" tag obj.StreamIndex = index; obj.Album = XmlMetadataStrings.GetParentTitle(metadata.Xml); obj.Artist = XmlMetadataStrings.GetGrandparentTitle(metadata.Xml); obj.Synopsis = "Auditory Content"; //Plex audio does not contain the "summary" attribute //apply the raw metadata to the object (it won't get serialised) obj.RawMetadata = metadata.Xml; } 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 Music 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, @"MusicObjectError"); return(null); } }
//MOVIE OBJECT BUILDER public static PlexMovie GetMovieObjectFromIndex(int index, bool waitWindow = true) { try { if (waitWindow) { return((PlexMovie)WaitWindow.WaitWindow.Show(GetMovieObjectFromIndex_Callback, @"Getting metadata", index)); } var obj = new PlexMovie(); LoggingHelpers.RecordGeneralEntry(@"Content Parse Started"); LoggingHelpers.RecordGeneralEntry(@"Grabbing Titles"); var metadata = XmlMetadataContent.GetContentMetadata(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); obj.StreamInformation = dlInfo; obj.StreamResolution = XmlMetadataObjects.GetContentResolution(metadata.Xml); obj.Actors = XmlMetadataObjects.GetActorsFromMetadata(metadata.Xml); obj.StreamIndex = index; obj.Synopsis = XmlMetadataStrings.GetContentSynopsis(metadata.Xml); //apply the raw metadata to the object (it won't get serialised) obj.RawMetadata = metadata.Xml; } 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 Movie 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, @"MovieObjectError"); return(null); } }
public static void LaunchVlc(PlexObject stream) { try { if (!Methods.StreamAdultContentCheck(stream)) { return; } var p = new Process(); var c = new StringVariableController(); var vlc = ObjectProvider.Settings.Player.VlcMediaPlayerPath; var arg = ObjectProvider.Settings.Player.VlcMediaPlayerArgs; if (VlcInstalled()) { c.Input = arg; c.Variables = c.BuildFromDlInfo(stream.StreamInformation); arg = c.YieldString(); p.StartInfo.FileName = vlc; p.StartInfo.Arguments = arg; p.Start(); LoggingHelpers.RecordGeneralEntry("Started streaming " + stream.StreamInformation.ContentTitle + " (VLC)"); } else { UIMessages.Error(@"PlexDL could not find VLC Media Player. Please locate VLC and then try again."); var ofd = new OpenFileDialog { Filter = @"VLC Executable|vlc.exe", Title = @"Locate VLC Media Player", Multiselect = false }; if (ofd.ShowDialog() != DialogResult.OK) { return; } var fileName = ofd.FileName; var baseName = Path.GetFileName(fileName).ToLower(); if (baseName == "vlc.exe") { //apply the newly-located vlc.exe to global settings for persistence ObjectProvider.Settings.Player.VlcMediaPlayerPath = fileName; //finally, launch VLC itself. LaunchVlc(stream); } else { UIMessages.Error(@"Invalid VLC Media Player executable name"); } } } catch (Exception ex) { UIMessages.Error("Error occurred whilst trying to launch VLC\n\n" + ex, @"Launch Error"); LoggingHelpers.RecordException(ex.Message, "VLCLaunchError"); } }
public static StreamInfo GetContentDownloadInfo(XmlDocument xml) { try { if (!Methods.PlexXmlValid(xml)) { return(new StreamInfo()); } var obj = new StreamInfo(); LoggingHelpers.RecordGeneralEntry("Grabbing DownloadInfo object"); var sections = new DataSet(); sections.ReadXml(new XmlNodeReader(xml)); var part = sections.Tables["Part"]; DataRow dlRow; //UIMessages.Info(ObjectProvider.CurrentContentType.ToString()); switch (ObjectProvider.CurrentContentType) { case ContentType.Movies: dlRow = sections.Tables["Video"].Rows[0]; break; case ContentType.TvShows: dlRow = sections.Tables["Video"].Rows[0]; break; case ContentType.Music: dlRow = sections.Tables["Track"].Rows[0]; break; default: throw new ArgumentOutOfRangeException(); } if (dlRow == null) { return(new StreamInfo()); } var title = dlRow["title"].ToString(); if (title.Length > ObjectProvider.Settings.Generic.DefaultStringLength) { title = title.Substring(0, ObjectProvider.Settings.Generic.DefaultStringLength); } var thumb = dlRow["thumb"].ToString(); var thumbnailFullUri = ""; if (!string.IsNullOrEmpty(thumb)) { var baseUri = Strings.GetBaseUri(false).TrimEnd('/'); thumbnailFullUri = baseUri + thumb + "?X-Plex-Token=" + Strings.GetToken(); } var partRow = part.Rows[0]; var filePart = ""; var container = ""; if (partRow["key"] != null) { filePart = partRow["key"].ToString(); } if (partRow["container"] != null) { container = partRow["container"].ToString(); } var byteLength = Convert.ToInt64(partRow["size"]); var contentDuration = Convert.ToInt32(partRow["duration"]); var fileName = (title + "." + container).ToClean(); //The PMS (Plex Media Server) will return the file as an octet-stream (download) if we set //the GET parameter 'download' to '1' and a normal MP4 stream if we set it to '0'. obj.Links.View = Strings.GetBaseUri(false).TrimEnd('/') + filePart + "?download=0&X-Plex-Token=" + Strings.GetToken(); obj.Links.Download = Strings.GetBaseUri(false).TrimEnd('/') + filePart + "?download=1&X-Plex-Token=" + Strings.GetToken(); obj.Container = container; obj.ByteLength = byteLength; obj.ContentDuration = contentDuration; obj.FileName = fileName; obj.ContentTitle = title; obj.ContentThumbnailUri = thumbnailFullUri; return(obj); } catch (Exception ex) { LoggingHelpers.RecordException(ex.Message, "DownloadXmlError"); UIMessages.Error(ex.ToString()); return(null); } }