/// <summary> /// Typically pictures are given an absolute size in px, which looks right given /// the current absolute size of the page it is on. For an ePUB, a percent size /// will work better. We calculate it based on the page sizes and margins in /// BasePage.less and commonMixins.less. The page size definitions are unlikely /// to change, but change might be needed here if there is a change to the main /// .marginBox rule in basePage.less. /// To partly accommodate origami pages, we adjust for parent divs with an explict /// style setting the percent width. /// </summary> /// <param name="pageDom"></param> private void FixPictureSizes(HtmlDom pageDom) { bool firstTime = true; double pageWidthMm = 210; // assume A5 Portrait if not specified foreach (XmlElement img in HtmlDom.SelectChildImgAndBackgroundImageElements(pageDom.RawDom.DocumentElement)) { var parent = img.ParentNode.ParentNode as XmlElement; var mulitplier = 1.0; // For now we only attempt to adjust pictures contained in the marginBox. // To do better than this we will probably need to actually load the HTML into // a browser; even then it will be complex. while (parent != null && !HasClass(parent, "marginBox")) { // 'marginBox' is not yet the margin box...it is some parent div. // If it has an explicit percent width style, adjust for this. var styleAttr = parent.Attributes["style"]; if (styleAttr != null) { var style = styleAttr.Value; var match = new Regex("width:\\s*(\\d+(\\.\\d+)?)%").Match(style); if (match.Success) { double percent; if (Double.TryParse(match.Groups[1].Value, out percent)) { mulitplier *= percent/100; } } } parent = parent.ParentNode as XmlElement; } if (parent == null) continue; var page = parent.ParentNode as XmlElement; if (!HasClass(page, "bloom-page")) continue; // or return? marginBox should be child of page! if (firstTime) { var pageClass = HtmlDom.GetAttributeValue(page, "class").Split().FirstOrDefault(c => c.Contains("Portrait") || c.Contains("Landscape")); // This calculation unfortunately duplicates information from basePage.less. const int A4Width = 210; const int A4Height = 297; const double letterPortraitHeight = 11.0 * mmPerInch; const double letterPortraitWidth = 8.5 * mmPerInch; const double legalPortraitHeight = 14.0 * mmPerInch; const double legalPortraitWidth = 8.5 * mmPerInch; switch (pageClass) { case "A3Landscape": pageWidthMm = A4Width*2.0; break; case "A5Portrait": pageWidthMm = A4Height/2.0; break; case "A4Portrait": pageWidthMm = A4Width; break; case "A5Landscape": pageWidthMm = A4Width / 2.0; break; case "A3Portrait": case "A4Landscape": pageWidthMm = A4Height; break; case "A6Portrait": pageWidthMm = A4Width / 2.0; break; case "A6Landscape": pageWidthMm = A4Height / 2.0; break; case "B5Portrait": pageWidthMm = 176; break; case "QuarterLetterPortrait": pageWidthMm = letterPortraitWidth/2.0; break; case "QuarterLetterLandscape": case "HalfLetterPortrait": pageWidthMm = letterPortraitHeight / 2.0; break; case "HalfLetterLandscape": case "LetterPortrait": pageWidthMm = letterPortraitWidth; break; case "LetterLandscape": pageWidthMm = letterPortraitHeight; break; case "HalfLegalPortrait": pageWidthMm = legalPortraitHeight / 2.0; break; case "HalfLegalLandscape": case "LegalPortrait": pageWidthMm = legalPortraitWidth; break; case "LegalLandscape": pageWidthMm = legalPortraitHeight; break; } firstTime = false; } var imgStyle = HtmlDom.GetAttributeValue(img, "style"); // We want to take something like 'width:334px; height:220px; margin-left: 34px; margin-top: 0px;' // and change it to something like 'width:75%; height:auto; margin-left: 10%; margin-top: 0px;' // This first pass deals with width. if (ConvertStyleFromPxToPercent("width", pageWidthMm, mulitplier, ref imgStyle)) continue; // Now change height to auto, to preserve aspect ratio imgStyle = new Regex("height:\\s*\\d+px").Replace(imgStyle, "height:auto"); if (!imgStyle.Contains("height")) imgStyle = "height:auto; " + imgStyle; // Similarly fix indent ConvertStyleFromPxToPercent("margin-left", pageWidthMm, mulitplier, ref imgStyle); img.SetAttribute("style", imgStyle); } }
public void ExecuteReader(string command, Action<DbDataReader> action) { var table = new DataTable(); var sqlSplit = new Regex(@"\W+").Split(command); if (sqlSplit.Contains("AppliedConcept")) { // SELECT ID, InfoType, SerializedInfo, ConceptInfoKey, ImplementationType, ConceptImplementationVersion, CreateQuery, RemoveQuery, ModificationOrder table.Columns.Add(new DataColumn("ID", typeof(Guid))); table.Columns.Add(); table.Columns.Add(); table.Columns.Add(); table.Columns.Add(); table.Columns.Add(); table.Columns.Add(new DataColumn("ModificationOrder", typeof(Int32))); foreach (var ca in Expected) AddRow(table, ca); } else if (sqlSplit.Contains("AppliedConceptDependsOn")) { //"SELECT DependentID, DependsOnID FROM Rhetos.AppliedConceptDependsOn" table.Columns.Add(new DataColumn("DependentID", typeof(Guid))); table.Columns.Add(new DataColumn("DependsOnID", typeof(Guid))); foreach (var ca in Expected) foreach (var dependsOn in ca.DependsOn) table.Rows.Add(ca.Id, dependsOn.Id); } else throw new NotImplementedException(); var reader = new DataTableReader(table); while (reader.Read()) action(reader); }
public static IEnumerable<string> EquationsFromParentheses(string recipe) { var equations = new List<string>(); if (string.IsNullOrWhiteSpace(recipe)) { return equations; } recipe = "(" + recipe + ")"; // If this is a duplication of effort, we'll silently ignore it later. recipe = new Regex(@"\s+").Replace(recipe, string.Empty); // Remove all whitespace. recipe = LeveledPreparser(recipe); var multiLetterMatch = invalidLetterFinder.Match(recipe); if (multiLetterMatch.Success) { throw new ArgumentException("The gem \"" + multiLetterMatch.Value + "\" must be a single letter. Gem combinations must be expressed as individual components separated with plus signs and brackets, as needed. For example:\nob → o+b\nob+o → (o+b)+o"); } var id = 0; foreach (var c in Gem.GemInitializer) { if (recipe.IndexOf(c) > -1) { recipe = recipe.Replace(c, id.ToString(CultureInfo.InvariantCulture)[0]); equations.Add(string.Format(CultureInfo.InvariantCulture, "{0}={1}", id, c)); id++; } } if (equations.Count == 0) { throw new ArgumentException("Recipe did not contain any recognizable gems."); } // Scan for plus signs within the formula and add gems together appropriately. int plus = recipe.IndexOf('+'); string newNum = (id - 1).ToString(CultureInfo.InvariantCulture); while (plus > -1) { string thisCombine; var close = recipe.IndexOf(')', plus); if (close >= 0) { var open = recipe.LastIndexOf('(', close); if (open < 0) { throw new ArgumentException("Bracket mismatch in formula."); } thisCombine = recipe.Substring(open + 1, close - open - 1); string[] combineGems = thisCombine.Split('+'); if (combineGems.Length != 2) { throw new ArgumentException("The formula provided contains more than a single plus sign within a pair of brackets or a term that is over-bracketed (e.g., \"((o+o))\"). These are not currently supported."); } if (combineGems[0].Length == 0 || combineGems[1].Length == 0) { throw new ArgumentException("Invalid formula part: (" + thisCombine + ")"); } newNum = id.ToString(CultureInfo.InvariantCulture); recipe = recipe.Replace("(" + thisCombine + ")", newNum); equations.Add(string.Format(CultureInfo.InvariantCulture, "{0}={1}+{2}", id, combineGems[0], combineGems[1])); } else { throw new ArgumentException("Bracket mismatch in formula."); } plus = recipe.IndexOf('+'); id++; } while (recipe.StartsWith("(", StringComparison.Ordinal) && recipe.EndsWith(")", StringComparison.Ordinal)) { recipe = recipe.Substring(1, recipe.Length - 2); } if (recipe != newNum) { if (recipe.Contains("(")) { throw new ArgumentException("Bracket mismatch in formula."); } throw new ArgumentException("Invalid recipe."); } return equations; }
//[End] private static async Task<AudioInformation> ParseVideoFromHTML(string html) { try { // Parse basic video information from the HTML string url = new Regex(URL_PATTERN).Match(html).Groups[1].Value; string title = new Regex(TITLE_PATTERN).Match(html).Groups[1].Value; string description = new Regex(DESCRIPTION_PATTERN).Match(html).Groups[1].Value; string thumbnailURL = new Regex(THUMBNAIL_PATTERN).Match(html).Groups[1].Value; // Make sure that the title and description don't contain any HTML-escaped characters like & title = WebUtility.HtmlDecode(title); description = WebUtility.HtmlDecode(description); if (url.Contains("&")) url = url.Split('&')[0]; // If the URL contains more stuff in the query string, get rid of it // Separate the JSON string, which is what we need for the download URLs and qualities string jsonString = html.Split(new[] { "ytplayer.config = " }, StringSplitOptions.None)[1]; jsonString = jsonString.Split(new []{"};"}, StringSplitOptions.None)[0] + "}"; // Parse video information from the JSON dynamic json = new JavaScriptSerializer().Deserialize<object>(jsonString); string[] keywords = json["args"]["keywords"].Split(','); string[] adaptive_fmts = json["args"]["adaptive_fmts"].Split(new[] { "," }, StringSplitOptions.None); // Create a dictionary with different qualities, formats and URL's Dictionary<Tuple<FileFormat, AudioBitrate>, string> availableQualities = new Dictionary<Tuple<FileFormat, AudioBitrate>, string>(); foreach (string stream in adaptive_fmts) { if (!stream.Contains("url=")) continue; if (!stream.Contains("itag=")) continue; string formatString = Uri.UnescapeDataString(parseFieldFromQueryString("type", stream)); if(!isAudio(formatString)) continue; string videoURL = Uri.UnescapeDataString(parseFieldFromQueryString("url", stream)); string itag = Uri.UnescapeDataString(parseFieldFromQueryString("itag", stream)); AudioBitrate bitrate = parseBitrate(itag); FileFormat format = parseFormat(formatString); Tuple<FileFormat, AudioBitrate> qualityTuple = Tuple.Create(format, bitrate); if(!availableQualities.ContainsKey(qualityTuple)) availableQualities.Add(qualityTuple, videoURL); } // Download the thumbnail Image thumbnail; using (var http = new HttpClient()) { thumbnail = Image.FromStream(new MemoryStream(await http.GetByteArrayAsync(thumbnailURL))); } // Create the video instance AudioInformation audioInformation = new AudioInformation { URL = url, Title = title, Description = description, Keywords = keywords, Thumbnail = thumbnail, AvailableQualities = availableQualities }; foreach (Tuple<FileFormat, AudioBitrate> qualityTuple in availableQualities.Keys) { Console.WriteLine(qualityTuple.ToString()); } // And return it :) return audioInformation; } catch (Exception ex) { Console.WriteLine(ex.ToString()); return null; } }
//executeDownload(mh.GetCurrentTrack().GetArtistName(), mh.GetCurrentTrack().GetTrackName(), true); private async Task executeDownload(string artist, string name, bool tellIfAlreadyExists = false) { tryNumber = 0; time = 0; startdownload: try { if (downloading) { addToLog("Already downloading a song, ignoring requested download", logBox); return; } downloading = true; string term = artist + " - " + name; //Building search term term = new Regex(string.Format("[{0}]", Regex.Escape(new string(Path.GetInvalidFileNameChars()) + new string(Path.GetInvalidPathChars())))).Replace(term, ""); //Removing any invalid characters? if (string.IsNullOrWhiteSpace(artist) || string.IsNullOrWhiteSpace(name) || mh.IsAdRunning()) //If there is no artist or no name or an ad is running return since theres nothing to download { downloading = false; return; } if (term.Length > 16) if (term.Substring(term.Length - 15).ToLower() == " - original mix") term = term.Substring(0, term.Length - 15); //Remove "Original Mix" if (term.Contains(" - feat")) term = term.Split(new string[] { " - feat" }, StringSplitOptions.None)[0]; //Remove feat lastDownloaded = term; if (!File.Exists(browseForFolderBox.Text + lastDownloaded + ".mp3")) //If the song wasent downloaded to the folder already { addToLog("Searching MP3Clan for term \"" + term + "\"", logBox); string pageSource = client.DownloadString(new Uri(string.Format("http://mp3clan.com/mp3_source.php?q={0}", term.Replace(" ", "+")))); //Perform search and get page source //Perfom a search query in your browser and you can view the source to understand the next line Match trackId = new Regex("<div class=\"mp3list-table\" id=\"(.+?)\">").Match(pageSource); //Checks if div exists in the page source //What is (.+?) if (!trackId.Success || string.IsNullOrWhiteSpace(trackId.Groups[1].Value)) //If there was no match or ...I don't know what is trackId.Groups[1].Value? Is it the ID of the div? { if (tryNumber < 3) //If try number is less than 3, retry download { downloading = false; tryNumber++; addToLog("Could not find TrackID, retrying " + tryNumber + "/3", logBox); goto startdownload; } else //If try number is greater than 3, then skip the download/give up { addToLog("Could not find TrackID, skipping download", logBox); downloading = false; return; } } addToLog("TrackId: " + trackId.Groups[1].Value, logBox); string dlLink = string.Format("http://mp3clan.com/app/get.php?mp3={0}", trackId.Groups[1].Value); addToLog("Downloading from link: " + dlLink, logBox); sw.Start(); //Start the download stopwatch await Task.WhenAll(downloadFileAsync(dlLink, lastDownloaded)); //Download the track } else { if (tellIfAlreadyExists) { addToLog("Song already downloaded", logBox); } downloading = false; } //FIle already downloaded FileInfo fileInfo = new FileInfo(browseForFolderBox.Text + lastDownloaded + ".mp3"); if (fileInfo.Length < 1000000 && retryIfUnder1Mb.Checked) //If length of file is less than 1mb and retry under 1mb is checked then retry download { if (tryNumber < 3) { downloading = false; tryNumber++; if (File.Exists(browseForFolderBox.Text + lastDownloaded + ".mp3")) File.Delete(browseForFolderBox.Text + lastDownloaded + ".mp3"); addToLog("File downloaded was under 1MB, redownloading try " + tryNumber + "/3", logBox); goto startdownload; } else { downloading = false; addToLog(term + " failed to download every try, skipping", logBox); if (Settings.Default.DownloadNotifications) notifyIcon.ShowBalloonTip(3000, "Download error", "The download for \"" + lastDownloaded + "\" failed to download.", ToolTipIcon.Error); } } downloading = false; } catch (Exception e) { downloading = false; tryNumber++; addToLog("Error downloading file, retrying " + tryNumber + "\n" + e.ToString(), logBox); goto startdownload; } }