private static string CheckDirectory(Syousetsu.Constants details, int current) { string path; if (!details.FilenameFormat.Contains('/') && !details.FilenameFormat.Contains('\\')) { path = Path.Combine(Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location), details.SeriesTitle); } else { string[] temp = details.FilenameFormat .Replace("/", "\\") .Split('\\'); temp = temp.Take(temp.Length - 1).ToArray(); string tempFormat = (temp.Length > 1) ? String.Join("\\", temp) : temp[0]; path = Path.Combine(new string[] { Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location), details.SeriesTitle, String.Format(tempFormat, new object[] { current, details.ChapterTitle[current], details.SeriesCode }) }); } if (!Directory.Exists(path)) { Directory.CreateDirectory(path); } return(path); }
private static void DownloadCss(Syousetsu.Constants details, List <string> link) { string cssfile = Path.Combine(details.Path, details.SeriesTitle, details.SeriesCode + ".css"); File.WriteAllText(cssfile, ""); foreach (string f in link) { HttpWebRequest request = (HttpWebRequest)WebRequest.Create(f); request.Method = "GET"; request.UserAgent = Constants.UserAgent; HttpWebResponse response = (HttpWebResponse)request.GetResponse(); var stream = response.GetResponseStream(); using (StreamReader reader = new StreamReader(stream)) { string css = reader.ReadToEnd(); using (StreamWriter writer = File.AppendText(cssfile)) { writer.Write(css); writer.Close(); } } } }
public static void SaveFile(Syousetsu.Constants details, string[] chapter, int current) { string path = CheckDirectory(details, current); //replace illigal character(s) with "□" string regexSearch = new string(Path.GetInvalidFileNameChars()) + new string(Path.GetInvalidPathChars()); Regex r = new Regex(string.Format("[{0}]", System.Text.RegularExpressions.Regex.Escape(regexSearch))); chapter[0] = r.Replace(chapter[0], "□"); //save the chapter string fileName = details.FilenameFormat.Replace("/", "\\") .Split('\\').Last(); if (details.CurrentFileType == Constants.FileType.Text) { fileName = String.Format(fileName + ".txt", new object[] { current, chapter[0], details.SeriesCode }); } else if (details.CurrentFileType == Constants.FileType.HTML) { fileName = String.Format(fileName + ".htm", new object[] { current, chapter[0], details.SeriesCode }); File.WriteAllText(Path.Combine(path, "ChapterStyle.css"), "@charset \"UTF - 8\";\n/*chapter css here*/"); } chapter[0] = String.Empty; fileName = Path.Combine(path, fileName); File.WriteAllLines(fileName, chapter, Encoding.Unicode); }
public static CancellationTokenSource AddDownloadJob(Syousetsu.Constants details, ProgressBar pb) { int max = Convert.ToInt32(pb.Maximum); int i = 0; int upTo = -1; if (details.Start != String.Empty && details.End == String.Empty)//determine if user don't want to start at chapter 1 { i = Convert.ToInt32(details.Start); } else if (details.Start == String.Empty && details.End != String.Empty)//determine if user wants to end at a specific chapter { i = 1; upTo = max; } else if (details.Start != String.Empty && details.End != String.Empty) //determine if user only wants to download a specifc range { i = Convert.ToInt32(details.Start); //get start of the range upTo = max; //get the end of the range } else { i = 1;//if both textbox are blank assume user wants to start from the first chapter "http://*.syosetu.com/xxxxxxx/1" until the latest/last one "http://*.syosetu.com/xxxxxxx/*" } CancellationTokenSource ct = new CancellationTokenSource(); Task.Factory.StartNew(() => { for (int ctr = i; ctr <= max; ctr++) { string subLink = details.Link + ctr; string[] chapter = Create.GenerateContents(details, GetPage(subLink, details.SyousetsuCookie), ctr); Create.SaveFile(details, chapter, ctr); pb.Dispatcher.Invoke((Action)(() => { pb.Value = ctr; })); if (upTo != -1 && ctr > upTo)//stop loop if the specifed range is reached { break; } if (ct.IsCancellationRequested) { // another thread decided to cancel break; } } pb.Dispatcher.Invoke((Action)(() => { pb.Value = max; pb.ToolTip = null; })); }, ct.Token); return(ct); }
private void UpdateCommand_Executed(object sender, ExecutedRoutedEventArgs ea) { Updating = true; UpdateStatus(0); foreach (Syousetsu.History.Item item in viewHistoryList.SelectedItems) { UpdateStatus(+1); Task.Run(() => { if (!item.Finished) { try { Syousetsu.Constants sc = new Syousetsu.Constants(item.Link, null, null); HtmlDocument toc = Syousetsu.Methods.GetTableOfContents(item.Link, sc); if (Syousetsu.Methods.IsValid(toc, sc)) { item.Total = Syousetsu.Methods.GetTotalChapters(toc, sc); Syousetsu.History.SaveItem(item); } else { throw new Exception("Link not valid!" + Environment.NewLine + item.Link); } } catch (Exception e) { MessageBox.Show(e.Message, "ERROR", MessageBoxButton.OK, MessageBoxImage.Error); } } } ) .ContinueWith(delegate { UpdateStatus(-1); } , TaskScheduler.FromCurrentSynchronizationContext()); } // Updating = true; // var item = GetCurrentItem(); // Syousetsu.Constants sc = new Syousetsu.Constants(item.Link, null); // HtmlDocument toc = Syousetsu.Methods.GetTableOfContents(item.Link, sc); // if (!Syousetsu.Methods.IsValid(toc, sc)) // { // MessageBox.Show("Link not valid!", "Error", MessageBoxButton.OK, MessageBoxImage.Error); // goto updateCommand_end; // } // item.Total = Syousetsu.Methods.GetTotalChapters(toc, sc); // Syousetsu.History.SaveItem(item); //updateCommand_end: // Updating = false; }
static void Main(string[] args) { Options o = new Options(); if (args.Any()) { /* do stuff without a GUI */ Parser.Default.ParseArguments(args, o); if (o.Help == true) { Console.WriteLine(CommandLine.Text.HelpText.AutoBuild(o)); return; } o.Link = o.Link.Trim(' ', '\t', '\n', '\v', '\f', '\r', '"', '\''); Syousetsu.Constants sc = new Syousetsu.Constants(); HtmlDocument toc = Syousetsu.Methods.GetTableOfContents(o.Link, sc.SyousetsuCookie); sc.Chapters.Add(""); sc.SeriesTitle = Syousetsu.Methods.GetTitle(toc); sc.Link = o.Link; sc.Start = o.Start; sc.End = String.IsNullOrWhiteSpace(o.End) ? Syousetsu.Methods.GetTotalChapters(toc).ToString() : o.End; sc.SeriesCode = Syousetsu.Methods.GetSeriesCode(o.Link); sc.FilenameFormat = GetFilenameFormat(); Syousetsu.Methods.GetAllChapterTitles(sc, toc); Syousetsu.Constants.FileType fileType = Syousetsu.Constants.FileType.Text; switch (o.Format.ToUpper()) { case "HTML": { fileType = Syousetsu.Constants.FileType.HTML; break; } case "TXT": { fileType = Syousetsu.Constants.FileType.Text; break; } default: { fileType = Syousetsu.Constants.FileType.Text; break; } } sc.CurrentFileType = fileType; Syousetsu.Methods.GetAllChapterTitles(sc, toc); if (o.ToC == true) { Syousetsu.Create.GenerateTableOfContents(sc, toc); } System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch(); sw.Start(); Syousetsu.Methods.AddDownloadJob(sc); sw.Stop(); Console.WriteLine(sw.Elapsed); } }
public static void GetAllChapterTitles(Syousetsu.Constants details, HtmlDocument doc) { //edit all href HtmlNodeCollection chapterNode = doc.DocumentNode.SelectNodes("//div[@class='index_box']/dl[@class='novel_sublist2']"); foreach (HtmlNode node in chapterNode) { //get current chapter number string pattern = "(href=\"/)(?<series>.+)/(?<num>.+)/\">(?<title>.+)(?=</a>)"; Regex r = new Regex(pattern); Match m = r.Match(node.ChildNodes["dd"].OuterHtml); int current = Convert.ToInt32(m.Groups["num"].Value); details.ChapterTitle.Add(m.Groups["title"].Value); } }
private static void DownloadCss(Syousetsu.Constants details, string link) { HttpWebRequest request = (HttpWebRequest)WebRequest.Create(link); request.Method = "GET"; request.UserAgent = Constants.UserAgent; HttpWebResponse response = (HttpWebResponse)request.GetResponse(); var stream = response.GetResponseStream(); using (StreamReader reader = new StreamReader(stream)) { string css = reader.ReadToEnd(); File.WriteAllText(Path.Combine(details.Path, details.SeriesTitle, details.SeriesCode + ".css"), css); } }
public static string[] GenerateContents(Syousetsu.Constants details, HtmlDocument doc, int current) { string[] chapter = new string[2]; if (details.CurrentFileType == Constants.FileType.Text) { chapter[0] = Methods.GetChapterTitle(doc).TrimStart().TrimEnd(); chapter[1] = Methods.GetNovelHeader(doc, details.CurrentFileType); chapter[1] += chapter[0]; chapter[1] += Methods.GetNovelBody(doc, details.CurrentFileType); if (doc.DocumentNode.SelectSingleNode("//div[@id='novel_honbun']").InnerHtml.Contains("<img")) { string subLink = String.Format("{0}{1}", details.Link, current); chapter[1] += String.Format("\n\n===\n\nContains image(s): {0}\n\n===", subLink); } } else if (details.CurrentFileType == Constants.FileType.HTML) { chapter[0] = Methods.GetChapterTitle(doc).TrimStart().TrimEnd(); chapter[1] = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"; chapter[1] += "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\"\n"; chapter[1] += "\"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">\n\n"; chapter[1] += "<html xmlns=\"http://www.w3.org/1999/xhtml\">\n"; chapter[1] += "<head>\n"; chapter[1] += $"\t<title>{Methods.GetChapterTitle(doc).TrimStart().TrimEnd()}" + $" ({current}) {details.SeriesTitle}</title>\n"; chapter[1] += "\t<link href=\"ChapterStyle.css\" rel=\"stylesheet\" type=\"text/css\" />\n"; chapter[1] += "</head>\n"; chapter[1] += "<body>\n "; chapter[1] += Methods.GetNovelHeader(doc, details.CurrentFileType); chapter[1] += "\n<h2>" + chapter[0] + "</h2>\n\n"; chapter[1] += Methods.GetNovelBody(doc, details.CurrentFileType); if (doc.DocumentNode.SelectSingleNode("//div[@id='novel_honbun']").InnerHtml.Contains("<img")) { string subLink = String.Format("{0}{1}", details.Link, current); chapter[1] += String.Format("\n\n===\n\n<a href=\"{0}\">Contains image(s)</a>\n\n===", subLink); } } return(chapter); }
public static void AddDownloadJob(Syousetsu.Constants details) { int max = Convert.ToInt32(details.End); int i = 0; int upTo = -1; if (details.Start != String.Empty && details.End == String.Empty)//determine if user don't want to start at chapter 1 { i = Convert.ToInt32(details.Start); } else if (details.Start == String.Empty && details.End != String.Empty)//determine if user wants to end at a specific chapter { i = 1; upTo = max; } else if (details.Start != String.Empty && details.End != String.Empty) //determine if user only wants to download a specifc range { i = Convert.ToInt32(details.Start); //get start of the range upTo = max; //get the end of the range } else { i = 1;//if both textbox are blank assume user wants to start from the first chapter "http://*.syosetu.com/xxxxxxx/1" until the latest/last one "http://*.syosetu.com/xxxxxxx/*" } for (int ctr = i; ctr <= max; ctr++) { string subLink = details.Link + ctr; string[] chapter = Create.GenerateContents(details, GetPage(subLink, details.SyousetsuCookie), ctr); Create.SaveFile(details, chapter, ctr); if (upTo != -1 && ctr > upTo)//stop loop if the specifed range is reached { break; } } }
public static void GenerateTableOfContents(Syousetsu.Constants details, HtmlDocument doc) { //create novel folder if it doesn't exist CheckDirectory(details); HtmlNode tocNode = doc.DocumentNode.SelectSingleNode("//div[@class='index_box']"); HtmlNodeCollection cssNodeList = doc.DocumentNode.SelectNodes("//link[@rel='stylesheet']"); var cssNode = (from n in cssNodeList where n.Attributes["href"].Value.Contains("ncout.css") || n.Attributes["href"].Value.Contains("ncout2.css") select n).ToList(); //get css link and download string pattern = "(href=\")(?<link>.+)(?=\" media)"; Regex r = new Regex(pattern); Match m = r.Match(cssNode[0].OuterHtml); string cssink = m.Groups["link"].Value; DownloadCss(details, cssink); StringBuilder sb = new StringBuilder(); sb.AppendLine("<html>"); sb.AppendLine("<head>"); sb.AppendLine("\t<meta charset=\"UTF-8\">"); sb.AppendLine("\t<link rel=\"stylesheet\" type=\"text/css\" href=\"" + details.SeriesCode + ".css\" media=\"screen,print\" />"); sb.AppendLine("</head>"); sb.AppendLine("<body>"); //edit all href int i = 1; HtmlNodeCollection chapterNode = doc.DocumentNode.SelectNodes("//div[@class='index_box']/dl[@class='novel_sublist2']"); foreach (HtmlNode node in chapterNode) { //get current chapter number pattern = "(href=\"/)(?<series>.+)/(?<num>.+)/\">(?<title>.+)(?=</a>)"; r = new Regex(pattern); m = r.Match(node.ChildNodes["dd"].OuterHtml); int current = Convert.ToInt32(m.Groups["num"].Value); details.ChapterTitle.Add(m.Groups["title"].Value); //edit href string fileName = details.FilenameFormat; fileName = String.Format(fileName + ".htm", current, details.ChapterTitle[current], details.SeriesCode); node.ChildNodes["dd"].ChildNodes["a"].Attributes["href"].Value = "./" + fileName; if (i <= Convert.ToInt32(details.End)) { CheckDirectory(details, current); } i++; } sb.AppendLine(tocNode.OuterHtml); sb.AppendLine("</body>"); sb.AppendLine("</html>"); File.WriteAllText(Path.Combine(details.Path, details.SeriesTitle, details.SeriesCode + ".htm"), sb.ToString()); }
private void btnDownload_Click(object sender, RoutedEventArgs e) { this._link = txtLink.Text; this._start = txtFrom.Text; this._end = txtTo.Text; bool fromToValid = (System.Text.RegularExpressions.Regex.IsMatch(_start, @"^\d+$") || _start.Equals(String.Empty)) && (System.Text.RegularExpressions.Regex.IsMatch(_end, @"^\d+$") || _end.Equals(String.Empty)); if (String.IsNullOrWhiteSpace(_link) && fromToValid) { MessageBox.Show("Error parsing link and/or chapter range!", "", MessageBoxButton.OK, MessageBoxImage.Error); } if (!_link.StartsWith("http")) { _link = @"http://" + _link; } if (!_link.EndsWith("/")) { _link += "/"; } if (!Syousetsu.Methods.IsValidLink(_link)) { MessageBox.Show("Link not valid!", "Error", MessageBoxButton.OK, MessageBoxImage.Error); } Syousetsu.Constants sc = new Syousetsu.Constants(); sc.ChapterTitle.Add(""); HtmlDocument toc = Syousetsu.Methods.GetTableOfContents(_link, sc.SyousetsuCookie); if (!Syousetsu.Methods.IsValid(toc)) { MessageBox.Show("Link not valid!", "Error", MessageBoxButton.OK, MessageBoxImage.Error); } GetFilenameFormat(); _row += 1; Label lb = new Label(); lb.Content = Syousetsu.Methods.GetTitle(toc); lb.ToolTip = "Click to open folder"; ProgressBar pb = new ProgressBar(); pb.Maximum = (_end == String.Empty) ? Syousetsu.Methods.GetTotalChapters(toc) : Convert.ToDouble(_end); pb.ToolTip = "Click to stop download"; pb.Height = 10; pb.Tag = 0; Separator s = new Separator(); s.Height = 5; _start = (_start == String.Empty) ? "1" : _start; _end = pb.Maximum.ToString(); sc.SeriesTitle = lb.Content.ToString(); sc.Link = _link; sc.Start = _start; sc.End = _end; sc.CurrentFileType = _fileType; sc.SeriesCode = Syousetsu.Methods.GetSeriesCode(_link); sc.FilenameFormat = _format; Syousetsu.Methods.GetAllChapterTitles(sc, toc); if (chkList.IsChecked == true) { Syousetsu.Create.GenerateTableOfContents(sc, toc); } System.Threading.CancellationTokenSource ct = Syousetsu.Methods.AddDownloadJob(sc, pb, lb); pb.MouseDown += (snt, evt) => { ct.Cancel(); pb.ToolTip = null; }; lb.MouseDown += (snt, evt) => { string path = System.IO.Path.Combine(System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location), sc.SeriesTitle); if (System.IO.Directory.Exists(path)) { System.Diagnostics.Process.Start("explorer.exe", path); } }; stackPanel1.Children.Add(lb); stackPanel1.Children.Add(pb); stackPanel1.Children.Add(s); scrollViewer1.ScrollToLeftEnd(); scrollViewer1.ScrollToBottom(); scrollViewer1.Dispatcher.Invoke(DispatcherPriority.Render, EmptyDelegate); _controls.Add(new Syousetsu.Controls { ID = _row, Label = lb, ProgressBar = pb, Separator = s }); }
private void Download() { this._link = txtLink.Text; this._start = txtFrom.Text; this._end = txtTo.Text; bool fromToValid = (System.Text.RegularExpressions.Regex.IsMatch(_start, @"^\d+$") || _start.Equals(String.Empty)) && (System.Text.RegularExpressions.Regex.IsMatch(_end, @"^\d+$") || _end.Equals(String.Empty)); if (String.IsNullOrWhiteSpace(_link) && fromToValid) { MessageBox.Show("Error parsing link and/or chapter range!", "", MessageBoxButton.OK, MessageBoxImage.Error); } if (!_link.StartsWith("http")) { _link = @"http://" + _link; } if (Syousetsu.Constants.Site(_link) == Syousetsu.Constants.SiteType.Syousetsu) // syousetsu { if (!_link.EndsWith("/")) { _link += "/"; } } if (!Syousetsu.Methods.IsValidLink(_link)) { MessageBox.Show("Link not valid!", "Error", MessageBoxButton.OK, MessageBoxImage.Error); } Syousetsu.Constants sc = new Syousetsu.Constants(_link, _exe_dir, _dl_dir); sc.AddChapter("", ""); // start chapters from 1 HtmlDocument toc = Syousetsu.Methods.GetTableOfContents(_link, sc); if (!Syousetsu.Methods.IsValid(toc, sc)) { MessageBox.Show("Link not valid!", "Error", MessageBoxButton.OK, MessageBoxImage.Error); } GetFilenameFormat(); // set up download progress gui-controls Label lb = _controls.Last().Label; lb.Content = Syousetsu.Methods.GetTitle(toc, sc); lb.Background = Brushes.Transparent; lb.ToolTip = "Click to open folder"; ProgressBar pb = _controls.Last().ProgressBar; pb.Maximum = (_end == String.Empty) ? Syousetsu.Methods.GetTotalChapters(toc, sc) : Convert.ToDouble(_end); pb.ToolTip = "Click to stop download"; _start = (_start == String.Empty) ? "1" : _start; _end = pb.Maximum.ToString(); sc.SeriesTitle = lb.Content.ToString(); sc.Link = _link; sc.Start = _start; sc.End = _end; sc.CurrentFileType = _fileType; sc.SeriesCode = Syousetsu.Methods.GetSeriesCode(_link); sc.FilenameFormat = _format; Syousetsu.Methods.GetAllChapterTitles(sc, toc); if (chkList.IsChecked == true) { Syousetsu.Create.GenerateTableOfContents(sc, toc); } System.Threading.CancellationTokenSource ct = Syousetsu.Methods.AddDownloadJob(sc, pb, lb); pb.MouseDown += (snt, evt) => { ct.Cancel(); pb.ToolTip = null; }; lb.MouseDown += (snt, evt) => { _shell.Explore(System.IO.Path.Combine(_dl_dir, sc.SeriesTitle)); }; scrollViewer1.ScrollToLeftEnd(); scrollViewer1.ScrollToBottom(); scrollViewer1.Dispatcher.Invoke(DispatcherPriority.Render, EmptyDelegate); }
public static void GenerateTableOfContents(Syousetsu.Constants details, HtmlDocument doc) { //create novel folder if it doesn't exist CheckDirectory(details); HtmlNode ptitleNode; // page title HtmlNode stitleNode; // series title HtmlNode titleNode; // novel title HtmlNode writerNode; // author HtmlNode tocNode; // table of contents if (details.Site() == Constants.SiteType.Syousetsu) { ptitleNode = doc.DocumentNode.SelectSingleNode("//title"); stitleNode = doc.DocumentNode.SelectSingleNode("//p[@class='series_title']"); titleNode = doc.DocumentNode.SelectSingleNode("//p[@class='novel_title']"); writerNode = doc.DocumentNode.SelectSingleNode("//div[@class='novel_writername']"); tocNode = doc.DocumentNode.SelectSingleNode("//div[@class='index_box']"); } else // kakuyomu { ptitleNode = doc.DocumentNode.SelectSingleNode("//title"); stitleNode = null; titleNode = doc.DocumentNode.SelectSingleNode("//h1[@id='workTitle']"); writerNode = doc.DocumentNode.SelectSingleNode("//h2[@id='workAuthor']"); tocNode = doc.DocumentNode.SelectSingleNode("//section[@class='widget-toc']"); // remove left header tocNode.ChildNodes["header"].Remove(); } HtmlNodeCollection cssNodeList = doc.DocumentNode.SelectNodes("//link[@rel='stylesheet']"); var cssNode = (from n in cssNodeList where n.Attributes["href"].Value.Contains("ncout.css") || n.Attributes["href"].Value.Contains("ncout2.css") || n.Attributes["href"].Value.Contains("kotei.css") || // ... n.Attributes["href"].Value.Contains("reset.css") || // syousetsu n.Attributes["href"].Value.Contains("kakuyomu.css") // kakuyomu select n).ToList(); //get css link and download List <string> cssink = new List <string>(); string pattern; Regex r; Match m; foreach (HtmlNode node in cssNode) { if (details.Site() == Constants.SiteType.Syousetsu) // syousetsu { pattern = "(href=\")(?<link>.+)(?=\" media)"; } else // kakuyomu { pattern = "(href=\")(?<link>.+)(?=\">)"; } r = new Regex(pattern); m = r.Match(node.OuterHtml); cssink.Add(m.Groups["link"].Value); } DownloadCss(details, cssink); StringBuilder sb = new StringBuilder(); sb.AppendLine("<html>"); sb.AppendLine("<head>"); sb.AppendLine("\t<meta charset=\"UTF-8\">"); sb.AppendLine("\t<link rel=\"stylesheet\" type=\"text/css\" href=\"" + details.SeriesCode + ".css\" media=\"screen,print\" />"); if (ptitleNode != null) { sb.AppendLine(ptitleNode.OuterHtml); } sb.AppendLine("</head>"); if (details.Site() == Constants.SiteType.Syousetsu) // syousetsu { sb.AppendLine("<body>"); } else // kakuyomu { // copy <body> as is for it's id HtmlNode body = doc.DocumentNode.SelectSingleNode("//body"); sb.AppendLine(body.OuterHtml.Substring(0, body.OuterHtml.IndexOf('>') + 1)); } // restore header links if (stitleNode != null) // syousetsu { if (null != stitleNode.ChildNodes["a"] && null != stitleNode.ChildNodes["a"].Attributes["href"]) { var href = stitleNode.ChildNodes["a"].Attributes["href"].Value; if (!string.IsNullOrEmpty(href)) { stitleNode.ChildNodes["a"].Attributes["href"].Value = "https://ncode.syosetu.com" + href; } } sb.AppendLine(stitleNode.OuterHtml); } else // kakuyomu { HtmlNode title_node = doc.DocumentNode.SelectSingleNode("//h1[@id='workTitle']/a"); HtmlNode author_node = doc.DocumentNode.SelectSingleNode("//h2[@id='workAuthor']/span[@id='workAuthor-activityName']/a"); if (title_node != null) { string s = null; s = title_node.Attributes["href"]?.Value; if (!string.IsNullOrEmpty(s)) { title_node.Attributes["href"].Value = "https://kakuyomu.jp" + s; } } if (author_node != null) { string s = null; s = author_node.Attributes["href"]?.Value; if (!string.IsNullOrEmpty(s)) { author_node.Attributes["href"].Value = "https://kakuyomu.jp" + s; } } } if (titleNode != null) { sb.AppendLine(titleNode.OuterHtml); } if (writerNode != null) { sb.AppendLine(writerNode.OuterHtml); } //edit all href int i = 1; HtmlNodeCollection chapterNode; if (details.Site() == Constants.SiteType.Syousetsu) // syousetsu { chapterNode = doc.DocumentNode.SelectNodes("//div[@class='index_box']/dl[@class='novel_sublist2']"); } else // kakuyomu { chapterNode = doc.DocumentNode.SelectNodes("//section[@class='widget-toc']/div[@class='widget-toc-main']/ol/li[@class='widget-toc-episode']"); } foreach (HtmlNode node in chapterNode) { //get current chapter number if (details.Site() == Constants.SiteType.Syousetsu) // syousetsu { pattern = "(href=\"/)(?<series>.+)/(?<num>.+)/\">(?<title>.+)(?=</a>)"; r = new Regex(pattern); m = r.Match(node.ChildNodes["dd"].OuterHtml); //int current = Convert.ToInt32(m.Groups["num"].Value); //edit href string fileName = details.FilenameFormat; fileName = String.Format(fileName + ".htm", i, details.GetChapterByIndex(i).title, details.SeriesCode); node.ChildNodes["dd"].ChildNodes["a"].Attributes["href"].Value = "./" + fileName; node.ChildNodes["dd"].ChildNodes["a"].InnerHtml = "(" + i + ") " + node.ChildNodes["dd"].ChildNodes["a"].InnerHtml; } else // kakuyomu { pattern = "(href=\"/works/)(?<series>.+)/episodes/(?<num>.+)\" class.+item\">(?<title>.+)(?=</span>)"; r = new Regex(pattern); m = r.Match(node.OuterHtml); //edit href string fileName = details.FilenameFormat; fileName = String.Format(fileName + ".htm", i, details.GetChapterByIndex(i).title, details.SeriesCode); node.ChildNodes["a"].Attributes["href"].Value = "./" + fileName; node.ChildNodes["a"].ChildNodes["span"].InnerHtml = "(" + i + ") " + node.ChildNodes["a"].ChildNodes["span"].InnerHtml; } if (i <= Convert.ToInt32(details.End)) { CheckDirectory(details, i); } i++; } sb.AppendLine(tocNode.OuterHtml); sb.AppendLine("</body>"); sb.AppendLine("</html>"); File.WriteAllText(Path.Combine(details.Path, details.SeriesTitle, details.SeriesCode + ".htm"), sb.ToString()); }
public static CancellationTokenSource AddDownloadJob(Syousetsu.Constants details, ProgressBar pb, Label lb) { int max = Convert.ToInt32(pb.Maximum); int i = 0; int upTo = -1; if (details.Start != String.Empty && details.End == String.Empty)//determine if user don't want to start at chapter 1 { i = Convert.ToInt32(details.Start); } else if (details.Start == String.Empty && details.End != String.Empty)//determine if user wants to end at a specific chapter { i = 1; upTo = max; } else if (details.Start != String.Empty && details.End != String.Empty) //determine if user only wants to download a specifc range { i = Convert.ToInt32(details.Start); //get start of the range upTo = max; //get the end of the range } else { i = 1;//if both textbox are blank assume user wants to start from the first chapter "http://*.syosetu.com/xxxxxxx/1" until the latest/last one "http://*.syosetu.com/xxxxxxx/*" } CancellationTokenSource ct = new CancellationTokenSource(); Task.Factory.StartNew(() => { bool cancelled = false; for (int ctr = i; ctr <= max; ctr++) { string subLink; if (details.Site() == Constants.SiteType.Syousetsu) // syousetsu { subLink = details.Link + ctr; } else // kakuyomu { subLink = details.Link + "/episodes/" + details.GetChapterByIndex(ctr).number; } string[] chapter = Create.GenerateContents(details, GetPage(subLink, details), ctr); Create.SaveFile(details, chapter, ctr); // update downloaded history details.LastDownloaded = ctr; History.SaveNovel(details); pb.Dispatcher.Invoke((Action)(() => { pb.Value = ctr; })); if (upTo != -1 && ctr > upTo)//stop loop if the specifed range is reached { break; } if (ct.IsCancellationRequested) { // another thread decided to cancel cancelled = true; break; } } pb.Dispatcher.Invoke((Action)(() => { //pb.Value = max; pb.ToolTip = null; pb.Tag = 1; if (cancelled) { lb.Content = "download aborted - " + lb.Content; //lb.Background = Brushes.MistyRose; } else { pb.Value = max; lb.Content = "finished - " + lb.Content; //lb.Background = Brushes.Aquamarine; } })); }, ct.Token); return(ct); }