Пример #1
0
        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);
        }
Пример #2
0
        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();
                    }
                }
            }
        }
Пример #3
0
        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);
        }
Пример #4
0
        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;
        }
Пример #6
0
        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);
            }
        }
Пример #7
0
        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);
            }
        }
Пример #8
0
        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);
            }
        }
Пример #9
0
        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);
        }
Пример #10
0
        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;
                }
            }
        }
Пример #11
0
        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
            });
        }
Пример #13
0
        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);
        }
Пример #14
0
        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());
        }
Пример #15
0
        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);
        }