diff --git a/src/checker/chapterChecker.java b/src/checker/chapterChecker.java deleted file mode 100644 index 1b7150b..0000000 --- a/src/checker/chapterChecker.java +++ /dev/null @@ -1,211 +0,0 @@ -package checker; - -import grabber.HostSettings; -import gui.GUI; -import org.json.simple.JSONArray; -import org.json.simple.JSONObject; -import org.json.simple.parser.JSONParser; -import org.json.simple.parser.ParseException; -import org.jsoup.Jsoup; -import org.jsoup.nodes.Document; -import org.jsoup.select.Elements; - -import java.awt.*; -import java.io.File; -import java.io.FileReader; -import java.io.FileWriter; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Comparator; -import java.util.List; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.TimeUnit; - -import static java.lang.Math.toIntExact; - -public class chapterChecker { - public static List hosts = new ArrayList<>(); - public static List urls = new ArrayList<>(); - private static List lastChapters; - private static List toBeRemoved; - private static ScheduledExecutorService service; - private static final int pollingInterval = 20; - public static boolean checkerRunning; - private static boolean taskIsKilled; - private static String curTitle; - private static String latestChapterListFile; - - - //checker handling. - public static void chapterPolling(GUI mygui) { - taskIsKilled = false; - checkerRunning = true; - lastChapters = new ArrayList<>(); - toBeRemoved = new ArrayList<>(); - - latestChapterListFile = GUI.appdataPath + File.separator + "lastChapters_" + urls.hashCode() + ".json"; - File file = new File(latestChapterListFile); - if (file.exists()) { - readDataFromJSON(); - } else { - initializeFile(mygui); - } - if (urls.isEmpty()) { - mygui.appendText("checker", "No checkers defined."); - mygui.stopPolling(); - mygui.resetCheckerGUIButtons(); - return; - } - if (lastChapters.contains(-1)) { - mygui.appendText("checker", "Could not reach one or more hosts."); - mygui.stopPolling(); - mygui.resetCheckerGUIButtons(); - return; - } - // Updates checker list on gui with chapter numbers. - for (int i = 0; i < urls.size(); i++) { - GUI.listModelCheckerLinks.set(i, "Latest chapter: " + lastChapters.get(i) + " / [" + urls.get(i) + "]"); - } - // Runs every set interval. - Runnable runnable = () -> { - try { - for (int i = 0; i < urls.size(); i++) { - if (!taskIsKilled) { - Thread.sleep((int) (Math.random() * 3001 + 2000)); - mygui.appendText("checker", "Polling: " + urls.get(i)); - int newChapter = countChapters(hosts.get(i), urls.get(i)); - if (newChapter > lastChapters.get(i)) { - if (newChapter - lastChapters.get(i) > 1) { - mygui.appendText("checker", newChapter - lastChapters.get(i) + " new chapters."); - showNotification(curTitle + ": " + (newChapter - lastChapters.get(i)) + " new chapters."); - } else { - mygui.appendText("checker", "New chapter: " + newChapter); - showNotification(curTitle + ": " + newChapter); - } - lastChapters.add(i, newChapter); - writeDataToJSON(latestChapterListFile, true); - GUI.listModelCheckerLinks.set(i, "Latest chapter: " + newChapter + " / [" + curTitle + "]"); - } - } - } - if (!taskIsKilled) - mygui.appendText("checker", "Polling again in " + pollingInterval + " minutes."); - } catch (IllegalArgumentException | InterruptedException e) { - e.printStackTrace(); - } - }; - // Start scheduled task. - if (!taskIsKilled) { - mygui.checkStatusLbl.setText("Checking active."); - mygui.checkStopPollingBtn.setEnabled(true); - service = Executors.newSingleThreadScheduledExecutor(); - service.scheduleAtFixedRate(runnable, 0, pollingInterval, TimeUnit.MINUTES); - } else { - mygui.appendText("checker", "Stopping polling."); - mygui.stopPolling(); - } - } - - /** - * Creates and fills a file for a new list of Checkers. - */ - private static void initializeFile(GUI mygui) { - mygui.checkStatusLbl.setText("Initializing..."); - // Gets chapter count for each checker entry. - for (int i = 0; i < urls.size(); i++) { - try { - mygui.appendText("checker", "Initializing: " + urls.get(i)); - lastChapters.add(countChapters(hosts.get(i), urls.get(i))); - Thread.sleep(3000); - } catch (IllegalArgumentException e) { - toBeRemoved.add(i); - } catch (InterruptedException e) { - e.printStackTrace(); - } - } - // Remove faulty entries. - toBeRemoved.sort(Comparator.reverseOrder()); - for (int a : toBeRemoved) { - mygui.appendText("checker", "Removing faulty: " + urls.get(a)); - urls.remove(a); - hosts.remove(a); - GUI.listModelCheckerLinks.removeElementAt(a); - } - toBeRemoved.clear(); - // Create a new file to store latest chapter numbers. File name is the hashCode() of Listurls. - if (!urls.isEmpty()) { - latestChapterListFile = GUI.appdataPath + File.separator + "lastChapters_" + urls.hashCode() + ".json"; - writeDataToJSON(latestChapterListFile, true); - } - } - - /** - * Reads latest chapter numbers from existing file. - */ - private static void readDataFromJSON() { - JSONParser parser = new JSONParser(); - try { - JSONArray a = (JSONArray) parser.parse(new FileReader(latestChapterListFile)); - for (Object o : a) { - JSONObject checker = (JSONObject) o; - lastChapters.add(toIntExact((Long) checker.get("CHAPTER"))); - } - } catch (IOException | ParseException e) { - e.printStackTrace(); - } - } - - public static void writeDataToJSON(String filepath, boolean withChapters) { - JSONArray array = new JSONArray(); - for (int i = 0; i < hosts.size(); i++) { - JSONObject checker = new JSONObject(); - if (withChapters) checker.put("CHAPTER", lastChapters.get(i)); - checker.put("HOST", hosts.get(i)); - checker.put("URL", urls.get(i)); - array.add(checker); - } - try (FileWriter JSONfile = new FileWriter(filepath)) { - JSONfile.write(array.toJSONString()); - } catch (IOException e) { - e.printStackTrace(); - } - } - - public static void killTask(GUI mygui) { - if (!(service == null)) { - taskIsKilled = true; - service.shutdown(); - try { - if (!service.awaitTermination(800, TimeUnit.MINUTES)) { - service.shutdownNow(); - } - } catch (InterruptedException e) { - service.shutdownNow(); - } - mygui.appendText("checker", "Stopped polling."); - mygui.resetCheckerGUIButtons(); - } - } - - private static int countChapters(String host, String tocUrl) { - HostSettings currHostSettings = new HostSettings(host, tocUrl); - try { - Document doc = Jsoup.connect(currHostSettings.url).timeout(30 * 1000).get(); - curTitle = doc.title(); - Elements chapterItems = doc.select(currHostSettings.chapterLinkSelecter); - return chapterItems.size(); - } catch (IOException e) { - e.printStackTrace(); - return -1; - } - } - - private static void showNotification(String message) { - try { - GUI.trayIcon.displayMessage("Novel-Grabber: Chapter release", message, TrayIcon.MessageType.INFO); - } catch (Exception e) { - e.printStackTrace(); - } - } -} diff --git a/src/files/about.txt b/src/files/about.txt index 17eec57..01ec821 100644 --- a/src/files/about.txt +++ b/src/files/about.txt @@ -1,31 +1,31 @@ -Author: Flameish -GitHub: https://github.com/Flameish - -MIT License - -Copyright (c) 2019 Flameish - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - -CREDITS: - - json.simple https://code.google.com/archive/p/json-simple/ - - jsoup https://jsoup.org/ - - webdrivermanager https://github.com/bonigarcia/webdrivermanager - - selenium https://selenium.dev/ +Author: Flameish +GitHub: https://github.com/Flameish + +MIT License + +Copyright (c) 2019 Flameish + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +CREDITS: + - json.simple https://code.google.com/archive/p/json-simple/ + - jsoup https://jsoup.org/ + - webdrivermanager https://github.com/bonigarcia/webdrivermanager + - selenium https://selenium.dev/ - Images https://icons8.com/ \ No newline at end of file diff --git a/src/files/default.css b/src/files/default.css index 5420ce1..287884b 100644 --- a/src/files/default.css +++ b/src/files/default.css @@ -1,710 +1,710 @@ -/* credit: @mattharrison https://github.com/mattharrison/epub-css-starter-kit */ -/* This assumes geometric header shrinkage */ -/* Also, it tries to make h2 be 1em */ -html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, big, cite, code, del, dfn, em, img, ins, kbd, q, s, samp, small, strike, strong, sub, sup, tt, var, b, u, i, center, dl, dt, dd, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td, article, aside, canvas, details, embed, figure, figcaption, footer, header, hgroup, menu, nav, output, ruby, section, summary, time, mark, audio, video { - /* Note kindle hates margin:0 ! (or margin-left or margin-top set) it inserts newlines galore */ - /* margin: 0 */ - margin-right: 0; - padding: 0; - border: 0; - font-size: 100%; - /* font: inherit */ - vertical-align: baseline; } - -/* optimal sizing see http://demosthenes.info/blog/578/Crafting-Optimal-Type-Sizes-For-Web-Pages */ -/* kobo and nook dislike this */ -/* */ -/*html */ -/* font-size: 62.5% */ -/*body */ -/* font-size: 1.6rem */ -/* line-height: 2.56rem */ -/* text-rendering: optimizeLegibility */ -table { - border-collapse: collapse; - border-spacing: 0; } - -/* end reset */ -@page { - margin-top: 30px; - margin-bottom: 20px; } - -div.cover { - text-align: center; - page-break-after: always; - padding: 0px; - margin: 0px; } - div.cover img { - height: 100%; - max-width: 100%; - padding: 10px; - margin: 0px; - background-color: #cccccc; } - -.half { - max-width: 50%; } - -.tenth { - max-width: 10%; - width: 10%; } - -.cover-img { - height: 100%; - max-width: 100%; - padding: 0px; - margin: 0px; } - -/* font plan- serif text, sans headers */ -h1, h2, h3, h4, h5, h6 { - hyphens: none !important; - -moz-hyphens: none !important; - -webkit-hyphens: none !important; - adobe-hyphenate: none !important; - page-break-after: avoid; - page-break-inside: avoid; - text-indent: 0px; - text-align: left; - font-family: Helvetica, Arial, sans-serif; } - -h1 { - font-size: 1.6em; - margin-bottom: 3.2em; } - -.title h1 { - margin-bottom: 0px; - margin-top: 3.2em; } - -h2 { - font-size: 1em; - margin-top: 0.5em; - margin-bottom: 0.5em; } - -h3 { - font-size: 0.625em; } - -h4 { - font-size: 0.391em; } - -h5 { - font-size: 0.244em; } - -h6 { - font-size: 0.153em; } - -/* Do not indent first paragraph. Mobi will need class='first-para' */ -h1 + p, h2 + p, h3 + p, h4 + p, h5 + p, h6 + p { - text-indent: 0; } - -p { - /* paperwhite defaults to sans */ - font-family: "Palatino", "Times New Roman", Caecilia, serif; - -webkit-hyphens: auto; - -moz-hyphens: auto; - hyphens: auto; - hyphenate-after: 3; - hyphenate-before: 3; - hyphenate-lines: 2; - -webkit-hyphenate-after: 3; - -webkit-hyphenate-before: 3; - -webkit-hyphenate-lines: 2; - line-height: 1.5em; - margin: 0; - text-align: justify; - text-indent: 1em; - orphans: 2; - widows: 2; } - p.first-para, p.first-para-chapter, p.note-p-first { - text-indent: 0; } - p.first-para-chapter::first-line { - /* handle run-in */ - font-variant: small-caps; } - p.no-indent { - text-indent: 0; } - -.no-hyphens { - hyphens: none !important; - -moz-hyphens: none !important; - -webkit-hyphens: none !important; - adobe-hyphenate: none !important; } - -.rtl { - direction: rtl; - float: right; } - -.drop { - overflow: hidden; - line-height: 89%; - height: 0.8em; - font-size: 281%; - margin-right: 0.075em; - float: left; } - -.dropcap { - line-height: 100%; - font-size: 341%; - margin-right: 0.075em; - margin-top: -0.22em; - float: left; - height: 0.8em; } - -/* lists */ -ul, ol, dl { - margin: 1em 0 1em 0; - text-align: left; } - -li { - font-family: "Palatino", "Times New Roman", Caecilia, serif; - line-height: 1.5em; - orphans: 2; - widows: 2; - text-align: justify; - text-indent: 0; - margin: 0; } - li p { - /* Fix paragraph indenting inside of lists */ - text-indent: 0em; } - -dt { - font-weight: bold; - font-family: Helvetica, Arial, sans-serif; } - -dd { - line-height: 1.5em; - font-family: "Palatino", "Times New Roman", Caecilia, serif; } - dd p { - /* Fix paragraph indenting inside of definition lists */ - text-indent: 0em; } - -blockquote { - margin-left: 1em; - margin-right: 1em; - line-height: 1.5em; - font-style: italic; } - blockquote p.first-para, blockquote p { - text-indent: 0; } - -pre, tt, code, samp, kbd { - font-family: "Courier New", Courier, monospace; - word-wrap: break-word; } - -pre { - font-size: 0.8em; - line-height: 1.2em; - margin-left: 1em; - /* margin-top: 1em */ - margin-bottom: 1em; - white-space: pre-wrap; - display: block; } - -img { - border-radius: 0.3em; - -webkit-border-radius: 0.3em; - -webkit-box-shadow: rgba(0, 0, 0, 0.15) 0 1px 4px; - box-shadow: rgba(0, 0, 0, 0.15) 0 1px 4px; - box-sizing: border-box; - border: white 0.5em solid; - /* Don't go too big on images, let reader zoom in if they care to */ - max-width: 80%; - max-height: 80%; } - -img.pwhack { - /* Paperwhite hack */ - width: 100%; } - -.group { - page-break-inside: avoid; } - -.caption { - text-align: center; - font-size: 0.8em; - font-weight: bold; } - -p img { - border-radius: 0; - border: none; } - -figure { - /* These first 3 should center figures */ - padding: 1em; - background-color: #cccccc; - border: 1px solid black; - text-align: center; } - figure figcaption { - text-align: center; - font-size: 0.8em; - font-weight: bold; } - -div.div-literal-block-admonition { - margin-left: 1em; - background-color: #cccccc; } -div.note, div.tip, div.hint { - margin: 1em 0 1em 0 !important; - background-color: #cccccc; - padding: 1em !important; - /* kindle is finnicky with borders, bottoms dissappear, width is ignored */ - border-top: 0px solid #cccccc; - border-bottom: 0px dashed #cccccc; - page-break-inside: avoid; } - -/* sidebar */ -p.note-title, .admonition-title { - margin-top: 0; - /*mobi doesn't like div margins */ - font-variant: small-caps; - font-size: 0.9em; - text-align: center; - font-weight: bold; - font-style: normal; - -webkit-hyphens: none; - -moz-hyphens: none; - hyphens: none; - /* margin:0 1em 0 1em */ } - -div.note p, .note-p { - text-indent: 1em; - margin-left: 0; - margin-right: 0; } - -/* font-style: italic */ -/* Since Kindle doesn't like multiple classes have to have combinations */ -div.note p.note-p-first { - text-indent: 0; - margin-left: 0; - margin-right: 0; } - -/* Tables */ -table { - /*width: 100% */ - page-break-inside: avoid; - border: 1px; - /* centers on kf8 */ - margin: 1em auto; - border-collapse: collapse; - border-spacing: 0; } - -th { - font-variant: small-caps; - padding: 5px !important; - vertical-align: baseline; - border-bottom: 1px solid black; } - -td { - font-family: "Palatino", "Times New Roman", Caecilia, serif; - font-size: small; - hyphens: none; - -moz-hyphens: none; - -webkit-hyphens: none; - padding: 5px !important; - page-break-inside: avoid; - text-align: left; - text-indent: 0; - vertical-align: baseline; } - -td:nth-last-child { - border-bottom: 1px solid black; } - -.zebra { - /* shade background by groups of three */ } - .zebra tr th { - background-color: white; } - .zebra tr:nth-child(6n-1), .zebra tr:nth-child(6n+0), .zebra tr:nth-child(6n+1) { - background-color: #cccccc; } - -sup { - vertical-align: super; - font-size: 0.5em; - line-height: 0.5em; } - -sub { - vertical-align: sub; - font-size: 0.5em; - line-height: 0.5em; } - -table.footnote { - margin: 0.5em 0em 0em 0em; } - -.footnote { - font-size: 0.8em; } - -.footnote-link { - font-size: 0.8em; - vertical-align: super; } - -.tocEntry-1 a { - /* empty */ - font-weight: bold; - text-decoration: none; - color: black; } - -.tocEntry-2 a { - margin-left: 1em; - text-indent: 1em; - text-decoration: none; - color: black; } - -.tocEntry-3 a { - text-indent: 2em; - text-decoration: none; - color: black; } - -.tocEntry-4 a { - text-indent: 3em; - text-decoration: none; - color: black; } - -.copyright-top { - margin-top: 6em; } - -.page-break-before { - page-break-before: always; } - -.page-break-after { - page-break-after: always; } - -.center { - text-indent: 0; - text-align: center; - margin-left: auto; - margin-right: auto; - display: block; } - -.right { - text-align: right; } - -.left { - text-align: left; } - -.f-right { - float: right; } - -.f-left { - float: left; } - -/* Samples */ -.ingredient { - page-break-inside: avoid; } - -.box-example { - background-color: #8ae234; - margin: 2em; - padding: 1em; - border: 2px dashed #ef2929; } - -.blue { - background-color: blue; } - -.dashed { - border: 2px dashed #ef2929; } - -.padding-only { - padding: 1em; } - -.margin-only { - margin: 2em; } - -.smaller { - font-size: 0.8em; } - -.em1 { - font-size: 0.5em; } - -.em2 { - font-size: 0.75em; } - -.em3 { - font-size: 1em; } - -.em4 { - font-size: 1.5em; } - -.em5 { - font-size: 2em; } - -.per1 { - font-size: 50%; } - -.per2 { - font-size: 75%; } - -.per3 { - font-size: 100%; } - -.per4 { - font-size: 150%; } - -.per5 { - font-size: 200%; } - -.mousepoem p { - line-height: 0; - margin-left: 1em; } - -.per100 { - font-size: 100%; - line-height: 0.9em; } - -.per90 { - font-size: 90%; - line-height: 0.9em; } - -.per80 { - font-size: 80%; - line-height: 0.9em; } - -.per70 { - font-size: 70%; - line-height: 0.9em; } - -.per60 { - font-size: 60%; - line-height: 0.9em; } - -.per50 { - font-size: 50%; - line-height: 1.05em; } - -.per40 { - font-size: 40%; - line-height: 0.9em; } - -.size1 { - font-size: x-small; } - -.size2 { - font-size: small; } - -.size3 { - /* default */ - font-size: medium; } - -.size4 { - font-size: large; } - -.size5 { - font-size: x-large; } - -/* Poetic margins */ -.stanza { - margin-top: 1em; - font-family: serif; - padding-left: 1em; } - .stanza p { - padding-left: 1em; } - -.poetry { - margin: 1em; } - -/*line number */ -.ln { - float: left; - color: #999999; - font-size: 0.8em; - font-style: italic; } - -.pos1 { - margin-left: 1em; - text-indent: -1em; } - -.pos2 { - margin-left: 2em; - text-indent: -1em; } - -.pos3 { - margin-left: 3em; - text-indent: -1em; } - -.pos4 { - margin-left: 4em; - text-indent: -1em; } - -@font-face { - font-family: Inconsolata Mono; - font-style: normal; - font-weight: normal; - src: url("Inconsolata.otf"); } - -.normal-mono { - font-family: "Courier New", Courier, monospace; } - -tt, pre, .mono { - /* Kindle Keyboard has KF8 but no font support, fallback to default mono */ - font-family: "Inconsolata Mono", "Courier New", Courier, monospace; - font-style: normal; } - -@font-face { - font-family: mgopen modata; - font-style: normal; - font-weight: normal; - font-size: 0.5em; - src: url("MgOpenModataRegular.ttf"); } - -.modata { - font-family: "mgopen modata"; } - -@font-face { - font-family: hidden; - font-style: normal; - font-weight: normal; - font-size: 1em; - src: url("invisible1.ttf"); } - -.hidden-font { - font-family: "hidden"; } - -/* Nook works to here :) */ -/* media queries at bottom to not confuse other platforms */ -@media (min-width: 200px) { - .px200 { - color: #8ae234; } } -@media (min-width: 400px) { - .px400 { - color: #8ae234; } } -@media (min-width: 800px) { - .px800 { - color: #8ae234; } } -@media (min-width: 1200px) { - .px1200 { - color: #8ae234; } } -/* broke nook! */ -/*/* WIP device specific... */ -/*@media (min-width: 600px) and (height: 800px) and (amzn-kf8) */ -/* /* Kindle Keyboard w/ KF8 */ -/* .kk */ -/* color: $green */ -/* */ -/*/* @media (min-width: 768px) and (height: 1024px) and (amzn-kf8) */ -/*@media (min-width: 748px) and (min-height: 1004px) and (amzn-kf8) */ -/* /* Kindle Paperwhite */ -/* .kpw */ -/* color: $green */ -/* */ -/*@media (width: 600px) and (height: 1024px) and (amzn-kf8) */ -/* /* Kindle Fire */ -/* .kf */ -/* color: $green */ -/* */ -/*/* Retina iPad */ -/*@media (-webkit-min-device-pixel-ratio: 1.5), (min-device-pixel-ratio: 1.5) */ -/* .retina */ -/* color: $green */ -/* */ -@media amzn-kf8 { - span.dropcapold { - font-size: 300%; - font-weight: bold; - height: 1em; - float: left; - margin: -0.2em 0.1em 0 0.1em; } - - .dropcap { - line-height: 100%; - font-size: 341%; - margin-right: 0.075em; - margin-top: -0.22em; - float: left; - height: 0.8em; } } -@media amzn-mobi { - span.dropcap { - font-size: 1.5em; - font-weight: bold; } - - /* tt, pre */ - /* font-size: 3 */ - /* Size table */ - /* name becomes */ - /* x-small 2 */ - /* small 3 */ - /* medium 4 */ - /* 1em default (nothing) */ - tt { - /* mobi fun */ - /* font-size: x-small /* turns into bookDesc = new ArrayList<>(); - public boolean autoChapterToChapter; - public String bookTitle; - public String bookAuthor; - public List bookSubjects = new ArrayList<>(); - public String bookCover; - List failedChapters = new ArrayList<>(); - List successfulChapterNames = new ArrayList<>(); - List successfulFilenames = new ArrayList<>(); - List imageLinks = new ArrayList<>(); - List imageNames = new ArrayList<>(); - List blacklistedTags; - String export; - String window; - String saveLocation; - String tocFileName; - boolean getImages; - boolean invertOrder; - boolean noStyling; - List successfulExtraPagesNames = new ArrayList<>(); - int waitTime; - List successfulExtraPagesFilenames = new ArrayList<>(); - String nextChapterURL; - String nextChapterBtn = "NOT_SET"; - boolean displayChapterTitle; - int wordCount = 0; - private Document tocDoc; - public List chapterLinks = new ArrayList<>(); - public List chaptersNames = new ArrayList<>(); - private List xhrChapterIds = new ArrayList<>(); - private boolean allChapters; - private int xhrBookId; - private int firstChapter; - private int lastChapter; - private boolean useHeaderlessBrowser; - private int chapterToChapterNumber; - - // Empty constructor for ManNovel - AutoNovel() { - } - - // Is called when a novel URL is being 'checked' - public AutoNovel(GUI myGUI) { - gui = myGUI; - String tocUrl = gui.chapterListURL.getText(); - String host = Objects.requireNonNull(gui.autoHostSelection.getSelectedItem()).toString().toLowerCase().replace(" ", ""); - useHeaderlessBrowser = gui.useHeaderlessBrowserCheckBox.isSelected(); - window = "auto"; - currHostSettings = new HostSettings(host, tocUrl); - blacklistedTags = currHostSettings.blacklistedTags; - if (HostSettings.autoChapterToChapterWebsitesList.contains(gui.autoHostSelection.getSelectedItem().toString())) { - autoChapterToChapter = true; - } - getChapterList(); - getNovelMetadata(); - } - - public void startDownload() { - saveLocation = gui.saveLocation.getText(); - export = gui.exportSelection.getSelectedItem().toString(); - waitTime = Integer.parseInt(gui.waitTime.getText()); - allChapters = gui.chapterAllCheckBox.isSelected(); - invertOrder = gui.checkInvertOrder.isSelected(); - useHeaderlessBrowser = gui.useHeaderlessBrowserCheckBox.isSelected(); - displayChapterTitle = gui.displayChapterTitleCheckBox.isSelected(); - noStyling = gui.autoNoStyling.isSelected(); - if (!gui.autoChapterToChapterNumberField.getText().equals("Number")) { - chapterToChapterNumber = Integer.valueOf(gui.autoChapterToChapterNumberField.getText()); - } else { - chapterToChapterNumber = 1; - } - if (!gui.chapterAllCheckBox.isSelected()) { - firstChapter = (Integer) gui.firstChapter.getValue(); - if (!gui.toLastChapter.isSelected()) { - lastChapter = (Integer) gui.lastChapter.getValue(); - } - } - getImages = gui.getImages.isSelected(); - // Write buffered cover to save location - if (bufferedCover != null && bookCover != null) { - try { - File outputfile = new File(saveLocation + File.separator + "images" + File.separator + bufferedCoverName); - if (!outputfile.exists()) outputfile.mkdirs(); - ImageIO.write(bufferedCover, bufferedCoverName.substring(bufferedCoverName.lastIndexOf(".") + 1), outputfile); - } catch (IOException e) { - gui.appendText(window, "[ERROR]Could not write cover image to file."); - } - } - // Getting the chapters again if it was stopped previously - if (killTask) getChapterList(); - killTask = false; - // Start headerless browser - if (useHeaderlessBrowser) { - driverSetup(); - wait = new WebDriverWait(driver, 30); - } - if (autoChapterToChapter) { - String[] chapterToChapterArgs = { - gui.autoFirstChapterURL.getText(), - gui.autoLastChapterURL.getText(), - currHostSettings.nextChapterBtn - }; - processChaptersToChapters(chapterToChapterArgs); - } else { - downloadChapters(); - } - if (useHeaderlessBrowser) { - driver.close(); - } - if (!successfulFilenames.isEmpty() && !killTask) { - switch ((String) gui.exportSelection.getSelectedItem()) { - case "Calibre": - shared.createToc(this); - break; - case "EPUB": - shared.createCoverPage(this); - shared.createToc(this); - if (!bookDesc.get(0).isEmpty() && !noDescription) shared.createDescPage(this); - ToEpub epub = new ToEpub(this); - break; - } - shared.report(this); - } - } - - // Retrieves chapter links and names - private void getChapterList() { - try { - gui.appendText(window, "[INFO]Fetching novel info..."); - // Needs to be reset in case of stopped grabbing - chapterLinks.clear(); - chaptersNames.clear(); - bookDesc.add(0, ""); - wordCount = 0; - if (useHeaderlessBrowser) { - getChaptersHeaderless(); - } else { - getChaptersJsoup(); - } - } catch (IllegalArgumentException | IOException e) { - gui.appendText(window, "[ERROR]" + e.getMessage()); - e.printStackTrace(); - } - } - - /** - * Gets chapters using Jsoup (static html) - faster - */ - private void getChaptersJsoup() throws IOException { - Document doc = Jsoup.connect(currHostSettings.url).timeout(30 * 1000).get(); - tocDoc = doc; - Elements chapterItems; - Elements links; - if (!autoChapterToChapter) { - switch (currHostSettings.host) { - // Custom chapter selection - case "https://boxnovel.com/": - chapterItems = doc.select(currHostSettings.chapterLinkSelecter); - for(Element link: chapterItems) { - chapterLinks.add(link.attr("abs:href")); - chaptersNames.add(link.text()); - } - // Get href link of last (first in novel context) chapter - String boxNovelFirstChapter = chapterLinks.get(chapterLinks.size()-1); - String boxNovelbaseLinkStart = boxNovelFirstChapter.substring(0, shared.ordinalIndexOf(boxNovelFirstChapter, "/", 5) + 9); - String boxNovelChapterNumberString = boxNovelFirstChapter.substring(boxNovelbaseLinkStart.length()); - int boxNovelChapterNumber; - if(boxNovelChapterNumberString.contains("-")) { - boxNovelChapterNumber = Integer.valueOf(boxNovelChapterNumberString.substring(0,boxNovelChapterNumberString.indexOf("-"))); - } else { - boxNovelChapterNumber = Integer.valueOf(boxNovelChapterNumberString); - - } - if (boxNovelChapterNumber != 1) { - for (int i = boxNovelChapterNumber - 1; i >= 1; i--) { - chapterLinks.add(boxNovelbaseLinkStart + i); - chaptersNames.add("Chapter " + i); - } - } - break; - case "http://novelfull.com/": - while (!doc.select("li.next").hasClass("disabled")) { - chapterItems = doc.select(currHostSettings.chapterLinkSelecter); - for (Element link : chapterItems) { - chapterLinks.add(link.attr("abs:href")); - chaptersNames.add(link.text()); - } - doc = Jsoup.connect(doc.select("li.next a").attr("abs:href")).timeout(30 * 1000).get(); - } - chapterItems = doc.select(currHostSettings.chapterLinkSelecter); - for (Element link : chapterItems) { - chapterLinks.add(link.attr("abs:href")); - chaptersNames.add(link.text()); - } - break; - case "https://zenithnovels.com/": - while (!doc.select(".lcp_paginator a.lcp_nextlink").attr("abs:href").isEmpty()) { - chapterItems = doc.select(currHostSettings.chapterLinkSelecter); - for (Element link : chapterItems) { - chapterLinks.add(link.attr("abs:href")); - chaptersNames.add(link.text()); - } - doc = Jsoup.connect(doc.select(".lcp_paginator a.lcp_nextlink").attr("abs:href")).timeout(30 * 1000).get(); - } - chapterItems = doc.select(currHostSettings.chapterLinkSelecter); - for (Element link : chapterItems) { - chapterLinks.add(link.attr("abs:href")); - chaptersNames.add(link.text()); - } - break; - case "https://translatinotaku.net/": - while (!doc.select("a.page-numbers.next").attr("abs:href").isEmpty()) { - chapterItems = doc.select(currHostSettings.chapterLinkSelecter); - for (Element link : chapterItems) { - chapterLinks.add(link.attr("abs:href")); - chaptersNames.add(link.text()); - } - doc = Jsoup.connect(doc.select("a.page-numbers.next").attr("abs:href")).timeout(30 * 1000).get(); - } - chapterItems = doc.select(currHostSettings.chapterLinkSelecter); - for (Element link : chapterItems) { - chapterLinks.add(link.attr("abs:href")); - chaptersNames.add(link.text()); - } - break; - case "https://comrademao.com/": - while (!doc.select(".column a.next").attr("abs:href").isEmpty()) { - chapterItems = doc.select(currHostSettings.chapterLinkSelecter); - for (Element link : chapterItems) { - chapterLinks.add(link.attr("abs:href")); - chaptersNames.add(link.text()); - } - doc = Jsoup.connect(doc.select(".column a.next").attr("abs:href")).timeout(30 * 1000).get(); - - } - chapterItems = doc.select(currHostSettings.chapterLinkSelecter); - for (Element link : chapterItems) { - chapterLinks.add(link.attr("abs:href")); - chaptersNames.add(link.text()); - } - break; - case "https://wuxiaworld.online/": - chapterItems = doc.select(currHostSettings.chapterLinkSelecter); - for (Element link : chapterItems) { - chapterLinks.add(link.attr("abs:href")); - chaptersNames.add(link.text()); - } - // Get href link of last (first in novel context) chapter - String wuxiaonlineFirstChapter = chapterLinks.get(chapterLinks.size() - 1); - String wuxiaonlinebaseLinkStart = wuxiaonlineFirstChapter.substring(0, shared.ordinalIndexOf(wuxiaonlineFirstChapter, "/", 4) + 9); - String wuxiaonlineChapterNumberString = wuxiaonlineFirstChapter.substring(wuxiaonlinebaseLinkStart.length()); - int wuxiaonlineChapterNumber; - if(wuxiaonlineChapterNumberString.contains("-")) { - boxNovelChapterNumber = Integer.valueOf(wuxiaonlineChapterNumberString.substring(0,wuxiaonlineChapterNumberString.indexOf("-"))); - } else { - boxNovelChapterNumber = Integer.valueOf(wuxiaonlineChapterNumberString); - - } - if(boxNovelChapterNumber != 1) { - for(int i = boxNovelChapterNumber-1; i >= 1; i--) { - chapterLinks.add(wuxiaonlinebaseLinkStart+i); - chaptersNames.add("Chapter "+i); - } - } - break; - case "https://fanfiction.net/": - chapterItems = doc.select(currHostSettings.chapterLinkSelecter); - String fullLink = doc.select("link[rel=canonical]").attr("abs:href"); - String baseLinkStart = fullLink.substring(0, shared.ordinalIndexOf(fullLink, "/", 5) + 1); - String baseLinkEnd = fullLink.substring(baseLinkStart.length() + 1); - - links = chapterItems.select("option[value]"); - for (Element chapterLink : links) { - if (!chapterLinks.contains(baseLinkStart + chapterLink.attr("value") + baseLinkEnd)) { - chapterLinks.add(baseLinkStart + chapterLink.attr("value") + baseLinkEnd); - chaptersNames.add(chapterLink.text()); - } - } - break; - case "https://fanfiktion.de/": - chapterItems = doc.select(currHostSettings.chapterLinkSelecter); - String fullLink1 = doc.select("link[rel=canonical]").attr("abs:href"); - String baseLinkStart1 = fullLink1.substring(0, shared.ordinalIndexOf(fullLink1, "/", 5) + 1); - String baseLinkEnd1 = fullLink1.substring(baseLinkStart1.length() + 1); - links = chapterItems.select("option[value]"); - for (Element chapterLink : links) { - if (!chapterLinks.contains(baseLinkStart1 + chapterLink.attr("value") + baseLinkEnd1)) { - chapterLinks.add(baseLinkStart1 + chapterLink.attr("value") + baseLinkEnd1); - chaptersNames.add(chapterLink.text()); - } - } - break; - case "https://flying-lines.com/": - chapterItems = doc.select(currHostSettings.chapterLinkSelecter); - links = chapterItems.select("a[href]"); - String chapterName; - int chapterNumber; - String chapterURL; - for (Element chapterLink : links) { - chapterNumber = Integer.parseInt(chapterLink.text().substring(0, chapterLink.text().indexOf(".") - 1)); - chapterName = chapterLink.text().substring(chapterLink.text().indexOf(".") + 1); - chaptersNames.add("Chapter " + chapterNumber + ": " + chapterName); - chapterURL = chapterLink.attr("abs:href").replace("/autoNovel", "/h5/autoNovel/" - + gui.chapterListURL.getText().substring(gui.chapterListURL.getText().lastIndexOf("/") + 1) - + "/" + chapterNumber); - chapterLinks.add(chapterURL.substring(0, chapterURL.lastIndexOf("/"))); - } - break; - case "https://tapread.com/": - String novelURL = gui.chapterListURL.getText(); - int tapReadNovelId = Integer.valueOf(novelURL.substring(novelURL.lastIndexOf("/") + 1)); - xhrBookId = tapReadNovelId; - Map chapters = xhrRequest.tapReadGetChapterList(tapReadNovelId); - for (String chapterId : chapters.keySet()) { - chaptersNames.add(chapters.get(chapterId)); - xhrChapterIds.add(chapterId); - chapterLinks.add("https://.tapread.com/book/index/" + tapReadNovelId + "/" + chapterId); - } - break; - case "https://webnovel.com/": - String csrfToken = "null"; - String bookId = gui.chapterListURL.getText(); - String bookTitle = doc.select(currHostSettings.bookTitleSelector).first().text().replaceAll("[\\\\/:*?\"<>|]", ""); - bookId = bookId.substring(shared.ordinalIndexOf(bookId, "/", 4) + 1, shared.ordinalIndexOf(bookId, "/", 5)); - - String otherParameter = ""; - CookieManager cookieManager = new CookieManager(); - CookieHandler.setDefault(cookieManager); - - URL url = new URL(currHostSettings.url); - URLConnection connection = url.openConnection(); - connection.getContent(); - - List cookies = cookieManager.getCookieStore().getCookies(); - for (HttpCookie cookie : cookies) { - if (cookie.toString().startsWith("_csrfToken")) { - csrfToken = cookie.toString().substring(11); - } - - } - Map webnovelChapters = xhrRequest.webnovelGetChapterList( - "https://www.webnovel.com/apiajax/chapter/GetChapterList?_csrfToken=" + csrfToken + "&bookId=" + bookId + "&_=" + otherParameter); - int webnovelChapterNumber = 1; - for (String chapterId : webnovelChapters.keySet()) { - chaptersNames.add("Chapter " + webnovelChapterNumber + ": " + webnovelChapters.get(chapterId)); - xhrChapterIds.add(chapterId); - chapterLinks.add( - "https://www.webnovel.com/book/" + bookId + "/" + chapterId + "/" - + bookTitle.replace(" ", "-") + "/" + webnovelChapters.get(chapterId).replace(" ", "-")); - webnovelChapterNumber++; - } - break; - case "https://creativenovels.com/": - String novelId = doc.select("chapter_list_novel_page").attr("class"); - xhrRequest http = new xhrRequest(); - String postResponse = http.sendPost("https://creativenovels.com/wp-admin/admin-ajax.php", - "action=crn_chapter_list&view_id=61581"); - List containedUrls = new ArrayList(); - String urlRegex = "\\b((https?|ftp|file)://[-a-zA-Z0-9+&@#/%?=~_|!:,.;]*[-a-zA-Z0-9+&@#/%=~_|])"; - Pattern pattern = Pattern.compile(urlRegex, Pattern.CASE_INSENSITIVE); - Matcher urlMatcher = pattern.matcher(postResponse); - - while (urlMatcher.find()) { - containedUrls.add(postResponse.substring(urlMatcher.start(0), - urlMatcher.end(0))); - } - int i = 1; - for (String chapterUrl : containedUrls) { - chapterUrl = chapterUrl.substring(0, chapterUrl.lastIndexOf("/")); - chapterLinks.add(chapterUrl); - chaptersNames.add("Chapter: " + i); - i++; - } - break; - default: - chapterItems = doc.select(currHostSettings.chapterLinkSelecter); - for (Element chapterLink : chapterItems) { - chapterLinks.add(chapterLink.attr("abs:href")); - chaptersNames.add(chapterLink.text()); - } - break; - } - } - } - - /** - * Gets chapters using Selenium (full browser visit of website) - slower - */ - private void getChaptersHeaderless() { - driverSetup(); - wait = new WebDriverWait(driver, 30); - driver.navigate().to(gui.chapterListURL.getText()); - // Save HTML source for metadata later on - tocDoc = Jsoup.parse(driver.getPageSource()); - // Website interactions - switch (currHostSettings.host) { - case "https://royalroad.com/": - Select chapterShow = new Select(driver.findElement(By.name("chapters_length"))); - chapterShow.selectByVisibleText("All"); - break; - case "https://creativenovels.com/": - driver.findElement(By.cssSelector("ul[role='tablist'] > li:nth-of-type(3) button")).click(); - wait.until(ExpectedConditions.presenceOfElementLocated(By.cssSelector(".post_box"))); - break; - case "https://flying-lines.com/": - wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector(".chapter-tables > span:nth-child(2)"))); - driver.findElement(By.cssSelector(".chapter-tables > span:nth-child(2)")).click(); - break; - case "https://tapread.com/": - wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector(".tab-content"))); - driver.findElement(By.cssSelector(".tab-content")).click(); - wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector(".chapter-list a"))); - break; - case "https://wordexcerpt.com/": - driver.findElement(By.cssSelector("li.nav-item:nth-child(2) > a:nth-child(1)")).click(); - wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector(currHostSettings.chapterLinkSelecter))); - break; - case "https://webnovel.com/": - wait.until(ExpectedConditions.visibilityOfElementLocated(By.xpath("/html/body/div[1]/div/div/div/div[2]/div/div/div/div[1]/div/div[1]/div/ul/li[2]/a"))); - driver.findElement(By.xpath("/html/body/div[1]/div/div/div/div[2]/div/div/div/div[1]/div/div[1]/div/ul/li[2]/a")).click(); - wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector(".j_catalog_list a"))); - break; - case "https://boxnovel.com/": - wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector(".chapter-readmore"))); - driver.findElement(By.cssSelector(".chapter-readmore")).click(); - break; - case "https://wordrain69.com/": - driver.findElement(By.cssSelector(".chapter-readmore")).click(); - wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector(currHostSettings.chapterLinkSelecter))); - break; - case "https://ficfun.com/": - driver.findElement(By.cssSelector(".button-round-red")).click(); - break; - case "https://dreame.com/": - driver.findElement(By.cssSelector(".button-round-purple")).click(); - break; - case "https://wuxiaworld.site/": - wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector(currHostSettings.chapterLinkSelecter))); - break; - } - // Parse html from headerless to Jsoup for faster interaction. - String baseUrl = driver.getCurrentUrl().substring(0, shared.ordinalIndexOf(driver.getCurrentUrl(), "/", 3) + 1); - // baseUrl (eg. wuxiaworld.com) is needed to get full href links - tocDoc = Jsoup.parse(driver.getPageSource(), baseUrl); - for (Element chapterLink : tocDoc.select(currHostSettings.chapterLinkSelecter)) { - chapterLinks.add(chapterLink.attr("abs:href")); - chaptersNames.add(chapterLink.text()); - } - driver.close(); - } - - void downloadChapters() { - gui.appendText(window, "[INFO]Downloading chapters..."); - successfulFilenames.clear(); - successfulChapterNames.clear(); - successfulExtraPagesFilenames.clear(); - successfulExtraPagesNames.clear(); - failedChapters.clear(); - imageLinks.clear(); - imageNames.clear(); - if (invertOrder) { - Collections.reverse(chapterLinks); - Collections.reverse(chaptersNames); - } - if (gui.toLastChapter.isSelected()) { - lastChapter = chapterLinks.size(); - } - if (allChapters) { - processAllChapters(); - } else { - if (lastChapter > chapterLinks.size()) { - gui.appendText(window, "[ERROR] Novel does not have that many chapters. " + - "(" + chapterLinks.size() + " detected.)"); - return; - } - processSpecificChapters(); - } - // Reverse chapter list back for potential re-grab - if (gui.checkInvertOrder.isSelected()) { - Collections.reverse(chapterLinks); - Collections.reverse(chaptersNames); - } - } - - private void getNovelMetadata() { - try { - // Reset autoNovel info on GUI - gui.autoBookTitle.setText(""); - gui.autoAuthor.setText(""); - gui.autoChapterAmount.setText(""); - gui.setBufferedCover(null); - gui.autoBookSubjects.setText(""); - Document doc = tocDoc; - // Title - if (!currHostSettings.bookTitleSelector.isEmpty()) { - if (doc.select(currHostSettings.bookTitleSelector) != null && !doc.select(currHostSettings.bookTitleSelector).isEmpty()) { - bookTitle = doc.select(currHostSettings.bookTitleSelector).first().text().replaceAll("[\\\\/:*?\"<>|]", ""); - gui.autoBookTitle.setText(bookTitle); - } else { - bookTitle = "Unknown"; - gui.autoBookTitle.setText("Unknown"); - } - } else { - bookTitle = "Unknown"; - gui.autoBookTitle.setText("Unknown"); - } - // Description - if (!currHostSettings.bookDescSelector.equals("false")) { - if (doc.select(currHostSettings.bookDescSelector) != null && !doc.select(currHostSettings.bookDescSelector).isEmpty()) { - bookDesc.set(0, doc.select(currHostSettings.bookDescSelector).first().text()); - } else { - bookDesc.set(0, ""); - } - } else { - bookDesc.set(0, ""); - } - // Author - if (!currHostSettings.bookAuthorSelector.isEmpty()) { - if (doc.select(currHostSettings.bookAuthorSelector) != null && !doc.select(currHostSettings.bookAuthorSelector).isEmpty()) { - bookAuthor = doc.select(currHostSettings.bookAuthorSelector).first().text(); - gui.autoAuthor.setText(bookAuthor); - } else { - bookAuthor = "Unknown"; - gui.autoAuthor.setText("Unknown"); - } - } else { - bookAuthor = "Unknown"; - gui.autoAuthor.setText("Unknown"); - } - if (!chapterLinks.isEmpty()) { - gui.autoChapterAmount.setText(String.valueOf(chapterLinks.size())); - gui.autoGetNumberButton.setEnabled(true); - } - // Tags - if (!currHostSettings.bookSubjectSelector.isEmpty()) { - if (doc.select(currHostSettings.bookSubjectSelector) != null && !doc.select(currHostSettings.bookSubjectSelector).isEmpty()) { - Elements tags = doc.select(currHostSettings.bookSubjectSelector); - for (Element tag : tags) { - bookSubjects.add(tag.text()); - } - - // Display book subjects on GUI - int maxNumberOfSubjects = 0; - gui.autoBookSubjects.setText(""); - for (String eachTag : bookSubjects) { - gui.autoBookSubjects.setText(gui.autoBookSubjects.getText() + eachTag + ", "); - maxNumberOfSubjects++; - if (maxNumberOfSubjects == 4) { - maxNumberOfSubjects = 0; - gui.autoBookSubjects.setText(gui.autoBookSubjects.getText() + "
"); - } - } - if (!gui.autoBookSubjects.getText().isEmpty()) { - gui.autoBookSubjects.setText( - gui.autoBookSubjects.getText().substring(0, - gui.autoBookSubjects.getText().lastIndexOf(","))); - } - } else { - bookSubjects.add("Unknown"); - gui.autoBookSubjects.setText("Unknown"); - } - } else { - bookSubjects.add("Unknown"); - gui.autoBookSubjects.setText("Unknown"); - } - // Chapter number - if (autoChapterToChapter) { - gui.autoChapterAmount.setText("Unknown"); - gui.autoGetNumberButton.setEnabled(false); - } - if (!chapterLinks.isEmpty()) { - gui.autoChapterAmount.setText(String.valueOf(chapterLinks.size())); - gui.autoGetNumberButton.setEnabled(true); - } - // Cover - if (!currHostSettings.bookCoverSelector.isEmpty()) { - if (doc.select(currHostSettings.bookCoverSelector) != null && !doc.select(currHostSettings.bookCoverSelector).isEmpty()) { - Element coverSelect = doc.select(currHostSettings.bookCoverSelector).first(); - if (coverSelect != null) { - String coverLink = coverSelect.attr("abs:src"); - // Custom - if (currHostSettings.host.equals("https://wordexcerpt.com/")) - coverLink = coverSelect.attr("data-src"); - if (currHostSettings.host.equals("https://webnovel.com/")) { - coverLink = coverLink.replace("/300/300", "/600/600"); - } - bufferedCover = shared.getBufferedCover(coverLink, this); - gui.setBufferedCover(bufferedCover); - bookCover = imageNames.get(0); - /* downloadImage() adds every image to and this interferes with - the cover image when adding images from these to the epub */ - imageNames.clear(); - imageLinks.clear(); - } - } - } - } catch (Exception e) { - gui.appendText(window, e.getMessage()); - e.printStackTrace(); - } - } - - private void processSpecificChapters() { - tocFileName = "Table of Contents " + firstChapter + "-" + lastChapter; - gui.setMaxProgress(window, (lastChapter - firstChapter) + 1); - gui.progressBar.setStringPainted(true); - for (int i = firstChapter; i <= lastChapter; i++) { - if (useHeaderlessBrowser) { - driver.navigate().to(chapterLinks.get(i - 1)); - String chapterContainer = currHostSettings.chapterContainer; - wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector(chapterContainer))); - WebElement chapter = driver.findElement(By.cssSelector("body")); - shared.saveChapterFromString(chapter.getAttribute("innerHTML"), i, chaptersNames.get(i - 1), - currHostSettings.chapterContainer, this); - } else { - // Custom chapter selection - switch (currHostSettings.host) { - // Custom - case "https://tapread.com/": - String chapterContentString = xhrRequest.tapReadGetChapterContent("bookId=" + xhrBookId + "&chapterId=" + xhrChapterIds.get(i - 1)); - shared.saveChapterFromString(chapterContentString, i, chaptersNames.get(i - 1), - currHostSettings.chapterContainer, this); - break; - default: - shared.saveChapterWithHTML(chapterLinks.get(i - 1), i, chaptersNames.get(i - 1), - currHostSettings.chapterContainer, this); - break; - } - } - // If grabbing was stopped - if (killTask) { - gui.appendText(window, "[INFO]Stopped."); - Path chaptersFolder = Paths.get(saveLocation + "/chapters"); - Path imagesFolder = Paths.get(saveLocation + "/images"); - try { - if (Files.exists(imagesFolder)) shared.deleteFolderAndItsContent(imagesFolder); - if (Files.exists(chaptersFolder)) shared.deleteFolderAndItsContent(chaptersFolder); - } catch (IOException e) { - gui.appendText(window, e.getMessage()); - e.printStackTrace(); - } - return; - } - shared.sleep(waitTime); - } - } - - private void processAllChapters() { - tocFileName = bookTitle; - gui.setMaxProgress(window, chapterLinks.size()); - gui.progressBar.setStringPainted(true); - for (int i = 1; i <= chapterLinks.size(); i++) { - if (useHeaderlessBrowser) { - driver.navigate().to(chapterLinks.get(i - 1)); - String chapterContainer = currHostSettings.chapterContainer; - wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector(chapterContainer))); - WebElement chapter = driver.findElement(By.cssSelector("body")); - shared.saveChapterFromString(chapter.getAttribute("innerHTML"), i, chaptersNames.get(i - 1), - currHostSettings.chapterContainer, this); - } else { - switch (currHostSettings.host) { - // Custom - case "https://tapread.com/": - String chapterContentString = xhrRequest.tapReadGetChapterContent("bookId=" + xhrBookId + "&chapterId=" + xhrChapterIds.get(i - 1)); - shared.saveChapterFromString(chapterContentString, i, chaptersNames.get(i - 1), - currHostSettings.chapterContainer, this); - break; - default: - shared.saveChapterWithHTML(chapterLinks.get(i - 1), i, chaptersNames.get(i - 1), - currHostSettings.chapterContainer, this); - break; - } - } - if (killTask) { - gui.appendText(window, "[INFO]Stopped."); - Path chaptersFolder = Paths.get(saveLocation + "/chapters"); - Path imagesFolder = Paths.get(saveLocation + "/images"); - try { - if (Files.exists(imagesFolder)) shared.deleteFolderAndItsContent(imagesFolder); - if (Files.exists(chaptersFolder)) shared.deleteFolderAndItsContent(chaptersFolder); - } catch (IOException e) { - gui.appendText(window, e.getMessage()); - e.printStackTrace(); - } - return; - } - shared.sleep(waitTime); - } - } - - /** - * Handles downloading chapter to chapter. - */ - void processChaptersToChapters(String[] args) { - successfulFilenames.clear(); - successfulChapterNames.clear(); - successfulExtraPagesFilenames.clear(); - successfulExtraPagesNames.clear(); - failedChapters.clear(); - imageLinks.clear(); - imageNames.clear(); - gui.appendText(window, "[INFO]Connecting..."); - gui.setMaxProgress(window, 9001); - String nextChapter = args[0]; - String lastChapter = args[1]; - nextChapterBtn = args[2]; - int chapterNumber = chapterToChapterNumber; - while (true) { - if (useHeaderlessBrowser) { - driver.navigate().to(nextChapter); - String chapterContainer = currHostSettings.chapterContainer; - wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector(chapterContainer))); - WebElement chapter = driver.findElement(By.cssSelector("body")); - shared.saveChapterFromString(chapter.getAttribute( - "innerHTML"), chapterNumber, "Chapter " + chapterNumber, - currHostSettings.chapterContainer, this); - } else { - shared.saveChapterWithHTML(nextChapter, chapterNumber, "Chapter " + chapterNumber, currHostSettings.chapterContainer, this); - } - nextChapter = nextChapterURL; - if (nextChapter.equals(lastChapter) || (nextChapter + "/").equals(lastChapter)) { - chapterNumber++; - shared.sleep(waitTime); - nextChapterBtn = "NOT_SET"; - if (useHeaderlessBrowser) { - driver.navigate().to(nextChapter); - String chapterContainer = currHostSettings.chapterContainer; - wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector(chapterContainer))); - WebElement chapter = driver.findElement(By.cssSelector("body")); - shared.saveChapterFromString(chapter.getAttribute( - "innerHTML"), chapterNumber, "Chapter " + chapterNumber, - currHostSettings.chapterContainer, this); - } else { - shared.saveChapterWithHTML(nextChapter, chapterNumber, "Chapter " + chapterNumber, currHostSettings.chapterContainer, this); - } - break; - } - if (killTask) { - gui.appendText(window, "[INFO]Stopped."); - Path chaptersFolder = Paths.get(saveLocation + "/chapters"); - Path imagesFolder = Paths.get(saveLocation + "/images"); - try { - if (Files.exists(imagesFolder)) shared.deleteFolderAndItsContent(imagesFolder); - if (Files.exists(chaptersFolder)) shared.deleteFolderAndItsContent(chaptersFolder); - } catch (IOException e) { - gui.appendText(window, e.getMessage()); - e.printStackTrace(); - } - return; - } - chapterNumber++; - shared.sleep(waitTime); - } - } - - /** - * Displays chapter name and chapter number. - */ - public String[] getChapterNumber(GUI gui, String chapterURL) { - try { - int chapterNumber = chapterLinks.indexOf(chapterURL); - if (chapterNumber == -1) - chapterNumber = chapterLinks.indexOf(chapterURL.substring(0, chapterURL.lastIndexOf("/"))); - if (chapterNumber == -1) - chapterNumber = chapterLinks.indexOf(chapterURL.replace("https:", "http:")); - if (chapterNumber == -1) gui.showPopup("Could not find chapter number.", "error"); - else { - return new String[]{chaptersNames.get(chapterNumber), String.valueOf(chapterNumber + 1)}; - } - } catch (IllegalArgumentException e) { - gui.appendText("auto", "[ERROR]" + e.getMessage()); - e.printStackTrace(); - } - return new String[]{null, null}; - } - - - private void driverSetup() { - gui.appendText(window, "[INFO]Starting headerless browser..."); - switch (gui.autoBrowserCombobox.getSelectedItem().toString()) { - case "Chrome": - WebDriverManager.chromedriver().setup(); - driver = new ChromeDriver(new ChromeOptions().setHeadless(true)); - break; - case "Firefox": - WebDriverManager.firefoxdriver().setup(); - driver = new FirefoxDriver(new FirefoxOptions().setHeadless(true)); - break; - case "Opera": - WebDriverManager.operadriver().setup(); - driver = new OperaDriver(); - break; - case "Edge": - WebDriverManager.edgedriver().setup(); - driver = new EdgeDriver(); - break; - case "IE": - WebDriverManager.iedriver().setup(); - driver = new InternetExplorerDriver(); - break; - } - } -} diff --git a/src/grabber/Chapter.java b/src/grabber/Chapter.java new file mode 100644 index 0000000..3909379 --- /dev/null +++ b/src/grabber/Chapter.java @@ -0,0 +1,114 @@ +package grabber; + +import org.jsoup.Jsoup; +import org.jsoup.nodes.Document; +import org.jsoup.nodes.Element; + +import java.io.File; +import java.io.IOException; +import java.io.PrintStream; +import java.nio.charset.StandardCharsets; + +public class Chapter { + String name; + String chapterURL; + String fileName; + // 0 = not downloaded, 1 = successfully downloaded, 2 = failed download + int status = 0; + String xhrChapterId; + int xhrBookId; + + public Chapter(String name, String link) { + this.name = name; + this.chapterURL = link; + fileName = name.replaceAll("[^\\w]+", "-"); + } + + void saveChapter(Novel novel) { + Document doc = null; + try { + if(novel.options.headless) { + doc = novel.headless.getChapterContent(chapterURL); + } else { + switch(novel.host.url) { + case "https://wattpad.com/": + doc = Jsoup.connect(xhrRequest.wattpadGetChapterTextURL(chapterURL.substring(24, chapterURL.indexOf("-")))).timeout(30 * 1000).get(); + break; + case "https://tapread.com/": + doc = Jsoup.parse(xhrRequest.tapReadGetChapterContent("bookId=" + xhrBookId + "&chapterId=" + xhrChapterId), "https://tapread.com/"); + break; + default: + doc = Jsoup.connect(chapterURL).timeout(30 * 1000).get(); + break; + } + } + } catch (IOException | IllegalArgumentException e) { + e.printStackTrace(); + novel.gui.appendText(novel.options.window,"[ERROR]"+e.getMessage()); + status = 2; + return; + } + Element chapterContent = doc.select(novel.host.chapterContainer).first(); + if (novel.host.url.equals("https://tapread.com/")) chapterContent = doc; + + if (chapterContent == null) { + novel.gui.appendText(novel.options.window,"[ERROR]Chapter container (" + novel.host.chapterContainer + ") not found."); + return; + } + // Getting the next chapter URL from the "nextChapterBtn" href for Chapter-To-Chapter. + if (!novel.nextChapterBtn.equals("NOT_SET")) novel.nextChapterURL = doc.select(novel.nextChapterBtn).first().absUrl("href"); + + if (novel.options.removeStyling) chapterContent.select("[style]").removeAttr("style"); + + if (novel.host.blacklistedTags != null && !novel.host.blacklistedTags.isEmpty()) { + for (String tag : novel.host.blacklistedTags) { + if (!chapterContent.select(tag).isEmpty()) { + chapterContent.select(tag).remove(); + } + } + } + if (novel.options.getImages) { + for (Element image : chapterContent.select("img")) { + GrabberUtils.downloadImage(image.absUrl("src"), novel); + } + } + + novel.metadata.wordCount = novel.metadata.wordCount + GrabberUtils.getWordCount(chapterContent.toString()); + novel.gui.pagesCountLbl.setText(String.valueOf(novel.metadata.wordCount)); + + // Create chapters folder if it doesn't exist. + File dir = new File(novel.options.saveLocation + File.separator + "chapters"); + if (!dir.exists()) dir.mkdirs(); + try (PrintStream out = new PrintStream(dir.getPath() + File.separator + fileName + ".html", StandardCharsets.UTF_8)) { + for (Element image : chapterContent.select("img")) { + // Check if the image was successfully downloaded. + String src = image.absUrl("src"); + if (novel.imageLinks.contains(src)) { + // Use hashCode of src + .jpg as the image name if renaming wasn't successful. + String imageName = GrabberUtils.getImageName(image.attr("src")); + if (imageName.equals("could_not_rename_image")) { + imageName = src.hashCode() + ".jpg"; + } + // Replace href for image to point to local path. + image.attr("src", imageName); + // Remove the img tag if image wasn't downloaded. + } else chapterContent.select("img").remove(); + } + // Write text content to file. + if (novel.options.displayChapterTitle) + chapterContent.prepend("" + name + "
"); + out.println(chapterContent); + } catch (IOException e) { + e.printStackTrace(); + novel.gui.appendText(novel.options.window, "[ERROR]"+e.getMessage()); + } finally { + status = 1; + novel.gui.appendText(novel.options.window, "[INFO]"+name+" saved."); + } + } + + @Override + public String toString() { + return name +" | "+ chapterURL; + } +} \ No newline at end of file diff --git a/src/grabber/Driver.java b/src/grabber/Driver.java new file mode 100644 index 0000000..f68e30d --- /dev/null +++ b/src/grabber/Driver.java @@ -0,0 +1,134 @@ +package grabber; + +import io.github.bonigarcia.wdm.WebDriverManager; +import org.jsoup.Jsoup; +import org.jsoup.nodes.Document; +import org.jsoup.nodes.Element; +import org.openqa.selenium.By; +import org.openqa.selenium.WebDriver; +import org.openqa.selenium.WebElement; +import org.openqa.selenium.chrome.ChromeDriver; +import org.openqa.selenium.chrome.ChromeOptions; +import org.openqa.selenium.edge.EdgeDriver; +import org.openqa.selenium.firefox.FirefoxDriver; +import org.openqa.selenium.firefox.FirefoxOptions; +import org.openqa.selenium.ie.InternetExplorerDriver; +import org.openqa.selenium.opera.OperaDriver; +import org.openqa.selenium.support.ui.ExpectedConditions; +import org.openqa.selenium.support.ui.Select; +import org.openqa.selenium.support.ui.WebDriverWait; + +import java.util.ArrayList; +import java.util.List; + +public class Driver { + WebDriver driver; + WebDriverWait wait; + Novel novel; + public Driver(Novel novel) { + this.novel = novel; + driverSetup(); + wait = new WebDriverWait(driver, 30); + } + + private void driverSetup() { + novel.gui.appendText(novel.options.window, "[INFO]Starting headerless browser..."); + switch (novel.options.browser) { + case "Chrome": + WebDriverManager.chromedriver().setup(); + driver = new ChromeDriver(new ChromeOptions().setHeadless(true)); + break; + case "Firefox": + WebDriverManager.firefoxdriver().setup(); + driver = new FirefoxDriver(new FirefoxOptions().setHeadless(true)); + break; + case "Opera": + WebDriverManager.operadriver().setup(); + driver = new OperaDriver(); + break; + case "Edge": + WebDriverManager.edgedriver().setup(); + driver = new EdgeDriver(); + break; + case "IE": + WebDriverManager.iedriver().setup(); + driver = new InternetExplorerDriver(); + break; + } + } + + /** + * Fetches chapters list with a headless browser and saves the page in novel.tableOfContent + */ + public List getChapterList() { + driver.navigate().to(novel.novelLink); + // These websites require manual interactions to display the chapter list + switch (novel.host.url) { + case "https://royalroad.com/": + Select chapterShow = new Select(driver.findElement(By.name("chapters_length"))); + chapterShow.selectByVisibleText("All"); + break; + case "https://creativenovels.com/": + driver.findElement(By.cssSelector("ul[role='tablist'] > li:nth-of-type(3) button")).click(); + wait.until(ExpectedConditions.presenceOfElementLocated(By.cssSelector(".post_box"))); + break; + case "https://flying-lines.com/": + wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector(".chapter-tables > span:nth-child(2)"))); + driver.findElement(By.cssSelector(".chapter-tables > span:nth-child(2)")).click(); + break; + case "https://tapread.com/": + wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector(".tab-content"))); + driver.findElement(By.cssSelector(".tab-content")).click(); + wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector(".chapter-list a"))); + break; + case "https://wordexcerpt.com/": + driver.findElement(By.cssSelector("li.nav-item:nth-child(2) > a:nth-child(1)")).click(); + wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector(novel.host.chapterLinkSelecter))); + break; + case "https://webnovel.com/": + wait.until(ExpectedConditions.visibilityOfElementLocated(By.xpath("/html/body/div[1]/div/div/div/div[2]/div/div/div/div[1]/div/div[1]/div/ul/li[2]/a"))); + driver.findElement(By.xpath("/html/body/div[1]/div/div/div/div[2]/div/div/div/div[1]/div/div[1]/div/ul/li[2]/a")).click(); + wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector(".j_catalog_list a"))); + break; + case "https://boxnovel.com/": + wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector(".chapter-readmore"))); + driver.findElement(By.cssSelector(".chapter-readmore")).click(); + break; + case "https://wordrain69.com/": + driver.findElement(By.cssSelector(".chapter-readmore")).click(); + wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector(novel.host.chapterLinkSelecter))); + break; + case "https://ficfun.com/": + driver.findElement(By.cssSelector(".button-round-red")).click(); + break; + case "https://dreame.com/": + driver.findElement(By.cssSelector(".button-round-purple")).click(); + break; + case "https://wuxiaworld.site/": + wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector(novel.host.chapterLinkSelecter))); + break; + } + // Parse html from headerless to Jsoup for faster interaction. + String baseUrl = driver.getCurrentUrl().substring(0, GrabberUtils.ordinalIndexOf(driver.getCurrentUrl(), "/", 3) + 1); + // Save table of contents doc for metadata extraction later on + novel.tableOfContent = Jsoup.parse(driver.getPageSource(), baseUrl); + + List chapters = new ArrayList<>(); + for (Element chapterLink : novel.tableOfContent.select(novel.host.chapterLinkSelecter)) { + chapters.add(new Chapter(chapterLink.text(), chapterLink.attr("abs:href"))); + } + return chapters; + } + + public Document getChapterContent(String chapterLink) { + driver.navigate().to(chapterLink); + wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector(novel.host.chapterContainer))); + WebElement chapterElement = driver.findElement(By.cssSelector("body")); + String baseUrl = driver.getCurrentUrl().substring(0, GrabberUtils.ordinalIndexOf(driver.getCurrentUrl(), "/", 3) + 1); + return Jsoup.parse(chapterElement.getAttribute("innerHTML"), baseUrl); + } + + public void close() { + driver.close(); + } +} diff --git a/src/grabber/EPUB.java b/src/grabber/EPUB.java new file mode 100644 index 0000000..eeb12b8 --- /dev/null +++ b/src/grabber/EPUB.java @@ -0,0 +1,134 @@ +package grabber; + +import nl.siegmann.epublib.domain.Author; +import nl.siegmann.epublib.domain.Book; +import nl.siegmann.epublib.domain.Metadata; +import nl.siegmann.epublib.domain.Resource; +import nl.siegmann.epublib.epub.EpubWriter; + +import java.io.*; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; + +public class EPUB { + private FileInputStream inputStream; + private Resource resource; + + EPUB(Novel currGrab) { + writeEpub(currGrab); + } + + private void writeEpub(Novel novel) { + try { + novel.gui.appendText(novel.options.window, "[INFO]Writing epub..."); + Book book = new Book(); + Metadata metadata = book.getMetadata(); + // Title + if (novel.metadata.bookTitle != null && !novel.metadata.bookTitle.isEmpty()) { + metadata.addTitle(novel.metadata.bookTitle); + } else { + metadata.addTitle("Unknown"); + } + // Author + if (novel.metadata.bookAuthor != null && !novel.metadata.bookAuthor.isEmpty() && !novel.metadata.bookAuthor.equals("null")) { + metadata.addAuthor(new Author(novel.metadata.bookAuthor)); + } else { + metadata.addAuthor(new Author("Unknown")); + } + // Subjects + if (novel.metadata.bookSubjects != null && !novel.metadata.bookSubjects.isEmpty()) { + metadata.setSubjects(novel.metadata.bookSubjects); + } + // Description + if (novel.metadata.bookDesc != null && !novel.metadata.bookDesc.isEmpty() && !novel.options.noDescription) { + metadata.setDescriptions(novel.metadata.bookDesc); + } + // Set cover image & page + if (novel.metadata.bookCover != null && !novel.metadata.bookCover.isEmpty()) { + if (novel.options.window.equals("auto")) { + // Add cover image as a resource + inputStream = new FileInputStream(novel.options.saveLocation + "/images/" + novel.metadata.bookCover); + resource = new Resource(inputStream, novel.metadata.bookCover); + book.getResources().add(resource); + book.setCoverImage(resource); + inputStream.close(); + } else { + // Add manual cover image. Its saved as a full path + inputStream = new FileInputStream(novel.metadata.bookCover); + resource = new Resource(inputStream, GrabberUtils.getFileName(novel.metadata.bookCover)); + book.getResources().add(resource); + book.setCoverImage(resource); + inputStream.close(); + } + // Adding cover page + inputStream = new FileInputStream(novel.options.saveLocation + "/chapters/" + + novel.extraPages.get(0) + ".html"); + resource = new Resource(inputStream, novel.extraPages.get(0) + ".html"); + book.setCoverPage(resource); + book.addSection("Cover", resource); + inputStream.close(); + } else { + book.setCoverImage(new Resource(getClass().getResourceAsStream("/files//images/cover_placeholder.png"), "cover_placeholder.png")); + + } + // Table of Contents + inputStream = new FileInputStream(novel.options.saveLocation + "/chapters/" + + novel.extraPages.get(1) + ".html"); + resource = new Resource(inputStream, novel.extraPages.get(1) + ".html"); + book.addSection("Table of Contents", resource); + inputStream.close(); + + // Description page + if (novel.metadata.bookDesc != null && !novel.metadata.bookDesc.isEmpty() && !novel.options.noDescription) { + inputStream = new FileInputStream(novel.options.saveLocation + "/chapters/" + + novel.extraPages.get(2) + ".html"); + resource = new Resource(inputStream, novel.extraPages.get(2) + ".html"); + book.addSection("Description", resource); + inputStream.close(); + } + + // Chapters + for(Chapter chapter: novel.chapters) { + if(chapter.status == 1) { + inputStream = new FileInputStream(novel.options.saveLocation + "/chapters/" + + chapter.fileName + ".html"); + resource = new Resource(inputStream, chapter.fileName + ".html"); + book.addSection(chapter.name, resource); + inputStream.close(); + } + + } + + // Add used images + if (novel.options.getImages) { + for (String imageName : novel.imageNames) { + inputStream = new FileInputStream(novel.options.saveLocation + "/images/" + imageName); + resource = new Resource(inputStream, imageName); + book.getResources().add(resource); + inputStream.close(); + } + } + // Add css file + book.getResources().add(new Resource(getClass().getResourceAsStream("/files/default.css"), "default.css")); + // Create EpubWriter + EpubWriter epubWriter = new EpubWriter(); + // Write the Book as Epub + epubWriter.write(book, new FileOutputStream(novel.options.saveLocation + File.separator + novel.metadata.bookTitle + ".epub")); + //novel.gui.appendText(novel.window, "[INFO]Epub successfully created."); + + // Delete image and chapter files + Path chaptersFolder = Paths.get(novel.options.saveLocation + "/chapters"); + Path imagesFolder = Paths.get(novel.options.saveLocation + "/images"); + + if (Files.exists(imagesFolder)) GrabberUtils.deleteFolderAndItsContent(imagesFolder); + if (Files.exists(chaptersFolder)) GrabberUtils.deleteFolderAndItsContent(chaptersFolder); + + } catch (FileNotFoundException e) { + //novel.gui.appendText(novel.window, "[ERROR]" + e.getMessage()); + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } + } +} diff --git a/src/grabber/GrabberUtils.java b/src/grabber/GrabberUtils.java new file mode 100644 index 0000000..665f78c --- /dev/null +++ b/src/grabber/GrabberUtils.java @@ -0,0 +1,165 @@ +package grabber; + +import org.jsoup.Jsoup; +import org.jsoup.nodes.Document; + +import javax.imageio.ImageIO; +import java.awt.image.BufferedImage; +import java.io.*; +import java.net.HttpURLConnection; +import java.net.URL; +import java.nio.file.FileVisitResult; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.SimpleFileVisitor; +import java.nio.file.attribute.BasicFileAttributes; + +public class GrabberUtils { + + static void downloadImage(String src, Novel currGrab) { + if (!currGrab.imageLinks.contains(src)) { + // Try to set the image name + String name = getImageName(src); + // If image could not be renamed correctly, the hashCode of the source + .jpg + // will be set as the image name. + if (name.equals("could_not_rename_image")) { + name = src.hashCode() + ".jpg"; + } + //For LiberSpark + if (src.startsWith("//")) src = src.replace("//", "https://"); + try { + // Connect to image source + URL url = new URL(src); + HttpURLConnection http = (HttpURLConnection) url.openConnection(); + http.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.95 Safari/537.11"); + http.connect(); + InputStream input = http.getInputStream(); + byte[] buffer = new byte[4096]; + // Create imageLinks folder + String filepath = currGrab.options.saveLocation + File.separator + "images"; + File dir = new File(filepath); + if (!dir.exists()) dir.mkdirs(); + // Save image to file + try (OutputStream output = new FileOutputStream(new File(filepath + File.separator + name))) { + int n; + while ((n = input.read(buffer)) != -1) { + output.write(buffer, 0, n); + } + } catch (IOException e) { + e.printStackTrace(); + //currGrab.gui.appendText(currGrab.window, e.getMessage()); + } + currGrab.imageLinks.add(src); + currGrab.imageNames.add(name); + //currGrab.gui.appendText(currGrab.window, "[INFO]" + name + " saved."); + //General catch + } catch (Throwable e) { + e.printStackTrace(); + //currGrab.gui.appendText(currGrab.window, "[ERROR]Failed to save " + name); + } + } + } + + /** + * Returns the image name without the href address/path + */ + static String getImageName(String src) { + String imageName; + int indexname = src.lastIndexOf("/"); + if (indexname == src.length()) { + src = src.substring(1, indexname); + } + indexname = src.lastIndexOf("/"); + imageName = src.substring(indexname + 1); + // Check against popular formats with regex + if (imageName.contains(".png")) imageName = imageName.replaceAll("\\.png(.*)", ".png"); + else if (imageName.contains(".jpg")) imageName = imageName.replaceAll("\\.jpg(.*)", ".jpg"); + else if (imageName.contains(".gif")) imageName = imageName.replaceAll("\\.gif(.*)", ".gif"); + else return "could_not_rename_image"; + return imageName.replaceAll("[\\\\/:*?\"<>|]", "_"); + } + + /** + * Saves the autoNovel cover into a buffered Image + */ + static BufferedImage getBufferedCover(String src, Novel novel) { + if (!novel.imageLinks.contains(src)) { + // Try to set the image name + String name = getImageName(src); + // If image could not be renamed correctly, the hashCode of the source + .jpg + // will be set as the image name. + if (name.equals("could_not_rename_image")) { + name = src.hashCode() + ".jpg"; + } + //For LiberSpark + if (src.startsWith("//")) src = src.replace("//", "https://"); + try { + URL url = new URL(src); + HttpURLConnection http = (HttpURLConnection) url.openConnection(); + http.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.95 Safari/537.11"); + http.connect(); + BufferedImage imageInput = ImageIO.read(http.getInputStream()); + novel.metadata.bufferedCoverName = name; + novel.imageLinks.add(src); + novel.imageNames.add(name); + return imageInput; + //General catch + } catch (Throwable e) { + e.printStackTrace(); + novel.gui.appendText("auto", "[ERROR]Failed to get" + name); + } + } + return null; + } + + static int getWordCount(String html) { + Document dom = Jsoup.parse(html); + String text = dom.text(); + return text.split(" ").length; + } + + public static void deleteFolderAndItsContent(final Path folder) throws IOException { + Files.walkFileTree(folder, new SimpleFileVisitor() { + @Override + public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { + Files.delete(file); + return FileVisitResult.CONTINUE; + } + + @Override + public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException { + if (exc != null) { + throw exc; + } + Files.delete(dir); + return FileVisitResult.CONTINUE; + } + }); + } + + static int ordinalIndexOf(String str, String substr, int n) { + int pos = str.indexOf(substr); + while (--n > 0 && pos != -1) + pos = str.indexOf(substr, pos + 1); + return pos; + } + + /** + * Freeze thread for selected wait time. + */ + static void sleep(int waitTime) { + try { + Thread.sleep(waitTime); + } catch (InterruptedException ex) { + Thread.currentThread().interrupt(); + } + } + + static String getFileName(String imageName) { + if (imageName != null && imageName.contains("/")) + imageName = imageName.substring(imageName.lastIndexOf("/") + 1); + if (imageName != null && imageName.contains("\\")) + imageName = imageName.substring(imageName.lastIndexOf("\\") + 1); + return imageName; + } +} diff --git a/src/grabber/HostSettings.java b/src/grabber/HostSettings.java index 10a6d40..f9e70b0 100644 --- a/src/grabber/HostSettings.java +++ b/src/grabber/HostSettings.java @@ -1,4 +1,5 @@ package grabber; + import java.util.Arrays; import java.util.LinkedList; import java.util.List; @@ -36,9 +37,6 @@ public class HostSettings { "WuxiaWorld.online", "Novelfull", "WuxiaWorld.site" - }; - private static String[] autoChapterToChapterWebsites = { - }; private static String[] headerlessBrowserWebsites = { "Creative Novels", @@ -52,33 +50,28 @@ public class HostSettings { "Fanfiktion" // same }; public static List headerlessBrowserWebsitesList = Arrays.asList(headerlessBrowserWebsites); - public static List autoChapterToChapterWebsitesList = Arrays.asList(autoChapterToChapterWebsites); public static List noHeaderlessBrowserWebsitesList = Arrays.asList(noHeaderlessBrowserWebsites); - public String chapterLinkSelecter; - public String chapterLinkSelecterButton; - String titleHostName; - public String url; - public String host; + public String chapterLinkSelecter; // Table of contents chapter links + public String titleHostName; + public String url; //Website URL public List blacklistedTags; - int ordinalIndexForBaseNovel; - String chapterContainer; - String nextChapterBtn; - String bookTitleSelector; - String bookDescSelector; - String bookAuthorSelector; - String bookSubjectSelector; - String bookCoverSelector; + public int ordinalIndexForBaseNovel; // To trim down string to base autoNovel url + public String chapterContainer; //chapter text container + public String bookTitleSelector; //From the tab title with whitespaces removed + public String bookDescSelector; + public String bookAuthorSelector; + public String bookSubjectSelector; + public String bookCoverSelector; - public HostSettings(String domain, String urla) { - url = urla; + public HostSettings(String domain) { switch (domain) { - case "wuxiaworld": //compared from websites[] with whitespaces removed and lowercase - host = "https://wuxiaworld.com/"; //Website URL - ordinalIndexForBaseNovel = 5; // To trim down string to base autoNovel url - chapterLinkSelecter = "#accordion .chapter-item a"; //Table of contents chapter links - chapterContainer = ".p-15 .fr-view"; //chapter text - titleHostName = "-WuxiaWorld"; //From the tab title with whitespaces removed + case "wuxiaworld": //compared to websites[] with whitespaces removed and lowercase + url = "https://wuxiaworld.com/"; + ordinalIndexForBaseNovel = 5; + chapterLinkSelecter = "#accordion .chapter-item a"; + chapterContainer = ".p-15 .fr-view"; + titleHostName = "-WuxiaWorld"; blacklistedTags = new LinkedList<>(Arrays.asList("a.chapter-nav")); bookTitleSelector = ".p-15 h4"; bookDescSelector = ".fr-view:not(.pt-10)"; @@ -87,7 +80,7 @@ public HostSettings(String domain, String urla) { bookSubjectSelector = ".genres a"; break; case "royalroad": - host = "https://royalroad.com/"; + url = "https://royalroad.com/"; ordinalIndexForBaseNovel = 6; chapterLinkSelecter = "td:not([class]) a"; chapterContainer = ".chapter-content"; @@ -100,11 +93,10 @@ public HostSettings(String domain, String urla) { bookSubjectSelector = ".tags span"; break; case "fanfiktion": - host = "https://fanfiktion.de/"; + url = "https://fanfiktion.de/"; ordinalIndexForBaseNovel = 0; chapterLinkSelecter = "#kA option"; chapterContainer = ".user-formatted-inner"; - nextChapterBtn = ""; titleHostName = "|FanFiktion-de"; blacklistedTags = null; bookTitleSelector = ".huge-font"; @@ -114,21 +106,20 @@ public HostSettings(String domain, String urla) { bookSubjectSelector = "false"; break; case "gravitytales": - host = "http://gravitytales.com/"; + url = "http://gravitytales.com/"; ordinalIndexForBaseNovel = 5; chapterLinkSelecter = ".table td a"; chapterContainer = "#chapterContent"; titleHostName = "-Gravity-Tales"; - url = urla + "/chapters"; //gravity tales' chapter list is at gravitytales.com/NOVEL/chapters blacklistedTags = null; - bookTitleSelector = ".main-content h3"; //Fix - bookDescSelector = ".desc"; - bookCoverSelector = "#coverImg"; + bookTitleSelector = ".main-content h3"; + bookDescSelector = "false"; + bookCoverSelector = ""; bookAuthorSelector = ".main-content h4"; - bookSubjectSelector = ".desc p"; + bookSubjectSelector = ""; break; case "volarenovels": - host = "https://volarenovels.com/"; + url = "https://volarenovels.com/"; ordinalIndexForBaseNovel = 5; chapterLinkSelecter = "#accordion .chapter-item a"; chapterContainer = ".jfontsize_content.fr-view"; @@ -137,11 +128,11 @@ public HostSettings(String domain, String urla) { bookTitleSelector = "h3.title"; bookDescSelector = ".description"; bookCoverSelector = "img.m-tb-30"; - bookAuthorSelector = "div.p-tb-10-rl-30 p"; //Fix + bookAuthorSelector = "div.p-tb-10-rl-30 p"; bookSubjectSelector = ".tags a"; break; case "wordexcerpt": - host = "https://wordexcerpt.com/"; + url = "https://wordexcerpt.com/"; ordinalIndexForBaseNovel = 5; chapterLinkSelecter = ".listing-chapters_wrap a"; chapterContainer = ".text-left"; @@ -154,9 +145,8 @@ public HostSettings(String domain, String urla) { bookSubjectSelector = ".genres-content a"; break; case "ficfun": - host = "https://ficfun.com/"; + url = "https://ficfun.com/"; ordinalIndexForBaseNovel = 0; - chapterLinkSelecterButton = ".button-round-red"; chapterLinkSelecter = ".chapter-list a"; chapterContainer = "#article-content"; titleHostName = ""; @@ -167,9 +157,8 @@ public HostSettings(String domain, String urla) { bookSubjectSelector = ".novel-tags span"; break; case "dreame": - host = "https://dreame.com/"; + url = "https://dreame.com/"; ordinalIndexForBaseNovel = 0; - chapterLinkSelecterButton = ".button-round-purple"; chapterLinkSelecter = ".chapter-list a"; chapterContainer = "#article-content"; titleHostName = ""; @@ -180,7 +169,7 @@ public HostSettings(String domain, String urla) { bookSubjectSelector = ".novel-tags span"; break; case "lightnovelstranslations": - host = "https://lightnovelstranslations.com/"; + url = "https://lightnovelstranslations.com/"; ordinalIndexForBaseNovel = 4; chapterLinkSelecter = ".su-spoiler-content a"; chapterContainer = ".entry-content"; @@ -193,13 +182,12 @@ public HostSettings(String domain, String urla) { bookSubjectSelector = ""; break; case "boxnovel": - host = "https://boxnovel.com/"; + url = "https://boxnovel.com/"; ordinalIndexForBaseNovel = 5; chapterLinkSelecter = ".listing-chapters_wrap a"; chapterContainer = ".text-left"; - nextChapterBtn = ".btn.next_page"; titleHostName = ""; - blacklistedTags = new LinkedList<>(Arrays.asList("div.code-block")); + blacklistedTags = new LinkedList<>(Arrays.asList("div.code-block",".adbox")); bookTitleSelector = ".post-title h3"; bookDescSelector = "#editdescription"; bookCoverSelector = ".summary_image img"; @@ -207,11 +195,10 @@ public HostSettings(String domain, String urla) { bookSubjectSelector = ".genres-content a"; break; case "liberspark": - host = "https://liberspark.com/"; + url = "https://liberspark.com/"; ordinalIndexForBaseNovel = 5; chapterLinkSelecter = "#novel-chapters-list a.text-links"; chapterContainer = "#reader-content"; - nextChapterBtn = "a:contains(Next Chapter)"; titleHostName = "|LiberSpark"; blacklistedTags = new LinkedList<>(Arrays.asList("div.ad-wrapper")); bookTitleSelector = "h1[style=text-align:left]"; @@ -222,7 +209,7 @@ public HostSettings(String domain, String urla) { bookSubjectSelector = ""; break; case "chrysanthemumgarden": - host = "https://chrysanthemumgarden.com/"; + url = "https://chrysanthemumgarden.com/"; ordinalIndexForBaseNovel = 5; chapterLinkSelecter = ".translated-chapters a"; chapterContainer = "#novel-content"; @@ -237,32 +224,30 @@ public HostSettings(String domain, String urla) { ".sharedaddy", ".jum" )); - bookTitleSelector = "a[href=" + url + "]"; + bookTitleSelector = ".chapter-item a"; bookDescSelector = "false"; bookCoverSelector = "img.materialboxed"; bookAuthorSelector = ""; bookSubjectSelector = ".novel-container a[href^=https://chrysanthemumgarden.com/genre/]"; break; case "comrademao": - host = "https://comrademao.com/"; - ordinalIndexForBaseNovel = 0; - chapterLinkSelecter = "tbody a"; - chapterContainer = "article.post "; - nextChapterBtn = "a.btn.btn-default.btn-sm:has(i.fa-angle-right)"; - titleHostName = ""; - blacklistedTags = new LinkedList<>(Arrays.asList("script", "nav", ".container--indented", ".entry-meta", "p.chinese", "button")); - bookTitleSelector = "h3.entry-title"; - bookDescSelector = "#Description"; - bookCoverSelector = "#thumbnail img"; + url = "https://comrademao.com/"; + ordinalIndexForBaseNovel = 5; + chapterLinkSelecter = "tbody td a"; + chapterContainer = "section#content"; + titleHostName = " - Comrade Mao"; + blacklistedTags = new LinkedList<>(Arrays.asList(".hide","#advertisment","button")); + bookTitleSelector = "figure:nth-child(1) > h5:nth-child(1)"; + bookDescSelector = "#recentnovels > span:nth-child(1) > div:nth-child(2) > p:nth-child(3)"; + bookCoverSelector = "amp-img.i-amphtml-element"; bookAuthorSelector = "div.author"; bookSubjectSelector = "a[rel=tag]"; break; case "creativenovels": - host = "https://creativenovels.com/"; + url = "https://creativenovels.com/"; ordinalIndexForBaseNovel = 0; chapterLinkSelecter = ".post_box a"; chapterContainer = ".post"; - nextChapterBtn = "a.x-btn.nextkey"; titleHostName = ""; blacklistedTags = new LinkedList<>(Arrays.asList(".mNS", ".support-placement")); bookTitleSelector = "div.e45344-16.x-text.bK_C"; @@ -272,11 +257,10 @@ public HostSettings(String domain, String urla) { bookSubjectSelector = "div.genre_novel"; break; case "wordrain": - host = "https://wordrain69.com/"; + url = "https://wordrain69.com/"; ordinalIndexForBaseNovel = 5; chapterLinkSelecter = ".main li a"; chapterContainer = ".text-left"; - nextChapterBtn = ""; titleHostName = "-Wordrain69"; blacklistedTags = null; bookTitleSelector = ".post-title h1"; @@ -286,11 +270,10 @@ public HostSettings(String domain, String urla) { bookSubjectSelector = ".genres-content a"; break; case "wattpad": - host = "https://wattpad.com/"; + url = "https://wattpad.com/"; ordinalIndexForBaseNovel = 0; chapterLinkSelecter = ".table-of-contents a"; chapterContainer = "body"; - nextChapterBtn = ""; titleHostName = "-Wattpad"; blacklistedTags = new LinkedList<>(Arrays.asList("span.comment-marker")); bookTitleSelector = ".container h1"; @@ -300,11 +283,10 @@ public HostSettings(String domain, String urla) { bookSubjectSelector = ".tag-items li div.tag-item"; break; case "fanfiction": - host = "https://fanfiction.net/"; + url = "https://fanfiction.net/"; ordinalIndexForBaseNovel = 0; chapterLinkSelecter = "#chap_select option"; chapterContainer = "#storytext"; - nextChapterBtn = ""; titleHostName = "|FanFiction"; blacklistedTags = null; bookTitleSelector = "#profile_top b.xcontrast_txt"; @@ -314,11 +296,10 @@ public HostSettings(String domain, String urla) { bookSubjectSelector = ""; break; case "flyinglines": - host = "https://flying-lines.com/"; + url = "https://flying-lines.com/"; ordinalIndexForBaseNovel = 5; chapterLinkSelecter = ".volume-item li:has(i:not(.detail-chapter-locked)) a"; chapterContainer = "div.content"; - nextChapterBtn = ""; titleHostName = ""; blacklistedTags = null; bookTitleSelector = "div.title h2"; @@ -328,11 +309,10 @@ public HostSettings(String domain, String urla) { bookSubjectSelector = ".btn-category"; break; case "tapread": - host = "https://tapread.com/"; + url = "https://tapread.com/"; ordinalIndexForBaseNovel = 5; chapterLinkSelecter = ".chapter-list a:not(a:has(div.item-lock))"; chapterContainer = ".chapter-entity"; - nextChapterBtn = ""; titleHostName = ""; blacklistedTags = null; bookTitleSelector = ".book-name"; @@ -342,11 +322,10 @@ public HostSettings(String domain, String urla) { bookSubjectSelector = ".book-catalog .txt"; break; case "kuhakulightnoveltranslations": - host = "https://kuhakulightnoveltranslations.com/"; + url = "https://kuhakulightnoveltranslations.com/"; ordinalIndexForBaseNovel = 5; chapterLinkSelecter = "a.maxbutton"; chapterContainer = ".entry-content"; - nextChapterBtn = ""; titleHostName = ""; blacklistedTags = new LinkedList<>(Arrays.asList("p[style=text-align: center;]")); bookTitleSelector = "h1.entry-title"; @@ -356,11 +335,10 @@ public HostSettings(String domain, String urla) { bookSubjectSelector = ""; break; case "zenithnovels": - host = "https://zenithnovels.com/"; + url = "https://zenithnovels.com/"; ordinalIndexForBaseNovel = 5; chapterLinkSelecter = ".lcp_catlist li a"; chapterContainer = ".entry"; - nextChapterBtn = ".post-next a"; titleHostName = ""; blacklistedTags = new LinkedList<>(Arrays.asList("dl", ".code-block", "p:has(strong)", "hr")); bookTitleSelector = ".name.post-title.entry-title"; @@ -370,11 +348,10 @@ public HostSettings(String domain, String urla) { bookSubjectSelector = ""; break; case "translationotaku": - host = "https://translatinotaku.net/"; + url = "https://translatinotaku.net/"; ordinalIndexForBaseNovel = 5; chapterLinkSelecter = "section:has(nav) .elementor-posts-container a"; chapterContainer = ".elementor-widget-container:has(p)"; - nextChapterBtn = ".elementor-post-navigation__next a"; titleHostName = ""; blacklistedTags = new LinkedList<>(Arrays.asList("script", "div[style=position:relative;text-align:center!important]", "#videoad")); bookTitleSelector = ".elementor-heading-title"; @@ -384,11 +361,10 @@ public HostSettings(String domain, String urla) { bookSubjectSelector = ""; break; case "isohungrytls": - host = "https://isohungrytls.com/"; + url = "https://isohungrytls.com/"; ordinalIndexForBaseNovel = 5; chapterLinkSelecter = ".collapseomatic_content a"; // there is a space in the class nam chapterContainer = ".entry-content"; - nextChapterBtn = ""; titleHostName = ""; blacklistedTags = new LinkedList<>(Arrays.asList("span.ezoic-ad", "p[style=text-align: center;]", "hr", "p:has(span[style=color: #ffffff;])")); bookTitleSelector = "span[style=font-size: 24pt;]"; @@ -398,11 +374,10 @@ public HostSettings(String domain, String urla) { bookSubjectSelector = "p:contains(Genres:)"; break; case "ebisutranslations": - host = "https://ebisutranslations.com/"; + url = "https://ebisutranslations.com/"; ordinalIndexForBaseNovel = 5; chapterLinkSelecter = ".page_item a"; chapterContainer = "div.page-content:nth-child(4)"; - nextChapterBtn = ""; titleHostName = ""; blacklistedTags = new LinkedList<>(Arrays.asList("div:has(div[class=row])", "hr", "script", "div.widget", "span[id^=ezoic]", "span[class^=ezoic]", "#disqus_thread", ".navi-div")); bookTitleSelector = "h1.content-header"; @@ -412,11 +387,10 @@ public HostSettings(String domain, String urla) { bookSubjectSelector = "p:contains(GenrebookDescSelector = \"false\";s:)"; break; case "webnovel": - host = "https://webnovel.com/"; + url = "https://webnovel.com/"; ordinalIndexForBaseNovel = 5; chapterLinkSelecter = ".j_catalog_list a:not(a:has(svg))"; chapterContainer = "div[class^=chapter_content]"; - nextChapterBtn = ""; titleHostName = ""; blacklistedTags = new LinkedList<>(Arrays.asList("pirate", ".cha-hr", ".cha-info", ".cha-tit p", ".j_bottom_comment_area", ".user-links-wrap", ".g_ad_ph")); bookTitleSelector = "p.lh24.fs16.pt24.pb24.ell.c_000 span:not(span:contains(/))"; @@ -426,11 +400,10 @@ public HostSettings(String domain, String urla) { bookSubjectSelector = "a[href^=/category/list?category=].c_000"; break; case "wuxiaworld.online": - host = "https://wuxiaworld.online/"; + url = "https://wuxiaworld.online/"; ordinalIndexForBaseNovel = 4; chapterLinkSelecter = ".chapter-list a"; chapterContainer = ".content-area"; - nextChapterBtn = "a[title=Next chapter]"; titleHostName = ""; blacklistedTags = null; bookTitleSelector = "h1.entry-title"; @@ -440,11 +413,10 @@ public HostSettings(String domain, String urla) { bookSubjectSelector = ""; break; case "novelfull": - host = "http://novelfull.com/"; + url = "http://novelfull.com/"; ordinalIndexForBaseNovel = 4; chapterLinkSelecter = ".list-chapter a"; chapterContainer = "#chapter-content"; - nextChapterBtn = "#next_chap"; titleHostName = ""; blacklistedTags = new LinkedList<>(Arrays.asList("script", "ads", "div[align=left]", ".adsbygoogle", ".cha-tit p")); bookTitleSelector = "h3.title"; @@ -454,11 +426,10 @@ public HostSettings(String domain, String urla) { bookSubjectSelector = ".info > div:nth-child(2)"; break; case "wuxiaworld.site": - host = "https://wuxiaworld.site/"; + url = "https://wuxiaworld.site/"; ordinalIndexForBaseNovel = 5; chapterLinkSelecter = ".listing-chapters_wrap a"; chapterContainer = ".text-left"; - nextChapterBtn = ".btn.next_page"; titleHostName = ""; blacklistedTags = new LinkedList<>(Arrays.asList("script", "ad")); bookTitleSelector = ".post-title h3"; @@ -467,6 +438,19 @@ public HostSettings(String domain, String urla) { bookAuthorSelector = ".author-content"; bookSubjectSelector = ".genres-content a"; break; + default: + url = ""; + ordinalIndexForBaseNovel = 0; + chapterLinkSelecter = null; + chapterContainer = null; + titleHostName = null; + blacklistedTags = null; + bookTitleSelector = null; + bookDescSelector = null; + bookCoverSelector = null; + bookAuthorSelector = null; + bookSubjectSelector = null; + break; } } } diff --git a/src/grabber/ManNovel.java b/src/grabber/ManNovel.java index 37560dc..c87606b 100644 --- a/src/grabber/ManNovel.java +++ b/src/grabber/ManNovel.java @@ -1,260 +1,155 @@ -package grabber; - -import gui.GUI; -import gui.manSetMetadata; -import io.github.bonigarcia.wdm.WebDriverManager; -import org.jsoup.Jsoup; -import org.jsoup.nodes.Document; -import org.jsoup.nodes.Element; -import org.jsoup.select.Elements; -import org.openqa.selenium.WebDriver; -import org.openqa.selenium.chrome.ChromeDriver; -import org.openqa.selenium.chrome.ChromeOptions; -import org.openqa.selenium.edge.EdgeDriver; -import org.openqa.selenium.firefox.FirefoxDriver; -import org.openqa.selenium.firefox.FirefoxOptions; -import org.openqa.selenium.ie.InternetExplorerDriver; -import org.openqa.selenium.opera.OperaDriver; - -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -public class ManNovel extends AutoNovel { - public static List chapterLinks = new ArrayList<>(); - private static WebDriver driver; - private String chapterContainer; - - public ManNovel(GUI myGUI, String method) { - gui = myGUI; - chapterContainer = gui.manChapterContainer.getText(); - saveLocation = gui.manSaveLocation.getText(); - invertOrder = gui.manInvertOrder.isSelected(); - getImages = gui.manGetImages.isSelected(); - blacklistedTags = GUI.blacklistedTags; - waitTime = Integer.parseInt(gui.manWaitTime.getText()); - window = "manual"; - tocFileName = "Table of Contents"; - export = gui.manExportSelection.getSelectedItem().toString(); - noStyling = gui.manNoStyling.isSelected(); - displayChapterTitle = gui.manDispalyChapterTitleCheckbox.isSelected(); - bookDesc.add(0, ""); - killTask = false; - switch (method) { - case "chapterToChapter": - processChaptersToChapters(GUI.chapterToChapterArgs); - break; - case "chaptersFromList": - processChapersFromList(); - break; - } - manGetMetadata(); - if (!successfulFilenames.isEmpty() && !killTask) { - switch ((String) myGUI.manExportSelection.getSelectedItem()) { - case "Calibre": - shared.createToc(this); - break; - case "EPUB": - shared.createCoverPage(this); - shared.createToc(this); - if (!bookDesc.get(0).isEmpty() && !noDescription) shared.createDescPage(this); - ToEpub epub = new ToEpub(this); - break; - } - shared.report(this); - } - } - - /** - * Stores all hyperlinks from the given URL and displays them on the gui. - */ - public static void retrieveLinks(GUI gui) - throws IllegalArgumentException, IOException { - String url = gui.manNovelURL.getText(); - gui.appendText("manual", "Retrieving links from: " + url); - Document doc; - if (gui.manUseHeaderlessBrowser.isSelected()) { - driverSetup(gui); - driver.navigate().to(url); - String baseUrl = driver.getCurrentUrl().substring(0, shared.ordinalIndexOf(driver.getCurrentUrl(), "/", 3) + 1); - doc = Jsoup.parse(driver.getPageSource(), baseUrl); - driver.close(); - } else { - doc = Jsoup.connect(url).get(); - } - Elements links = doc.select("a[href]"); - String currChapterLink; - chapterLinks.clear(); - GUI.listModelChapterLinks.removeAllElements(); - for (Element chapterLink : links) { - currChapterLink = chapterLink.attr("abs:href"); - if (currChapterLink.startsWith("http") && !chapterLink.text().isEmpty()) { - chapterLinks.add(currChapterLink); - GUI.listModelChapterLinks.addElement(chapterLink.text()); - } - } - if (!chapterLinks.isEmpty()) gui.appendText("manual", chapterLinks.size() + " links retrieved."); - } - - /** - * Checks if chapter numeration is selected and set the file name accordingly. - */ - private static String manSetChapterName(int chapterNumber, boolean invertOrder) { - String fileName; - if (invertOrder) - fileName = GUI.listModelChapterLinks.get(GUI.listModelChapterLinks.getSize() - chapterNumber); - else fileName = GUI.listModelChapterLinks.get(chapterNumber - 1); - return fileName; - } - - private static void driverSetup(GUI gui) { - gui.appendText("manual", "[INFO]Starting headerless browser..."); - switch (gui.manBrowserCombobox.getSelectedItem().toString()) { - case "Chrome": - WebDriverManager.chromedriver().setup(); - driver = new ChromeDriver(new ChromeOptions().setHeadless(true)); - break; - case "Firefox": - WebDriverManager.firefoxdriver().setup(); - driver = new FirefoxDriver(new FirefoxOptions().setHeadless(true)); - break; - case "Opera": - WebDriverManager.operadriver().setup(); - driver = new OperaDriver(); - break; - case "Edge": - WebDriverManager.edgedriver().setup(); - driver = new EdgeDriver(); - break; - case "IE": - WebDriverManager.iedriver().setup(); - driver = new InternetExplorerDriver(); - break; - } - } - - /** - * Handles downloading chapters from provided list. - */ - void processChapersFromList() throws IllegalArgumentException { - String fileName; - int chapterNumber = 0; - gui.setMaxProgress(window, chapterLinks.size()); - if (invertOrder) Collections.reverse(chapterLinks); - if (gui.manUseHeaderlessBrowser.isSelected()) driverSetup(gui); - // Loop through all remaining chapter links and save them to file. - for (String chapterLink : chapterLinks) { - chapterNumber++; - fileName = manSetChapterName(chapterNumber, invertOrder); - if (gui.manUseHeaderlessBrowser.isSelected()) { - driver.navigate().to(chapterLink); - String baseUrl = driver.getCurrentUrl().substring(0, shared.ordinalIndexOf(driver.getCurrentUrl(), "/", 3) + 1); - String chapterHTML = String.valueOf(Jsoup.parse(driver.getPageSource(), baseUrl)); - shared.saveChapterFromString(chapterHTML, chapterNumber, fileName, chapterContainer, this); - } else { - shared.saveChapterWithHTML(chapterLink, chapterNumber, fileName, chapterContainer, this); - } - if (killTask) { - gui.appendText(window, "[INFO]Stopped."); - Path chaptersFolder = Paths.get(saveLocation + "/chapters"); - Path imagesFolder = Paths.get(saveLocation + "/images"); - try { - if (Files.exists(imagesFolder)) shared.deleteFolderAndItsContent(imagesFolder); - if (Files.exists(chaptersFolder)) shared.deleteFolderAndItsContent(chaptersFolder); - } catch (IOException e) { - gui.appendText(window, e.getMessage()); - e.printStackTrace(); - } - return; - } - shared.sleep(waitTime); - } - // Since chapter links are not getting cleared, they need to be re-inversed. - if (invertOrder) Collections.reverse(chapterLinks); - if (gui.manUseHeaderlessBrowser.isSelected()) driver.close(); - } - - /** - * Handles downloading chapter to chapter. - */ - void processChaptersToChapters(String[] args) { - gui.appendText(window, "[INFO]Connecting..."); - gui.setMaxProgress(window, 9001); - String nextChapter = args[0]; - String lastChapter = args[1]; - nextChapterBtn = args[2]; - int chapterNumber = GUI.chapterToChapterNumber; - //if (gui.manUseHeaderlessBrowser.isSelected()) driverSetup(gui); - while (true) { -/* if(gui.manUseHeaderlessBrowser.isSelected()) { - driver.navigate().to(nextChapter); - String baseUrl = driver.getCurrentUrl().substring(0, shared.ordinalIndexOf(driver.getCurrentUrl(), "/", 3) + 1); - String chapterHTML = String.valueOf(Jsoup.parse(driver.getPageSource(), baseUrl)); - shared.saveChapterFromString(chapterHTML, chapterNumber, "Chapter " + chapterNumber, - chapterContainer, this); - } else { - - }*/ - shared.saveChapterWithHTML(nextChapter, chapterNumber, "Chapter " + chapterNumber, chapterContainer, this); - nextChapter = nextChapterURL; - System.out.println(nextChapter); - if (nextChapter.equals(lastChapter) || (nextChapter + "/").equals(lastChapter)) { - chapterNumber++; - shared.sleep(waitTime); - nextChapterBtn = "NOT_SET"; -/* if(gui.manUseHeaderlessBrowser.isSelected()) { - driver.navigate().to(nextChapter); - String baseUrl = driver.getCurrentUrl().substring(0, shared.ordinalIndexOf(driver.getCurrentUrl(), "/", 3) + 1); - String chapterHTML = String.valueOf(Jsoup.parse(driver.getPageSource(), baseUrl)); - shared.saveChapterFromString(chapterHTML, chapterNumber, "Chapter " + chapterNumber, - chapterContainer, this); - } else { - - }*/ - shared.saveChapterWithHTML(nextChapter, chapterNumber, "Chapter " + chapterNumber, chapterContainer, this); - break; - } - if (killTask) { - gui.appendText(window, "[INFO]Stopped."); - Path chaptersFolder = Paths.get(saveLocation + "/chapters"); - Path imagesFolder = Paths.get(saveLocation + "/images"); - try { - if (Files.exists(imagesFolder)) shared.deleteFolderAndItsContent(imagesFolder); - if (Files.exists(chaptersFolder)) shared.deleteFolderAndItsContent(chaptersFolder); - } catch (IOException e) { - gui.appendText(window, e.getMessage()); - e.printStackTrace(); - } - return; - } - chapterNumber++; - shared.sleep(waitTime); - } - //if (gui.manUseHeaderlessBrowser.isSelected()) driver.close(); - } - - void manGetMetadata() { - if (manSetMetadata.manMetadataInfo[0] != null && !manSetMetadata.manMetadataInfo[0].isEmpty()) { - bookTitle = manSetMetadata.manMetadataInfo[0].replaceAll("[\\\\/:*?\"<>|]", ""); - } else bookTitle = "Unknown"; - if (manSetMetadata.manMetadataInfo[1] != null && !manSetMetadata.manMetadataInfo[1].isEmpty()) { - bookAuthor = manSetMetadata.manMetadataInfo[1]; - } else bookAuthor = "Unknown"; - if (manSetMetadata.manMetadataInfo[2] != null && !manSetMetadata.manMetadataInfo[2].isEmpty()) { - bookCover = manSetMetadata.manMetadataInfo[2]; - } - if (manSetMetadata.manMetadataInfo[3] != null && !manSetMetadata.manMetadataInfo[3].isEmpty()) { - bookDesc.add(manSetMetadata.manMetadataInfo[3]); - } else { - bookDesc.set(0, ""); - } - if (manSetMetadata.manMetadataTags != null && !manSetMetadata.manMetadataTags.isEmpty()) { - bookSubjects = manSetMetadata.manMetadataTags; - } - noDescription = manSetMetadata.noDescription; - } -} +package grabber; + +import gui.GUI; +import gui.manSetMetadata; +import org.jsoup.Jsoup; +import org.jsoup.nodes.Document; +import org.jsoup.nodes.Element; +import org.jsoup.select.Elements; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public class ManNovel extends Novel { + + public ManNovel(GUI myGUI) { + gui = myGUI; + host = new HostSettings("no_domain"); + metadata = new Metadata(this); + options = new Options(); + chapters = new ArrayList(); + } + + /** + * Stores all hyperlinks from the given URL and displays them on the gui. + */ + public void retrieveLinks() throws IllegalArgumentException, IOException { + gui.appendText("manual", "Retrieving links from: " + novelLink); + // Fetch webpage + if (options.headless) { + headless = new Driver(this); + headless.driver.navigate().to(novelLink); + String baseUrl = headless.driver.getCurrentUrl().substring(0, GrabberUtils.ordinalIndexOf(headless.driver.getCurrentUrl(), "/", 3) + 1); + tableOfContent = Jsoup.parse(headless.driver.getPageSource(), baseUrl); + headless.close(); + } else { + tableOfContent = Jsoup.connect(novelLink).get(); + } + chapters.clear(); + GUI.listModelChapterLinks.removeAllElements(); + // Add every link as a new chapter and add to gui + Elements links = tableOfContent.select("a[href]"); + for (Element chapterLink : links) { + if (chapterLink.attr("abs:href").startsWith("http") && !chapterLink.text().isEmpty()) { + chapters.add(new Chapter(chapterLink.text(),chapterLink.attr("abs:href"))); + gui.listModelChapterLinks.addElement(chapterLink.text()); + } + } + if (!chapters.isEmpty()) gui.appendText("manual", "[INFO]"+chapters.size() + " links retrieved."); + } + + /** + * Handles downloading chapters of a provided list. + */ + public void processChaptersFromList() throws Exception { + gui.setMaxProgress(options.window, chapters.size()); + if (options.invertOrder) Collections.reverse(chapters); + if (options.headless) headless = new Driver(this); + + for (Chapter chapter : chapters) { + if(killTask) { + // Remove already downloaded images and chapters + try { + Path chaptersFolder = Paths.get(options.saveLocation + "/chapters"); + Path imagesFolder = Paths.get(options.saveLocation + "/images"); + if (Files.exists(imagesFolder)) GrabberUtils.deleteFolderAndItsContent(imagesFolder); + if (Files.exists(chaptersFolder)) GrabberUtils.deleteFolderAndItsContent(chaptersFolder); + } catch (IOException e) { + gui.appendText(options.window, e.getMessage()); + e.printStackTrace(); + } + throw new Exception("Grabbing stopped."); + } + chapter.saveChapter(this); + gui.updateProgress(options.window); + GrabberUtils.sleep(options.waitTime); + } + + // Since chapter links are not getting cleared, they need to be re-inversed. + if (options.invertOrder) Collections.reverse(chapters); + if (options.headless) headless.close(); + } + + /** + * Handles downloading chapter to chapter. + */ + public void processChaptersToChapters(String[] args) throws Exception { + gui.appendText(options.window, "[INFO]Connecting..."); + gui.setMaxProgress(options.window, 9001); + nextChapterURL = args[0]; + String lastChapterURL = args[1]; + nextChapterBtn = args[2]; + // This chapter number is optional and is used to start the numbering at higher chapters + int chapterNumber = GUI.chapterToChapterNumber; + // Driver is used by each Chapter to visit the webpage + if (options.headless) headless = new Driver(this); + while (true) { + if(killTask) { + // Remove already downloaded images and chapters + try { + Path chaptersFolder = Paths.get(options.saveLocation + "/chapters"); + Path imagesFolder = Paths.get(options.saveLocation + "/images"); + if (Files.exists(imagesFolder)) GrabberUtils.deleteFolderAndItsContent(imagesFolder); + if (Files.exists(chaptersFolder)) GrabberUtils.deleteFolderAndItsContent(chaptersFolder); + } catch (IOException e) { + gui.appendText(options.window, e.getMessage()); + e.printStackTrace(); + } + throw new Exception("Grabbing stopped."); + } + Chapter currentChapter = new Chapter("Chapter " + chapterNumber++, nextChapterURL); + chapters.add(currentChapter); + currentChapter.saveChapter(this); + gui.updateProgress(options.window); + // Reached final chapter + if (nextChapterURL.equals(lastChapterURL) || (nextChapterURL + "/").equals(lastChapterURL)) { + GrabberUtils.sleep(options.waitTime); + nextChapterBtn = "NOT_SET"; + currentChapter = new Chapter("Chapter " + chapterNumber++, nextChapterURL); + chapters.add(currentChapter); + currentChapter.saveChapter(this); + gui.updateProgress(options.window); + break; + } + GrabberUtils.sleep(options.waitTime); + } + } + + /** + * Set metadata specified in metadata GUI dialog + */ + public void manGetMetadata() { + if (manSetMetadata.manMetadataInfo[0] != null && !manSetMetadata.manMetadataInfo[0].isEmpty()) { + metadata.bookTitle = manSetMetadata.manMetadataInfo[0].replaceAll("[\\\\/:*?\"<>|]", ""); + } else metadata.bookTitle = "Unknown"; + if (manSetMetadata.manMetadataInfo[1] != null && !manSetMetadata.manMetadataInfo[1].isEmpty()) { + metadata.bookAuthor = manSetMetadata.manMetadataInfo[1]; + } else metadata.bookAuthor = "Unknown"; + if (manSetMetadata.manMetadataInfo[2] != null && !manSetMetadata.manMetadataInfo[2].isEmpty()) { + metadata.bookCover = manSetMetadata.manMetadataInfo[2]; + } + if (manSetMetadata.manMetadataInfo[3] != null && !manSetMetadata.manMetadataInfo[3].isEmpty()) { + metadata.bookDesc.add(manSetMetadata.manMetadataInfo[3]); + } else { + metadata.bookDesc.add(0, ""); + } + if (manSetMetadata.manMetadataTags != null && !manSetMetadata.manMetadataTags.isEmpty()) { + metadata.bookSubjects = manSetMetadata.manMetadataTags; + } + } +} diff --git a/src/grabber/Metadata.java b/src/grabber/Metadata.java new file mode 100644 index 0000000..b74aa80 --- /dev/null +++ b/src/grabber/Metadata.java @@ -0,0 +1,138 @@ +package grabber; + +import org.jsoup.nodes.Element; +import org.jsoup.select.Elements; + +import java.awt.image.BufferedImage; +import java.util.ArrayList; +import java.util.List; + +public class Metadata { + public String bookTitle; + public String bookAuthor; + public List bookSubjects = new ArrayList(); + public List bookDesc = new ArrayList(); + public BufferedImage bufferedCover; + public String bufferedCoverName; + public String bookCover; + public int wordCount = 0; + private Novel novel; + + public Metadata(Novel novel) { + this.novel = novel; + // Reset info on GUI + novel.gui.autoBookTitle.setText(""); + novel.gui.autoAuthor.setText(""); + novel.gui.autoChapterAmount.setText(""); + novel.gui.setBufferedCover(null); + novel.gui.autoBookSubjects.setText(""); + } + + void getTitle() { + if (!novel.host.bookTitleSelector.isEmpty()) { + if (novel.tableOfContent.select(novel.host.bookTitleSelector) != null && !novel.tableOfContent.select(novel.host.bookTitleSelector).isEmpty()) { + bookTitle = novel.tableOfContent.select(novel.host.bookTitleSelector).first().text().replaceAll("[\\\\/:*?\"<>|]", ""); + novel.gui.autoBookTitle.setText(bookTitle); + } else { + bookTitle = "Unknown"; + novel.gui.autoBookTitle.setText("Unknown"); + } + } else { + bookTitle = "Unknown"; + novel.gui.autoBookTitle.setText("Unknown"); + } + } + + void getDesc() { + if (!novel.host.bookDescSelector.equals("false")) { + if (novel.tableOfContent.select(novel.host.bookDescSelector) != null && !novel.tableOfContent.select(novel.host.bookDescSelector).isEmpty()) { + bookDesc.add(0, novel.tableOfContent.select(novel.host.bookDescSelector).first().text()); + } else { + bookDesc.add(0, ""); + } + } else { + bookDesc.add(0, ""); + } + } + + + void getAuthor() { + if (!novel.host.bookAuthorSelector.isEmpty()) { + if (novel.tableOfContent.select(novel.host.bookAuthorSelector) != null && !novel.tableOfContent.select(novel.host.bookAuthorSelector).isEmpty()) { + bookAuthor = novel.tableOfContent.select(novel.host.bookAuthorSelector).first().text(); + novel.gui.autoAuthor.setText(bookAuthor); + } else { + bookAuthor = "Unknown"; + novel.gui.autoAuthor.setText("Unknown"); + } + } else { + bookAuthor = "Unknown"; + novel.gui.autoAuthor.setText("Unknown"); + } + } + + void getTags() { + if (!novel.host.bookSubjectSelector.isEmpty()) { + if (novel.tableOfContent.select(novel.host.bookSubjectSelector) != null && !novel.tableOfContent.select(novel.host.bookSubjectSelector).isEmpty()) { + Elements tags = novel.tableOfContent.select(novel.host.bookSubjectSelector); + for (Element tag : tags) { + bookSubjects.add(tag.text()); + } + + // Display book subjects on GUI + int maxNumberOfSubjects = 0; + novel.gui.autoBookSubjects.setText(""); + for (String eachTag : bookSubjects) { + novel.gui.autoBookSubjects.setText(novel.gui.autoBookSubjects.getText() + eachTag + ", "); + maxNumberOfSubjects++; + if (maxNumberOfSubjects == 4) { + maxNumberOfSubjects = 0; + novel.gui.autoBookSubjects.setText(novel.gui.autoBookSubjects.getText() + "
"); + } + } + if (!novel.gui.autoBookSubjects.getText().isEmpty()) { + novel.gui.autoBookSubjects.setText( + novel.gui.autoBookSubjects.getText().substring(0, + novel.gui.autoBookSubjects.getText().lastIndexOf(","))); + } + } else { + bookSubjects.add("Unknown"); + novel.gui.autoBookSubjects.setText("Unknown"); + } + } else { + bookSubjects.add("Unknown"); + novel.gui.autoBookSubjects.setText("Unknown"); + } + } + + void getChapterNumber() { + if (!novel.chapters.isEmpty()) { + novel.gui.autoChapterAmount.setText(String.valueOf(novel.chapters.size())); + novel.gui.autoGetNumberButton.setEnabled(true); + } + } + + void getCover() { + if (!novel.host.bookCoverSelector.isEmpty()) { + if (novel.tableOfContent.select(novel.host.bookCoverSelector) != null && !novel.tableOfContent.select(novel.host.bookCoverSelector).isEmpty()) { + Element coverSelect = novel.tableOfContent.select(novel.host.bookCoverSelector).first(); + if (coverSelect != null) { + String coverLink = coverSelect.attr("abs:src"); + // Custom + if (novel.host.url.equals("https://wordexcerpt.com/")) + coverLink = coverSelect.attr("data-src"); + if (novel.host.url.equals("https://webnovel.com/")) { + coverLink = coverLink.replace("/300/300", "/600/600"); + } + bufferedCover = GrabberUtils.getBufferedCover(coverLink, novel); + novel.gui.setBufferedCover(bufferedCover); + bookCover = novel.imageNames.get(0); + /* downloadImage() adds every image to and this interferes with + the cover image when adding images from these to the epub */ + novel.imageNames.clear(); + novel.imageLinks.clear(); + } + } + } + } +} diff --git a/src/grabber/Novel.java b/src/grabber/Novel.java new file mode 100644 index 0000000..3635319 --- /dev/null +++ b/src/grabber/Novel.java @@ -0,0 +1,370 @@ +package grabber; + +import gui.GUI; +import org.jsoup.Jsoup; +import org.jsoup.nodes.Document; +import org.jsoup.nodes.Element; +import org.jsoup.select.Elements; + +import javax.imageio.ImageIO; +import java.io.*; +import java.net.*; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +public class Novel { + public GUI gui; + public List chapters; + public Metadata metadata; + public Options options; + public HostSettings host; + public Driver headless; + + Document tableOfContent; + public String novelLink; + String nextChapterBtn; + String nextChapterURL; + public boolean killTask; + private boolean reGrab = false; + List extraPages = new ArrayList<>(); + List imageLinks = new ArrayList<>(); + List imageNames = new ArrayList<>(); + + private static final String NL = System.getProperty("line.separator"); + private static final String htmlHead = "" + NL + "" + NL + "" + NL + + "" + NL + "" + NL + "" + NL; + private static final String htmlFoot = "" + NL + ""; + + public Novel() {} + public Novel(GUI gui) { + this.gui = gui; + String hostname = gui.autoHostSelection.getSelectedItem().toString().toLowerCase().replace(" ", ""); + novelLink = gui.chapterListURL.getText(); + host = new HostSettings(hostname); + metadata = new Metadata(this); + options = new Options(); + chapters = new ArrayList(); + } + + public void getChapterList() { + gui.appendText("auto", "[INFO]Fetching novel info..."); + try { + // Headless + if(options.headless) { + headless = new Driver(this); + chapters = headless.getChapterList(); + // Static + } else { + // Custom chapter selection + switch (host.url) { + case "https://boxnovel.com/": + tableOfContent = Jsoup.connect(novelLink).timeout(30 * 1000).get(); + Elements chapterLinks = tableOfContent.select(host.chapterLinkSelecter); + for(Element chapterLink: chapterLinks) { + chapters.add(new Chapter(chapterLink.text(), chapterLink.attr("abs:href"))); + } + // Get link of last chapter (first in novel context) + String boxNovelFirstChapter = chapters.get(chapters.size()-1).chapterURL; + String boxNovelbaseLinkStart = boxNovelFirstChapter.substring(0, GrabberUtils.ordinalIndexOf(boxNovelFirstChapter, "/", 5) + 9); + String boxNovelChapterNumberString = boxNovelFirstChapter.substring(boxNovelbaseLinkStart.length()); + int boxNovelChapterNumber; + if(boxNovelChapterNumberString.contains("-")) { + boxNovelChapterNumber = Integer.valueOf(boxNovelChapterNumberString.substring(0,boxNovelChapterNumberString.indexOf("-"))); + } else { + boxNovelChapterNumber = Integer.valueOf(boxNovelChapterNumberString); + } + if (boxNovelChapterNumber != 1) { + for (int i = boxNovelChapterNumber - 1; i >= 1; i--) { + chapters.add(new Chapter("Chapter " + i, boxNovelbaseLinkStart + i)); + } + } + break; + case "http://novelfull.com/": + tableOfContent = Jsoup.connect(novelLink).timeout(30 * 1000).get(); + while (!tableOfContent.select("li.next").hasClass("disabled")) { + chapterLinks = tableOfContent.select(host.chapterLinkSelecter); + for (Element chapterLink : chapterLinks) { + chapters.add(new Chapter(chapterLink.text(), chapterLink.attr("abs:href"))); + } + tableOfContent = Jsoup.connect(tableOfContent.select("li.next a").attr("abs:href")).timeout(30 * 1000).get(); + } + chapterLinks = tableOfContent.select(host.chapterLinkSelecter); + for (Element chapterLink : chapterLinks) { + chapters.add(new Chapter(chapterLink.text(), chapterLink.attr("abs:href"))); + } + break; + case "https://zenithnovels.com/": + tableOfContent = Jsoup.connect(novelLink).timeout(30 * 1000).get(); + while (!tableOfContent.select(".lcp_paginator a.lcp_nextlink").attr("abs:href").isEmpty()) { + chapterLinks = tableOfContent.select(host.chapterLinkSelecter); + for (Element chapterLink : chapterLinks) { + chapters.add(new Chapter(chapterLink.text(), chapterLink.attr("abs:href"))); + } + tableOfContent = Jsoup.connect(tableOfContent.select(".lcp_paginator a.lcp_nextlink").attr("abs:href")).timeout(30 * 1000).get(); + } + chapterLinks = tableOfContent.select(host.chapterLinkSelecter); + for (Element chapterLink : chapterLinks) { + chapters.add(new Chapter(chapterLink.text(), chapterLink.attr("abs:href"))); + } + break; + case "https://translatinotaku.net/": + tableOfContent = Jsoup.connect(novelLink).timeout(30 * 1000).get(); + while (!tableOfContent.select("a.page-numbers.next").attr("abs:href").isEmpty()) { + chapterLinks = tableOfContent.select(host.chapterLinkSelecter); + for (Element chapterLink : chapterLinks) { + chapters.add(new Chapter(chapterLink.text(), chapterLink.attr("abs:href"))); + } + tableOfContent = Jsoup.connect(tableOfContent.select("a.page-numbers.next").attr("abs:href")).timeout(30 * 1000).get(); + } + chapterLinks = tableOfContent.select(host.chapterLinkSelecter); + for (Element chapterLink : chapterLinks) { + chapters.add(new Chapter(chapterLink.text(), chapterLink.attr("abs:href"))); + + } + break; + case "https://comrademao.com/": + tableOfContent = Jsoup.connect(novelLink).timeout(30 * 1000).get(); + while (!tableOfContent.select(".pagination a.next").attr("abs:href").isEmpty()) { + chapterLinks = tableOfContent.select(host.chapterLinkSelecter); + for (Element chapterLink : chapterLinks) { + chapters.add(new Chapter(chapterLink.text(), chapterLink.attr("abs:href"))); + } + tableOfContent = Jsoup.connect(tableOfContent.select(".pagination a.next").attr("abs:href")).timeout(30 * 1000).get(); + } + chapterLinks = tableOfContent.select(host.chapterLinkSelecter); + for (Element chapterLink : chapterLinks) { + chapters.add(new Chapter(chapterLink.text(), chapterLink.attr("abs:href"))); + } + break; + case "https://wuxiaworld.online/": + tableOfContent = Jsoup.connect(novelLink).timeout(30 * 1000).get(); + chapterLinks = tableOfContent.select(host.chapterLinkSelecter); + for (Element chapterLink : chapterLinks) { + chapters.add(new Chapter(chapterLink.text(), chapterLink.attr("abs:href"))); + } + // Get href link of last chapter (first in novel context) + String wuxiaonlineFirstChapter = chapters.get(chapterLinks.size() - 1).chapterURL; + String wuxiaonlinebaseLinkStart = wuxiaonlineFirstChapter.substring(0, GrabberUtils.ordinalIndexOf(wuxiaonlineFirstChapter, "/", 4) + 9); + String wuxiaonlineChapterNumberString = wuxiaonlineFirstChapter.substring(wuxiaonlinebaseLinkStart.length()); + int wuxiaonlineChapterNumber; + if(wuxiaonlineChapterNumberString.contains("-")) + wuxiaonlineChapterNumber = Integer.valueOf(wuxiaonlineChapterNumberString.substring(0,wuxiaonlineChapterNumberString.indexOf("-"))); + else + wuxiaonlineChapterNumber = Integer.valueOf(wuxiaonlineChapterNumberString); + if(wuxiaonlineChapterNumber != 1) { + for(int i = wuxiaonlineChapterNumber-1; i >= 1; i--) { + chapters.add(new Chapter("Chapter "+i, wuxiaonlinebaseLinkStart+i)); + } + } + break; + case "https://fanfiction.net/": + tableOfContent = Jsoup.connect(novelLink).timeout(30 * 1000).get(); + chapterLinks = tableOfContent.select(host.chapterLinkSelecter); + String fullLink = tableOfContent.select("link[rel=canonical]").attr("abs:href"); + String baseLinkStart = fullLink.substring(0, GrabberUtils.ordinalIndexOf(fullLink, "/", 5) + 1); + String baseLinkEnd = fullLink.substring(baseLinkStart.length() + 1); + chapterLinks = chapterLinks.select("option[value]"); + for(int i = 0; i < chapterLinks.size() / 2; i++) + chapters.add(new Chapter(chapterLinks.get(i).text(),baseLinkStart + chapterLinks.get(i).attr("value") + baseLinkEnd)); + break; + // Is a reskin of fanction.net + case "https://fanfiktion.de/": + tableOfContent = Jsoup.connect(novelLink).timeout(30 * 1000).get(); + chapterLinks = tableOfContent.select(host.chapterLinkSelecter); + fullLink = tableOfContent.select("link[rel=canonical]").attr("abs:href"); + baseLinkStart = fullLink.substring(0, GrabberUtils.ordinalIndexOf(fullLink, "/", 5) + 1); + baseLinkEnd = fullLink.substring(baseLinkStart.length() + 1); + chapterLinks = chapterLinks.select("option[value]"); + for(int i = 0; i < chapterLinks.size(); i++) + chapters.add(new Chapter(chapterLinks.get(i).text(),baseLinkStart + chapterLinks.get(i).attr("value") + baseLinkEnd)); + break; + case "https://tapread.com/": + tableOfContent = Jsoup.connect(novelLink).timeout(30 * 1000).get(); + String novelURL = gui.chapterListURL.getText(); + int tapReadNovelId = Integer.parseInt(novelURL.substring(novelURL.lastIndexOf("/") + 1)); + Map chapterMap = xhrRequest.tapReadGetChapterList(tapReadNovelId); + int i = 0; + for (String chapterId : chapterMap.keySet()) { + chapters.add(new Chapter(chapterMap.get(chapterId), "https://tapread.com/book/index/" + tapReadNovelId + "/" + chapterId)); + chapters.get(i).xhrBookId = tapReadNovelId; + chapters.get(i).xhrChapterId = chapterId; + i++; + } + break; + case "https://webnovel.com/": + tableOfContent = Jsoup.connect(novelLink).timeout(30 * 1000).get(); + String csrfToken = "null"; + String bookId = gui.chapterListURL.getText(); + String bookTitle = tableOfContent.select(host.bookTitleSelector).first().text().replaceAll("[\\\\/:*?\"<>|]", ""); + bookId = bookId.substring(GrabberUtils.ordinalIndexOf(bookId, "/", 4) + 1, GrabberUtils.ordinalIndexOf(bookId, "/", 5)); + + String otherParameter = ""; + CookieManager cookieManager = new CookieManager(); + CookieHandler.setDefault(cookieManager); + + URL url = new URL(novelLink); + URLConnection connection = url.openConnection(); + connection.getContent(); + + List cookies = cookieManager.getCookieStore().getCookies(); + for (HttpCookie cookie : cookies) { + if (cookie.toString().startsWith("_csrfToken")) { + csrfToken = cookie.toString().substring(11); + } + } + Map webnovelChapters = xhrRequest.webnovelGetChapterList( + "https://www.webnovel.com/apiajax/chapter/GetChapterList?_csrfToken=" + csrfToken + "&bookId=" + bookId + "&_=" + otherParameter); + int webnovelChapterNumber = 1; + for (String chapterId : webnovelChapters.keySet()) { + chapters.add(new Chapter("Chapter " + webnovelChapterNumber + ": " + webnovelChapters.get(chapterId), "https://www.webnovel.com/book/" + bookId + "/" + chapterId + "/" + + bookTitle.replace(" ", "-") + "/" + webnovelChapters.get(chapterId).replace(" ", "-"))); + webnovelChapterNumber++; + } + break; + + case "https://gravitytales.com/": + //Chapter list at gravitytales.com/Novel/chapters + tableOfContent = Jsoup.connect(novelLink+"/chapters").timeout(30 * 1000).get(); + for (Element chapterLink : tableOfContent.select(host.chapterLinkSelecter)) { + chapters.add(new Chapter(chapterLink.text(), chapterLink.attr("abs:href"))); + } + // Fetch "table of contents" page for metadata + tableOfContent = Jsoup.connect(novelLink).timeout(30 * 1000).get(); + break; + default: + tableOfContent = Jsoup.connect(novelLink).timeout(30 * 1000).get(); + for (Element chapterLink : tableOfContent.select(host.chapterLinkSelecter)) { + chapters.add(new Chapter(chapterLink.text(), chapterLink.attr("abs:href"))); + } + break; + } + } + } catch (IOException e) { + e.printStackTrace(); + gui.appendText("auto", "[ERROR]"+e.getMessage()); + } + } + + public void downloadChapters() throws Exception { + gui.setMaxProgress(options.window, options.lastChapter-options.firstChapter+1); + if(reGrab) { + metadata.wordCount = 0; + for(Chapter chapter: chapters) chapter.status = 0; + } + if(options.invertOrder) Collections.reverse(chapters); // Will get un-reversed for potential re-grab in report(); + // -1 since chapter numbers start at 1 + for(int i = options.firstChapter-1; i < options.lastChapter; i++) { + if(killTask) { + // Remove already downloaded images and chapters + try { + Path chaptersFolder = Paths.get(options.saveLocation + "/chapters"); + Path imagesFolder = Paths.get(options.saveLocation + "/images"); + if (Files.exists(imagesFolder)) GrabberUtils.deleteFolderAndItsContent(imagesFolder); + if (Files.exists(chaptersFolder)) GrabberUtils.deleteFolderAndItsContent(chaptersFolder); + } catch (IOException e) { + gui.appendText(options.window, e.getMessage()); + } + throw new Exception("Grabbing stopped."); + } + chapters.get(i).saveChapter(this); + gui.updateProgress(options.window); + GrabberUtils.sleep(options.waitTime); + } + reGrab = true; + } + + public void getMetadata() { + metadata.getTitle(); + metadata.getDesc(); + metadata.getAuthor(); + metadata.getTags(); + metadata.getChapterNumber(); + metadata.getCover(); + } + + /** + * Extra pages for EPUB + */ + public void createCoverPage() { + // Write buffered cover to save location + if (metadata.bufferedCover != null && metadata.bookCover != null) { + try { + File outputfile = new File(options.saveLocation + File.separator + "images" + File.separator + metadata.bufferedCoverName); + if (!outputfile.exists()) outputfile.mkdirs(); + ImageIO.write(metadata.bufferedCover, metadata.bufferedCoverName.substring(metadata.bufferedCoverName.lastIndexOf(".") + 1), outputfile); + } catch (IOException e) { + gui.appendText(options.window, "[ERROR]Could not write cover image to file."); + } + } + String fileName = "cover_Page"; + String filePath = options.saveLocation + File.separator + "chapters" + File.separator + fileName +".html"; + String imageName = metadata.bookCover; + imageName = GrabberUtils.getFileName(imageName); + try (PrintStream out = new PrintStream(filePath, StandardCharsets.UTF_8)) { + out.print(htmlHead + "
" + NL); + out.println(""); + out.print("
" + NL + htmlFoot); + extraPages.add(fileName); + } catch (IOException e) { + gui.appendText(options.window, e.getMessage()); + e.printStackTrace(); + } + } + + public void createToc() { + String fileName = "table_of_contents"; + String filePath = options.saveLocation + File.separator + "chapters" + File.separator + fileName+ ".html"; + try (PrintStream out = new PrintStream(filePath , StandardCharsets.UTF_8)) { + out.print(htmlHead + "Table of Contents" + NL + "

" + NL); + for (Chapter chapter: chapters) { + if(chapter.status == 1) + out.println("" + chapter.name + "
"); + } + out.print("

" + NL + htmlFoot); + extraPages.add(fileName); + } catch (IOException e) { + gui.appendText(options.window, e.getMessage()); + e.printStackTrace(); + } + } + + public void createDescPage() { + String fileName = "desc_Page"; + String filePath = options.saveLocation + File.separator + "chapters" + File.separator + fileName + ".html"; + try (PrintStream out = new PrintStream(filePath, StandardCharsets.UTF_8)) { + out.print(htmlHead + "
Description" + NL); + out.println("

" + metadata.bookDesc.get(0) + "

"); + out.print("
" + NL + htmlFoot); + extraPages.add(fileName); + } catch (IOException e) { + gui.appendText(options.window, e.getMessage()); + e.printStackTrace(); + } + } + + public void createEPUB() { + EPUB epub = new EPUB(this); + } + + /** + Prints potential failed chapters. Reverses the chapter list again for next grabbing + and closes the headless driver if used. + */ + public void report() { + gui.appendText(options.window, "[INFO]Finished."); + if(options.invertOrder) Collections.reverse(chapters); + // Print failed chapters + for(Chapter chapter: chapters) { + if(chapter.status == 2) + gui.appendText(options.window,"[WARN]Failed to grab: " +chapter.name); + } + if(options.headless) headless.close(); + } + +} \ No newline at end of file diff --git a/src/grabber/Options.java b/src/grabber/Options.java new file mode 100644 index 0000000..4feb1a9 --- /dev/null +++ b/src/grabber/Options.java @@ -0,0 +1,19 @@ +package grabber; +// Dataclass for better readability +public class Options { + public boolean removeStyling = false; + public boolean getImages = false; + public boolean displayChapterTitle = false; + public boolean noDescription = false; + public boolean invertOrder = false; + public boolean headless = false; + public int waitTime = 0; + public int firstChapter; + public int lastChapter; + public String saveLocation; + public String window; + public String browser; + + public Options() { + } +} diff --git a/src/grabber/ToEpub.java b/src/grabber/ToEpub.java deleted file mode 100644 index f8bd65e..0000000 --- a/src/grabber/ToEpub.java +++ /dev/null @@ -1,130 +0,0 @@ -package grabber; - -import nl.siegmann.epublib.domain.Author; -import nl.siegmann.epublib.domain.Book; -import nl.siegmann.epublib.domain.Metadata; -import nl.siegmann.epublib.domain.Resource; -import nl.siegmann.epublib.epub.EpubWriter; - -import java.io.*; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; - -class ToEpub { - private FileInputStream inputStream; - private Resource resource; - - ToEpub(AutoNovel currGrab) { - writeEpub(currGrab); - } - - private void writeEpub(AutoNovel currGrab) { - try { - currGrab.gui.appendText(currGrab.window, "[INFO]Writing epub..."); - // Create new Book - Book book = new Book(); - Metadata metadata = book.getMetadata(); - // Title - if (currGrab.bookTitle != null && !currGrab.bookTitle.isEmpty()) { - metadata.addTitle(currGrab.bookTitle); - } else { - metadata.addTitle("Unknown"); - } - // Author - if (currGrab.bookAuthor != null && !currGrab.bookAuthor.isEmpty() && !currGrab.bookAuthor.equals("null")) { - metadata.addAuthor(new Author(currGrab.bookAuthor)); - } else { - metadata.addAuthor(new Author("Unknown")); - } - // Subjects - if (currGrab.bookSubjects != null && !currGrab.bookSubjects.isEmpty()) { - metadata.setSubjects(currGrab.bookSubjects); - } - // Description - if (currGrab.bookDesc != null && !currGrab.bookDesc.get(0).isEmpty() && !currGrab.noDescription) { - metadata.setDescriptions(currGrab.bookDesc); - } - // Set cover image & page - if (currGrab.bookCover != null && !currGrab.bookCover.isEmpty()) { - if (currGrab.window.equals("auto")) { - // Add cover image as a resource - inputStream = new FileInputStream(currGrab.saveLocation + "/images/" + currGrab.bookCover); - resource = new Resource(inputStream, currGrab.bookCover); - book.getResources().add(resource); - book.setCoverImage(resource); - inputStream.close(); - } else { - // Add manual cover image. Its saved as a full path - inputStream = new FileInputStream(currGrab.bookCover); - resource = new Resource(inputStream, shared.getFileName(currGrab.bookCover)); - book.getResources().add(resource); - book.setCoverImage(resource); - inputStream.close(); - } - // Adding cover page - inputStream = new FileInputStream(currGrab.saveLocation + "/chapters/" - + currGrab.successfulExtraPagesFilenames.get(0) + ".html"); - resource = new Resource(inputStream, currGrab.successfulExtraPagesFilenames.get(0) + ".html"); - book.setCoverPage(resource); - book.addSection(currGrab.successfulExtraPagesNames.get(0), resource); - inputStream.close(); - } else { - book.setCoverImage(new Resource(getClass().getResourceAsStream("/images/cover_placeholder.png"), "cover_placeholder.png")); - - } - // Description page - if (currGrab.bookDesc != null && !currGrab.bookDesc.get(0).isEmpty() && !currGrab.noDescription) { - inputStream = new FileInputStream(currGrab.saveLocation + "/chapters/" - + currGrab.successfulExtraPagesFilenames.get(2) + ".html"); - resource = new Resource(inputStream, currGrab.successfulExtraPagesFilenames.get(2) + ".html"); - book.addSection(currGrab.successfulExtraPagesNames.get(2), resource); - inputStream.close(); - } - // Table of Contents - inputStream = new FileInputStream(currGrab.saveLocation + "/chapters/" - + currGrab.successfulExtraPagesFilenames.get(1) + ".html"); - resource = new Resource(inputStream, currGrab.successfulExtraPagesFilenames.get(1) + ".html"); - book.addSection(currGrab.successfulExtraPagesNames.get(1), resource); - inputStream.close(); - - // Chapters - for (int i = 0; i < currGrab.successfulFilenames.size(); i++) { - inputStream = new FileInputStream(currGrab.saveLocation + "/chapters/" - + currGrab.successfulFilenames.get(i) + ".html"); - resource = new Resource(inputStream, currGrab.successfulFilenames.get(i) + ".html"); - book.addSection(currGrab.successfulChapterNames.get(i), resource); - inputStream.close(); - } - // Add used images - if (currGrab.getImages) { - for (String imageName : currGrab.imageNames) { - inputStream = new FileInputStream(currGrab.saveLocation + "/images/" + imageName); - resource = new Resource(inputStream, imageName); - book.getResources().add(resource); - inputStream.close(); - } - } - // Add css file - book.getResources().add(new Resource(getClass().getResourceAsStream("/files/default.css"), "default.css")); - // Create EpubWriter - EpubWriter epubWriter = new EpubWriter(); - // Write the Book as Epub - epubWriter.write(book, new FileOutputStream(currGrab.saveLocation + File.separator + currGrab.bookTitle + ".epub")); - currGrab.gui.appendText(currGrab.window, "[INFO]Epub successfully created."); - - // Delete image and chapter files - Path chaptersFolder = Paths.get(currGrab.saveLocation + "/chapters"); - Path imagesFolder = Paths.get(currGrab.saveLocation + "/images"); - - if (Files.exists(imagesFolder)) shared.deleteFolderAndItsContent(imagesFolder); - if (Files.exists(chaptersFolder)) shared.deleteFolderAndItsContent(chaptersFolder); - - } catch (FileNotFoundException e) { - currGrab.gui.appendText(currGrab.window, "[ERROR]" + e.getMessage()); - e.printStackTrace(); - } catch (IOException e) { - e.printStackTrace(); - } - } -} diff --git a/src/grabber/shared.java b/src/grabber/shared.java deleted file mode 100644 index 74a4c58..0000000 --- a/src/grabber/shared.java +++ /dev/null @@ -1,452 +0,0 @@ -package grabber; - -import org.jsoup.Jsoup; -import org.jsoup.nodes.Document; -import org.jsoup.nodes.Element; - -import javax.imageio.ImageIO; -import java.awt.image.BufferedImage; -import java.io.*; -import java.net.HttpURLConnection; -import java.net.URL; -import java.nio.file.FileVisitResult; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.SimpleFileVisitor; -import java.nio.file.attribute.BasicFileAttributes; - -/** - * Collection of shared functions. - */ -public class shared { - private static final String textEncoding = "UTF-8"; - private static final String NL = System.getProperty("line.separator"); - private static String htmlHead = "" + NL + "" + NL + "" + NL - + "" + NL + "" + NL + "" + NL; - private static String htmlFoot = "" + NL + ""; - - /** - * Freeze thread for selected wait time. - */ - static void sleep(int waitTime) { - try { - Thread.sleep(waitTime); - } catch (InterruptedException ex) { - Thread.currentThread().interrupt(); - } - } - - /** - * Processes a successful chapter. - */ - private static void successfulChapter(String fileName, String chapterName, AutoNovel currGrab) { - currGrab.successfulChapterNames.add(chapterName); - currGrab.successfulFilenames.add(fileName); - currGrab.gui.appendText(currGrab.window, "[INFO]" + chapterName + " saved."); - currGrab.gui.updateProgress(currGrab.window); - currGrab.gui.pagesCountLbl.setText(String.valueOf(currGrab.wordCount / 300)); - } - - /** - * Prints potential failed chapters after chapter grabs. - */ - static void report(AutoNovel currGrab) { - if (currGrab.export.equals("EPUB")) { - currGrab.gui.appendText(currGrab.window, "[INFO]Finished! " - + ((currGrab.successfulChapterNames.size()) - currGrab.failedChapters.size()) + " of " - + (currGrab.successfulChapterNames.size()) + " chapters successfully grabbed."); - } else { - currGrab.gui.appendText(currGrab.window, "[INFO]Finished! " - + ((currGrab.successfulChapterNames.size()) - currGrab.failedChapters.size()) + " of " - + (currGrab.successfulChapterNames.size()) + " chapters successfully grabbed."); - } - if (!currGrab.failedChapters.isEmpty()) { - currGrab.gui.appendText(currGrab.window, "[ERROR]Failed to grab the following chapters:"); - for (String failedChapter : currGrab.failedChapters) { - currGrab.gui.appendText(currGrab.window, failedChapter); - } - } - } - - /** - * Returns the image name without the href address/path - */ - private static String getImageName(String src) { - String imageName; - int indexname = src.lastIndexOf("/"); - if (indexname == src.length()) { - src = src.substring(1, indexname); - } - indexname = src.lastIndexOf("/"); - imageName = src.substring(indexname + 1); - // Check against popular formats with regex - if (imageName.contains(".png")) imageName = imageName.replaceAll("\\.png(.*)", ".png"); - else if (imageName.contains(".jpg")) imageName = imageName.replaceAll("\\.jpg(.*)", ".jpg"); - else if (imageName.contains(".gif")) imageName = imageName.replaceAll("\\.gif(.*)", ".gif"); - else return "could_not_rename_image"; - return imageName.replaceAll("[\\\\/:*?\"<>|]", "_"); - } - - /** - * Adjust chapter names for chapter numeration. - */ - private static String setFilename(int chapterNumber, String fileName) { - return String.format("%05d", chapterNumber) + "-" + fileName.replaceAll("[^\\w]+", "-"); - } - - static void downloadImage(String src, AutoNovel currGrab) { - if (!currGrab.imageLinks.contains(src)) { - // Try to set the image name - String name = getImageName(src); - // If image could not be renamed correctly, the hashCode of the source + .jpg - // will be set as the image name. - if (name.equals("could_not_rename_image")) { - name = src.hashCode() + ".jpg"; - } - //For LiberSpark - if (src.startsWith("//")) src = src.replace("//", "https://"); - try { - // Connect to image source - URL url = new URL(src); - HttpURLConnection http = (HttpURLConnection) url.openConnection(); - http.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.95 Safari/537.11"); - http.connect(); - InputStream input = http.getInputStream(); - byte[] buffer = new byte[4096]; - // Create imageLinks folder - String filepath = currGrab.saveLocation + File.separator + "images"; - File dir = new File(filepath); - if (!dir.exists()) dir.mkdirs(); - // Save image to file - try (OutputStream output = new FileOutputStream(new File(filepath + File.separator + name))) { - int n; - while ((n = input.read(buffer)) != -1) { - output.write(buffer, 0, n); - } - } catch (IOException e) { - e.printStackTrace(); - currGrab.gui.appendText(currGrab.window, e.getMessage()); - } - currGrab.imageLinks.add(src); - currGrab.imageNames.add(name); - currGrab.gui.appendText(currGrab.window, "[INFO]" + name + " saved."); - //General catch - } catch (Throwable e) { - e.printStackTrace(); - currGrab.gui.appendText(currGrab.window, "[ERROR]Failed to save " + name); - } - } - } - - /** - * Saves the autoNovel cover into a buffered Image - */ - static BufferedImage getBufferedCover(String src, AutoNovel currGrab) { - if (!currGrab.imageLinks.contains(src)) { - // Try to set the image name - String name = getImageName(src); - // If image could not be renamed correctly, the hashCode of the source + .jpg - // will be set as the image name. - if (name.equals("could_not_rename_image")) { - name = src.hashCode() + ".jpg"; - } - //For LiberSpark - if (src.startsWith("//")) src = src.replace("//", "https://"); - try { - URL url = new URL(src); - HttpURLConnection http = (HttpURLConnection) url.openConnection(); - http.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.95 Safari/537.11"); - http.connect(); - BufferedImage imageInput = ImageIO.read(http.getInputStream()); - currGrab.bufferedCoverName = name; - currGrab.imageLinks.add(src); - currGrab.imageNames.add(name); - return imageInput; - //General catch - } catch (Throwable e) { - e.printStackTrace(); - currGrab.gui.appendText(currGrab.window, "[ERROR]Failed to get" + name); - } - } - return null; - } - - /** - * Creates a 'Table of Contents' file of successfully grabbed chapters and imageLinks. - * (Calibre needs links to the imageLinks to display them) - */ - static void createToc(AutoNovel currGrab) { - if (!currGrab.successfulChapterNames.isEmpty()) { - String fileName = currGrab.tocFileName; - String filePath = currGrab.saveLocation + File.separator + fileName; - // Change the save location to path /chapters instead - if (currGrab.export.equals("EPUB")) { - filePath = currGrab.saveLocation + File.separator + "chapters" + File.separator + fileName; - } - try (PrintStream out = new PrintStream(filePath + ".html", textEncoding)) { - out.print(htmlHead + "Table of Contents" + NL + "

" + NL); - //Print chapter links - if (currGrab.export.equals("EPUB")) { - for (int i = 0; i < currGrab.successfulChapterNames.size(); i++) { - out.println("" + currGrab.successfulChapterNames.get(i) - + "
"); - } - } else { - for (int i = 0; i < currGrab.successfulChapterNames.size(); i++) { - out.println("" - + currGrab.successfulChapterNames.get(i) + "
"); - } - } - //Print image links (for calibre) - if (!currGrab.imageLinks.isEmpty() && !currGrab.export.equals("EPUB")) { - for (String image : currGrab.imageLinks) { - // Use hashCode of src + .jpg as the image name if renaming wasn't successful. - String imageName = getImageName(image); - if (imageName.equals("could_not_rename_image")) { - imageName = image.hashCode() + ".jpg"; - } - out.println("
"); - } - } - out.print("

" + NL + htmlFoot); - currGrab.successfulExtraPagesNames.add("Table of Contents"); - currGrab.successfulExtraPagesFilenames.add(fileName); - } catch (FileNotFoundException | UnsupportedEncodingException e) { - currGrab.gui.appendText(currGrab.window, e.getMessage()); - e.printStackTrace(); - } - } - } - - static void createCoverPage(AutoNovel currGrab) { - String fileName = "coverPage"; - String filePath = currGrab.saveLocation + File.separator + "chapters" + File.separator + fileName; - String imageName = currGrab.bookCover; - imageName = getFileName(imageName); - try (PrintStream out = new PrintStream(filePath + ".html", textEncoding)) { - out.print(htmlHead + "
" + NL); - out.println(""); - out.print("
" + NL + htmlFoot); - currGrab.successfulExtraPagesNames.add("Cover"); - currGrab.successfulExtraPagesFilenames.add(fileName); - } catch (FileNotFoundException | UnsupportedEncodingException e) { - currGrab.gui.appendText(currGrab.window, e.getMessage()); - e.printStackTrace(); - } - } - - static void createDescPage(AutoNovel currGrab) { - String fileName = "descPage"; - String filePath = currGrab.saveLocation + File.separator + "chapters" + File.separator + fileName; - try (PrintStream out = new PrintStream(filePath + ".html", textEncoding)) { - out.print(htmlHead + "
Description" + NL); - out.println("

" + currGrab.bookDesc.get(0) + "

"); - out.print("
" + NL + htmlFoot); - currGrab.successfulExtraPagesNames.add("Description"); - currGrab.successfulExtraPagesFilenames.add(fileName); - } catch (FileNotFoundException | UnsupportedEncodingException e) { - currGrab.gui.appendText(currGrab.window, e.getMessage()); - e.printStackTrace(); - } - } - - static String getFileName(String imageName) { - if (imageName != null && imageName.contains("/")) - imageName = imageName.substring(imageName.lastIndexOf("/") + 1); - if (imageName != null && imageName.contains("\\")) - imageName = imageName.substring(imageName.lastIndexOf("\\") + 1); - return imageName; - } - - /** - * Main method to save chapter content. - */ - static void saveChapterWithHTML(String url, int chapterNumber, String chapterName, String chapterContainer, AutoNovel currGrab) { - //Manual grabbing got it's own file naming method - String fileName = setFilename(chapterNumber, chapterName); - - try { - Document doc; - if (currGrab.window.equals("auto") && currGrab.currHostSettings.host.equals("https://wattpad.com/")) { - doc = Jsoup.connect(xhrRequest.wattpadGetChapterTextURL(url.substring(24, url.indexOf("-")))).timeout(30 * 1000).get(); - } else { - doc = Jsoup.connect(url).timeout(30 * 1000).get(); - } - - // Remove styling - if (currGrab.noStyling) doc.select("[style]").removeAttr("style"); - - // Getting the next chapter URL from the "nextChapterBtn" href for Chapter-To-Chapter. - if (!currGrab.nextChapterBtn.equals("NOT_SET")) - currGrab.nextChapterURL = doc.select(currGrab.nextChapterBtn).first().absUrl("href"); - - Element chapterContent = doc.select(chapterContainer).first(); - if (chapterContent == null) - throw new NullPointerException("Chapter container (" + chapterContainer + ") not found."); - - if (currGrab.window.equals("auto") && currGrab.currHostSettings.host.equals("https://flying-lines.com/")) { - String tempChapterText = "
" + doc.select("p").toString() + "
"; - chapterContent = Jsoup.parse(tempChapterText); - } - - // Remove unwanted tags from chapter container. - if (currGrab.blacklistedTags != null && !currGrab.blacklistedTags.isEmpty()) { - for (String tag : currGrab.blacklistedTags) { - if (!chapterContent.select(tag).isEmpty()) { - chapterContent.select(tag).remove(); - } - } - } - // AutoNovel images of chapter container. - if (currGrab.getImages) { - for (Element image : chapterContent.select("img")) { - downloadImage(image.absUrl("src"), currGrab); - } - } - // Add word count of chapter to total word count - if (currGrab.window.equals("auto")) { - currGrab.wordCount = currGrab.wordCount + getWordCount(chapterContent.toString()); - } - // Create chapters folder if it doesn't exist. - File dir = new File(currGrab.saveLocation + File.separator + "chapters"); - if (!dir.exists()) dir.mkdirs(); - try (PrintStream out = new PrintStream(dir.getPath() + File.separator + fileName + ".html", textEncoding)) { - if (chapterContent.select("img").size() > 0) { - // Iterate each image in chapter content. - for (Element image : chapterContent.select("img")) { - // Check if the image was successfully downloaded. - String src = image.absUrl("src"); - if (currGrab.imageLinks.contains(src)) { - // Use hashCode of src + .jpg as the image name if renaming wasn't successful. - String imageName = getImageName(image.attr("src")); - if (imageName.equals("could_not_rename_image")) { - imageName = src.hashCode() + ".jpg"; - } - // Replace href for image to point to local path. - image.attr("src", imageName); - // Remove the img tag if image wasn't downloaded. - } else chapterContent.select("img").remove(); - } - } - // Write text content to file. - if (currGrab.displayChapterTitle) - chapterContent.prepend("" + chapterName + "
"); - out.println(chapterContent); - } - successfulChapter(fileName, chapterName, currGrab); - } catch (Throwable e) { - currGrab.failedChapters.add(chapterName); - currGrab.gui.appendText(currGrab.window, "[ERROR]" + e.getMessage()); - e.printStackTrace(); - } - } - - /** - * Save chapter content from string - */ - static void saveChapterFromString(String chapterContentString, int chapterNumber, String chapterName, String chapterContainer, AutoNovel currGrab) { - - if (chapterContentString == null) - throw new NullPointerException("Chapter container (" + chapterContainer + ") not found."); - - //Manual grabbing got it's own file naming method - String fileName = setFilename(chapterNumber, chapterName); - - try { - Document doc = Jsoup.parse(chapterContentString); - // Remove unwanted tags from chapter container. - if (currGrab.blacklistedTags != null && !currGrab.blacklistedTags.isEmpty()) { - for (String tag : currGrab.blacklistedTags) { - if (!doc.select(tag).isEmpty()) { - doc.select(tag).remove(); - } - } - } - // Remove styling - if (currGrab.noStyling) doc.select("[style]").removeAttr("style"); - - // Getting the next chapter URL from the "nextChapterBtn" href for Chapter-To-Chapter. - if (!currGrab.nextChapterBtn.equals("NOT_SET")) - currGrab.nextChapterURL = - doc.select(currGrab.nextChapterBtn).first().absUrl("href"); - - Element chapterContent = doc.select(chapterContainer).first(); - if (currGrab.currHostSettings.host.equals("https://tapread.com/")) chapterContent = doc; - - // AutoNovel images of chapter container. - if (currGrab.getImages) { - for (Element image : chapterContent.select("img")) { - downloadImage(image.absUrl("src"), currGrab); - } - } - // Add word count of chapter to total word count - currGrab.wordCount = currGrab.wordCount + getWordCount(chapterContent.toString()); - // Create chapters folder if it doesn't exist. - File dir = new File(currGrab.saveLocation + File.separator + "chapters"); - if (!dir.exists()) dir.mkdirs(); - try (PrintStream out = new PrintStream(dir.getPath() + File.separator + fileName + ".html", textEncoding)) { - if (chapterContent.select("img").size() > 0) { - // Iterate each image in chapter content. - for (Element image : chapterContent.select("img")) { - // Check if the image was successfully downloaded. - String src = image.absUrl("src"); - if (currGrab.imageLinks.contains(src)) { - // Use hashCode of src + .jpg as the image name if renaming wasn't successful. - String imageName = getImageName(image.attr("src")); - if (imageName.equals("could_not_rename_image")) { - imageName = src.hashCode() + ".jpg"; - } - // Replace href for image to point to local path. - image.attr("src", imageName); - // Remove the img tag if image wasn't downloaded. - } else chapterContent.select("img").remove(); - } - } - // Add chapter title at the start of chapter - if (currGrab.displayChapterTitle) - chapterContent.prepend("" + chapterName + "
"); - // Write text content to file. - out.println(chapterContent); - } - successfulChapter(fileName, chapterName, currGrab); - } catch (Throwable e) { - currGrab.failedChapters.add(chapterName); - currGrab.gui.appendText(currGrab.window, "[ERROR]" + e.getMessage()); - e.printStackTrace(); - } - } - - // Utility - static int ordinalIndexOf(String str, String substr, int n) { - int pos = str.indexOf(substr); - while (--n > 0 && pos != -1) - pos = str.indexOf(substr, pos + 1); - return pos; - } - - public static void deleteFolderAndItsContent(final Path folder) throws IOException { - Files.walkFileTree(folder, new SimpleFileVisitor() { - @Override - public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { - Files.delete(file); - return FileVisitResult.CONTINUE; - } - - @Override - public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException { - if (exc != null) { - throw exc; - } - Files.delete(dir); - return FileVisitResult.CONTINUE; - } - }); - } - private static int getWordCount(String html) { - org.jsoup.nodes.Document dom = Jsoup.parse(html); - String text = dom.text(); - - return text.split(" ").length; - } -} \ No newline at end of file diff --git a/src/grabber/xhrRequest.java b/src/grabber/xhrRequest.java index c27e299..36cc259 100644 --- a/src/grabber/xhrRequest.java +++ b/src/grabber/xhrRequest.java @@ -1,164 +1,166 @@ -package grabber; - -import org.json.simple.JSONArray; -import org.json.simple.JSONObject; -import org.json.simple.parser.JSONParser; -import org.json.simple.parser.ParseException; - -import javax.net.ssl.HttpsURLConnection; -import java.io.BufferedReader; -import java.io.DataOutputStream; -import java.io.IOException; -import java.io.InputStreamReader; -import java.net.HttpURLConnection; -import java.net.URL; -import java.nio.charset.StandardCharsets; -import java.util.LinkedHashMap; -import java.util.Map; - -public class xhrRequest { - - private final String USER_AGENT = "Mozilla/5.0"; - - public static void main(String[] args) { - xhrRequest http = new xhrRequest(); - try { - System.out.println(http.sendPost("https://creativenovels.com/wp-admin/admin-ajax.php", "action=crn_chapter_list&view_id=9311")); - } catch (IOException e) { - e.printStackTrace(); - } - } - - public static Map tapReadGetChapterList(int bookNumber) { - xhrRequest http = new xhrRequest(); - JSONParser parser = new JSONParser(); - try { - Object obj = parser.parse(http.sendPost("https://www.tapread.com/book/contents", "bookId=" + bookNumber)); - JSONObject jsonObject = (JSONObject) obj; - JSONObject results = (JSONObject) jsonObject.get("result"); - JSONArray chapterObjects = (JSONArray) results.get("chapterList"); - Map chapterMap = new LinkedHashMap<>(); - for (Object o : chapterObjects) { - JSONObject slide = (JSONObject) o; - String chapterId = String.valueOf(slide.get("chapterId")); - String chapterName = String.valueOf(slide.get("chapterName")); - String chapterLocked = String.valueOf(slide.get("lock")); - if (chapterLocked.equals("0")) chapterMap.put(chapterId, chapterName); - } - return chapterMap; - } catch (ParseException | IOException e) { - e.printStackTrace(); - return null; - } - } - - public static String tapReadGetChapterContent(String paramenter) { - xhrRequest http = new xhrRequest(); - JSONParser parser = new JSONParser(); - try { - Object obj = parser.parse(http.sendPost("https://www.tapread.com/book/chapter", paramenter)); - JSONObject jsonObject = (JSONObject) obj; - JSONObject results = (JSONObject) jsonObject.get("result"); - String content = (String) results.get("content"); - return content; - } catch (ParseException | IOException e) { - e.printStackTrace(); - return null; - } - } - - public static Map webnovelGetChapterList(String url) { - xhrRequest http = new xhrRequest(); - JSONParser parser = new JSONParser(); - try { - Object obj = parser.parse(http.sendGet(url)); - JSONObject jsonObject = (JSONObject) obj; - JSONObject data = (JSONObject) jsonObject.get("data"); - JSONArray volumeItems = (JSONArray) data.get("volumeItems"); - Map chapterMap = new LinkedHashMap<>(); - - for (Object o : volumeItems) { - JSONObject chapterItem = (JSONObject) o; - JSONArray chapterItems = (JSONArray) chapterItem.get("chapterItems"); - for (Object a : chapterItems) { - JSONObject slide = (JSONObject) a; - String chapterId = String.valueOf(slide.get("id")); - // Crude hotfix - String chapterName = String.valueOf(slide.get("name")).replaceAll("’", "\'"); - String isVip = String.valueOf(slide.get("isVip")); - if (isVip.equals("0")) { - chapterMap.put(chapterId, chapterName); - } - } - } - return chapterMap; - } catch (ParseException | IOException e) { - e.printStackTrace(); - return null; - } - } - - public static String wattpadGetChapterTextURL(String chapterId) { - xhrRequest http = new xhrRequest(); - JSONParser parser = new JSONParser(); - try { - Object obj = parser.parse(http.sendGet("https://www.wattpad.com/v4/parts/" + chapterId + "?fields=text_url")); - JSONObject jsonObject = (JSONObject) obj; - JSONObject results = (JSONObject) jsonObject.get("text_url"); - return (String) results.get("text"); - } catch (ParseException | IOException e) { - e.printStackTrace(); - return null; - } - } - - // HTTP POST request - public String sendPost(String url, String paramenter) throws IOException { - URL obj = new URL(url); - HttpsURLConnection con = (HttpsURLConnection) obj.openConnection(); - - //add reuqest header - con.setRequestMethod("POST"); - con.setRequestProperty("User-Agent", USER_AGENT); - con.setRequestProperty("Accept-Language", "en-US,en;q=0.5"); - con.setRequestProperty("Accept-Charset", "UTF-8"); - - // Send post request - con.setDoOutput(true); - DataOutputStream wr = new DataOutputStream(con.getOutputStream()); - wr.writeBytes(paramenter); - wr.flush(); - wr.close(); - - BufferedReader in = new BufferedReader( - new InputStreamReader(con.getInputStream(), StandardCharsets.UTF_8)); - String inputLine; - StringBuilder response = new StringBuilder(); - - while ((inputLine = in.readLine()) != null) { - response.append(inputLine); - } - in.close(); - return response.toString(); - } - - // HTTP GET request - private String sendGet(String url) throws IOException { - URL obj = new URL(url); - HttpURLConnection con = (HttpURLConnection) obj.openConnection(); - con.setRequestMethod("GET"); - con.setRequestProperty("User-Agent", USER_AGENT); - - BufferedReader in = new BufferedReader( - new InputStreamReader(con.getInputStream())); - String inputLine; - StringBuilder response = new StringBuilder(); - - while ((inputLine = in.readLine()) != null) { - response.append(inputLine); - } - in.close(); - return response.toString(); - } -} - +package grabber; + +import org.json.simple.JSONArray; +import org.json.simple.JSONObject; +import org.json.simple.parser.JSONParser; +import org.json.simple.parser.ParseException; + +import javax.net.ssl.HttpsURLConnection; +import java.io.BufferedReader; +import java.io.DataOutputStream; +import java.io.IOException; +import java.io.InputStreamReader; +import java.net.HttpURLConnection; +import java.net.URL; +import java.nio.charset.StandardCharsets; +import java.util.LinkedHashMap; +import java.util.Map; +/** + xhr/AJAX interactions + */ +public class xhrRequest { + + private final String USER_AGENT = "Mozilla/5.0"; + + public static void main(String[] args) { + xhrRequest http = new xhrRequest(); + try { + System.out.println(http.sendPost("https://creativenovels.com/wp-admin/admin-ajax.php", "action=crn_chapter_list&view_id=9311")); + } catch (IOException e) { + e.printStackTrace(); + } + } + + public static Map tapReadGetChapterList(int bookNumber) { + xhrRequest http = new xhrRequest(); + JSONParser parser = new JSONParser(); + try { + Object obj = parser.parse(http.sendPost("https://www.tapread.com/book/contents", "bookId=" + bookNumber)); + JSONObject jsonObject = (JSONObject) obj; + JSONObject results = (JSONObject) jsonObject.get("result"); + JSONArray chapterObjects = (JSONArray) results.get("chapterList"); + Map chapterMap = new LinkedHashMap<>(); + for (Object o : chapterObjects) { + JSONObject slide = (JSONObject) o; + String chapterId = String.valueOf(slide.get("chapterId")); + String chapterName = String.valueOf(slide.get("chapterName")); + String chapterLocked = String.valueOf(slide.get("lock")); + if (chapterLocked.equals("0")) chapterMap.put(chapterId, chapterName); + } + return chapterMap; + } catch (ParseException | IOException e) { + e.printStackTrace(); + return null; + } + } + + public static String tapReadGetChapterContent(String paramenter) { + xhrRequest http = new xhrRequest(); + JSONParser parser = new JSONParser(); + try { + Object obj = parser.parse(http.sendPost("https://www.tapread.com/book/chapter", paramenter)); + JSONObject jsonObject = (JSONObject) obj; + JSONObject results = (JSONObject) jsonObject.get("result"); + String content = (String) results.get("content"); + return content; + } catch (ParseException | IOException e) { + e.printStackTrace(); + return null; + } + } + + public static Map webnovelGetChapterList(String url) { + xhrRequest http = new xhrRequest(); + JSONParser parser = new JSONParser(); + try { + Object obj = parser.parse(http.sendGet(url)); + JSONObject jsonObject = (JSONObject) obj; + JSONObject data = (JSONObject) jsonObject.get("data"); + JSONArray volumeItems = (JSONArray) data.get("volumeItems"); + Map chapterMap = new LinkedHashMap<>(); + + for (Object o : volumeItems) { + JSONObject chapterItem = (JSONObject) o; + JSONArray chapterItems = (JSONArray) chapterItem.get("chapterItems"); + for (Object a : chapterItems) { + JSONObject slide = (JSONObject) a; + String chapterId = String.valueOf(slide.get("id")); + // Crude hotfix + String chapterName = String.valueOf(slide.get("name")).replaceAll("’", "\'"); + String isVip = String.valueOf(slide.get("isVip")); + if (isVip.equals("0")) { + chapterMap.put(chapterId, chapterName); + } + } + } + return chapterMap; + } catch (ParseException | IOException e) { + e.printStackTrace(); + return null; + } + } + + public static String wattpadGetChapterTextURL(String chapterId) { + xhrRequest http = new xhrRequest(); + JSONParser parser = new JSONParser(); + try { + Object obj = parser.parse(http.sendGet("https://www.wattpad.com/v4/parts/" + chapterId + "?fields=text_url")); + JSONObject jsonObject = (JSONObject) obj; + JSONObject results = (JSONObject) jsonObject.get("text_url"); + return (String) results.get("text"); + } catch (ParseException | IOException e) { + e.printStackTrace(); + return null; + } + } + + // HTTP POST request + public String sendPost(String url, String paramenter) throws IOException { + URL obj = new URL(url); + HttpsURLConnection con = (HttpsURLConnection) obj.openConnection(); + + //add reuqest header + con.setRequestMethod("POST"); + con.setRequestProperty("User-Agent", USER_AGENT); + con.setRequestProperty("Accept-Language", "en-US,en;q=0.5"); + con.setRequestProperty("Accept-Charset", "UTF-8"); + + // Send post request + con.setDoOutput(true); + DataOutputStream wr = new DataOutputStream(con.getOutputStream()); + wr.writeBytes(paramenter); + wr.flush(); + wr.close(); + + BufferedReader in = new BufferedReader( + new InputStreamReader(con.getInputStream(), StandardCharsets.UTF_8)); + String inputLine; + StringBuilder response = new StringBuilder(); + + while ((inputLine = in.readLine()) != null) { + response.append(inputLine); + } + in.close(); + return response.toString(); + } + + // HTTP GET request + private String sendGet(String url) throws IOException { + URL obj = new URL(url); + HttpURLConnection con = (HttpURLConnection) obj.openConnection(); + con.setRequestMethod("GET"); + con.setRequestProperty("User-Agent", USER_AGENT); + + BufferedReader in = new BufferedReader( + new InputStreamReader(con.getInputStream())); + String inputLine; + StringBuilder response = new StringBuilder(); + + while ((inputLine = in.readLine()) != null) { + response.append(inputLine); + } + in.close(); + return response.toString(); + } +} + diff --git a/src/gui/ChapterToChapter.form b/src/gui/ChapterToChapter.form index cc39d83..9a03617 100644 --- a/src/gui/ChapterToChapter.form +++ b/src/gui/ChapterToChapter.form @@ -1,134 +1,134 @@ - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/src/gui/ChapterToChapter.java b/src/gui/ChapterToChapter.java index 2d4894d..297e760 100644 --- a/src/gui/ChapterToChapter.java +++ b/src/gui/ChapterToChapter.java @@ -1,108 +1,108 @@ -package gui; - -import javax.swing.*; -import java.awt.*; -import java.awt.event.*; - -public class ChapterToChapter extends JDialog { - private JPanel contentPane; - private JButton buttonOK; - private JButton buttonCancel; - private JTextField firstChapterField; - private JTextField lastChapterField; - private JTextField nextChapterButtonField; - private JTextField manChapterToChapterNumberField; - - public ChapterToChapter() { - setContentPane(contentPane); - setModal(true); - setTitle("Chapter to chapter navigation"); - ImageIcon favicon = new ImageIcon(getClass().getResource("/images/favicon.png")); - setIconImage(favicon.getImage()); - getRootPane().setDefaultButton(buttonOK); - - buttonOK.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - onOK(); - } - }); - - buttonCancel.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - onCancel(); - } - }); - - // call onCancel() when cross is clicked - setDefaultCloseOperation(DO_NOTHING_ON_CLOSE); - addWindowListener(new WindowAdapter() { - public void windowClosing(WindowEvent e) { - onCancel(); - } - }); - - // call onCancel() on ESCAPE - contentPane.registerKeyboardAction(new ActionListener() { - public void actionPerformed(ActionEvent e) { - onCancel(); - } - }, KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT); - manChapterToChapterNumberField.addFocusListener(new FocusListener() { - @Override - public void focusGained(FocusEvent e) { - if (manChapterToChapterNumberField.getText().equals("Number")) { - manChapterToChapterNumberField.setText(""); - manChapterToChapterNumberField.setForeground(Color.BLACK); - } - } - - @Override - public void focusLost(FocusEvent e) { - if (manChapterToChapterNumberField.getText().isEmpty()) { - manChapterToChapterNumberField.setForeground(Color.GRAY); - manChapterToChapterNumberField.setText("Number"); - } - } - }); - } - - public static void main() { - ChapterToChapter dialog = new ChapterToChapter(); - dialog.pack(); - dialog.setVisible(true); - } - - private void onOK() { - if ((!firstChapterField.getText().isEmpty() && firstChapterField.getText() != null) && - (!lastChapterField.getText().isEmpty() && lastChapterField.getText() != null) && - (!nextChapterButtonField.getText().isEmpty() && nextChapterButtonField.getText() != null)) { - GUI.chapterToChapterArgs[0] = firstChapterField.getText(); - GUI.chapterToChapterArgs[1] = lastChapterField.getText(); - GUI.chapterToChapterArgs[2] = nextChapterButtonField.getText(); - if (!manChapterToChapterNumberField.getText().equals("Number")) { - GUI.chapterToChapterNumber = Integer.valueOf(manChapterToChapterNumberField.getText()); - } else { - GUI.chapterToChapterNumber = 1; - } - } - dispose(); - } - - private void onCancel() { - // add your code here if necessary - dispose(); - } - - private void createUIComponents() { - manChapterToChapterNumberField = new JTextField("Number"); - manChapterToChapterNumberField.setForeground(Color.GRAY); - - firstChapterField = new JTextField(GUI.chapterToChapterArgs[0]); - lastChapterField = new JTextField(GUI.chapterToChapterArgs[1]); - nextChapterButtonField = new JTextField(GUI.chapterToChapterArgs[2]); - if (GUI.chapterToChapterNumber != 1) { - manChapterToChapterNumberField.setText(String.valueOf(GUI.chapterToChapterNumber)); - manChapterToChapterNumberField.setForeground(Color.BLACK); - } - } -} +package gui; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.*; + +public class ChapterToChapter extends JDialog { + private JPanel contentPane; + private JButton buttonOK; + private JButton buttonCancel; + private JTextField firstChapterField; + private JTextField lastChapterField; + private JTextField nextChapterButtonField; + private JTextField manChapterToChapterNumberField; + + public ChapterToChapter() { + setContentPane(contentPane); + setModal(true); + setTitle("Chapter to chapter navigation"); + ImageIcon favicon = new ImageIcon(getClass().getResource("/files/images/favicon.png")); + setIconImage(favicon.getImage()); + getRootPane().setDefaultButton(buttonOK); + + buttonOK.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + onOK(); + } + }); + + buttonCancel.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + onCancel(); + } + }); + + // call onCancel() when cross is clicked + setDefaultCloseOperation(DO_NOTHING_ON_CLOSE); + addWindowListener(new WindowAdapter() { + public void windowClosing(WindowEvent e) { + onCancel(); + } + }); + + // call onCancel() on ESCAPE + contentPane.registerKeyboardAction(new ActionListener() { + public void actionPerformed(ActionEvent e) { + onCancel(); + } + }, KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT); + manChapterToChapterNumberField.addFocusListener(new FocusListener() { + @Override + public void focusGained(FocusEvent e) { + if (manChapterToChapterNumberField.getText().equals("Number")) { + manChapterToChapterNumberField.setText(""); + manChapterToChapterNumberField.setForeground(Color.BLACK); + } + } + + @Override + public void focusLost(FocusEvent e) { + if (manChapterToChapterNumberField.getText().isEmpty()) { + manChapterToChapterNumberField.setForeground(Color.GRAY); + manChapterToChapterNumberField.setText("Number"); + } + } + }); + } + + public static void main() { + ChapterToChapter dialog = new ChapterToChapter(); + dialog.pack(); + dialog.setVisible(true); + } + + private void onOK() { + if ((!firstChapterField.getText().isEmpty() && firstChapterField.getText() != null) && + (!lastChapterField.getText().isEmpty() && lastChapterField.getText() != null) && + (!nextChapterButtonField.getText().isEmpty() && nextChapterButtonField.getText() != null)) { + GUI.chapterToChapterArgs[0] = firstChapterField.getText(); + GUI.chapterToChapterArgs[1] = lastChapterField.getText(); + GUI.chapterToChapterArgs[2] = nextChapterButtonField.getText(); + if (!manChapterToChapterNumberField.getText().equals("Number")) { + GUI.chapterToChapterNumber = Integer.valueOf(manChapterToChapterNumberField.getText()); + } else { + GUI.chapterToChapterNumber = 1; + } + } + dispose(); + } + + private void onCancel() { + // add your code here if necessary + dispose(); + } + + private void createUIComponents() { + manChapterToChapterNumberField = new JTextField("Number"); + manChapterToChapterNumberField.setForeground(Color.GRAY); + + firstChapterField = new JTextField(GUI.chapterToChapterArgs[0]); + lastChapterField = new JTextField(GUI.chapterToChapterArgs[1]); + nextChapterButtonField = new JTextField(GUI.chapterToChapterArgs[2]); + if (GUI.chapterToChapterNumber != 1) { + manChapterToChapterNumberField.setText(String.valueOf(GUI.chapterToChapterNumber)); + manChapterToChapterNumberField.setForeground(Color.BLACK); + } + } +} diff --git a/src/gui/GUI.form b/src/gui/GUI.form index e7bbf0d..d2901e5 100644 --- a/src/gui/GUI.form +++ b/src/gui/GUI.form @@ -1,1389 +1,1193 @@ - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/src/gui/GUI.java b/src/gui/GUI.java index 434d87c..bd7cb72 100644 --- a/src/gui/GUI.java +++ b/src/gui/GUI.java @@ -1,28 +1,20 @@ package gui; -import checker.chapterChecker; -import grabber.AutoNovel; -import grabber.HostSettings; -import grabber.ManNovel; -import org.json.simple.JSONArray; -import org.json.simple.JSONObject; -import org.json.simple.parser.JSONParser; -import org.json.simple.parser.ParseException; +import grabber.*; +import updater.Updater; import org.jsoup.Jsoup; import org.jsoup.nodes.Document; import org.jsoup.nodes.Element; import org.jsoup.select.Elements; -import updater.updater; + import javax.swing.*; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; -import javax.swing.filechooser.FileNameExtensionFilter; import java.awt.*; import java.awt.event.*; import java.awt.image.BufferedImage; import java.io.File; -import java.io.FileReader; import java.io.IOException; import java.io.InputStream; import java.net.URI; @@ -33,19 +25,16 @@ import java.util.concurrent.Executors; public class GUI extends JFrame { - public static String versionNumber = "2.4.0"; - public static String appdataPath = System.getProperty("user.home") + File.separator + "AppData" + File.separator + "Roaming" + File.separator + "Novel-Grabber"; + public static String versionNumber = "2.4.1"; public static DefaultListModel listModelChapterLinks = new DefaultListModel<>(); - public static DefaultListModel listModelCheckerLinks = new DefaultListModel<>(); public static List blacklistedTags = new ArrayList<>(); public static String[] chapterToChapterArgs = new String[3]; public static TrayIcon trayIcon; public static Integer chapterToChapterNumber = 1; - private static String[] exportFormats = {"EPUB", "Calibre"}; private static String[] browserList = {"Chrome", "Firefox", "Edge", "Opera", "IE"}; private static MenuItem defaultItem0; private final String NL = System.getProperty("line.separator"); - public static AutoNovel autoNovel = null; + public static Novel autoNovel = null; public static ManNovel manNovel = null; public JComboBox autoHostSelection; public JTextField chapterListURL; @@ -56,7 +45,6 @@ public class GUI extends JFrame { public JCheckBox toLastChapter; public JCheckBox getImages; public JCheckBox checkInvertOrder; - public JComboBox exportSelection; public JTextField waitTime; public JProgressBar progressBar; public JButton autoGetNumberButton; @@ -64,7 +52,6 @@ public class GUI extends JFrame { public JLabel autoBookTitle; public JLabel autoAuthor; public JLabel autoChapterAmount; - public JComboBox manExportSelection; public JTextField manWaitTime; public JCheckBox manGetImages; public JCheckBox manInvertOrder; @@ -143,6 +130,8 @@ public class GUI extends JFrame { public JComboBox manBrowserCombobox; public JCheckBox autoNoStyling; public JCheckBox manNoStyling; + private JButton manAddChapterButton; + private JButton manEditChapterOrder; public JTextArea autoBookDescArea; private JScrollPane autoBookDescScrollPane; private JButton autoEditMetadataButton; @@ -150,7 +139,124 @@ public class GUI extends JFrame { public GUI() { initialize(); - loadDefaultCheckerList(); + + // Button logic + + // Automatic grabbing + // First Auto-Novel initialization, fetching info and chapter list + autoCheckAvailability.addActionListener(e -> Executors.newSingleThreadExecutor().execute(() -> { + if (!chapterListURL.getText().isEmpty()) { + autoBusyLabel.setVisible(true); + + autoNovel = new Novel(this); + // Needed + autoNovel.options.headless = useHeaderlessBrowserCheckBox.isSelected(); + autoNovel.options.window = "auto"; + autoNovel.options.browser = autoBrowserCombobox.getSelectedItem().toString(); + autoNovel.getChapterList(); + autoNovel.getMetadata(); + if (!autoNovel.chapters.isEmpty()) { + grabChaptersButton.setEnabled(true); + autoGetNumberButton.setEnabled(true); + autoEditMetaBtn.setEnabled(true); + autoEditBlacklistBtn.setEnabled(true); + pagesCountLbl.setText(""); + pagesCountLbl.setVisible(false); + pagesLbl.setVisible(false); + } + autoBusyLabel.setVisible(false); + } + })); + + // Start Auto-Novel chapter download and EPUB conversion + grabChaptersButton.addActionListener(arg0 -> Executors.newSingleThreadExecutor().execute(() -> { + // input validation + if (chapterListURL.getText().isEmpty()) { + showPopup("URL field is empty.", "warning"); + chapterListURL.requestFocusInWindow(); + return; + } + if (saveLocation.getText().isEmpty()) { + showPopup("Save directory field is empty.", "warning"); + saveLocation.requestFocusInWindow(); + return; + } + if ((!chapterAllCheckBox.isSelected()) && (!toLastChapter.isSelected()) + && (((Integer) firstChapter.getValue() < 1) + || ((Integer) lastChapter.getValue()) < 1)) { + showPopup("Chapter numbers can't be lower than 1.", "warning"); + return; + } + if ((!chapterAllCheckBox.isSelected()) && (!toLastChapter.isSelected()) + && ((Integer) lastChapter.getValue() > autoNovel.chapters.size())) { + showPopup("Novel doesn't have that many chapters.", "warning"); + return; + } + if ((!chapterAllCheckBox.isSelected()) && (!toLastChapter.isSelected()) + && ((Integer) lastChapter.getValue()) < (Integer) firstChapter.getValue()) { + showPopup("Last chapter can't be lower than first chapter.", "warning"); + return; + } + if ((!chapterAllCheckBox.isSelected()) && (toLastChapter.isSelected()) + && ((Integer) firstChapter.getValue()) < 1) { + showPopup("First chapter number can't be lower than 1.", "warning"); + return; + } + if (waitTime.getText().isEmpty()) { + showPopup("Wait time cannot be empty.", "warning"); + return; + } + if (!waitTime.getText().matches("\\d+") && !waitTime.getText().isEmpty()) { + showPopup("Wait time must contain numbers.", "warning"); + return; + } + pagesLbl.setVisible(true); + pagesCountLbl.setVisible(true); + grabChaptersButton.setEnabled(false); + grabChaptersButton.setVisible(false); + stopButton.setEnabled(true); + stopButton.setVisible(true); + try { + // Needed + autoNovel.options.saveLocation = saveLocation.getText(); + //Optional + autoNovel.options.waitTime = Integer.parseInt(waitTime.getText()); + autoNovel.options.displayChapterTitle = displayChapterTitleCheckBox.isSelected(); + autoNovel.options.invertOrder = checkInvertOrder.isSelected(); + // Was set on "checking" but needs to be set again for potential changes + autoNovel.options.headless = useHeaderlessBrowserCheckBox.isSelected(); + autoNovel.options.browser = autoBrowserCombobox.getSelectedItem().toString(); + // Set chapter range + if(chapterAllCheckBox.isSelected()) { + autoNovel.options.firstChapter = 1; + autoNovel.options.lastChapter = autoNovel.chapters.size(); + } else { + autoNovel.options.firstChapter = (int) firstChapter.getValue(); + if(toLastChapter.isSelected()) { + autoNovel.options.lastChapter = autoNovel.chapters.size(); + } else { + autoNovel.options.lastChapter = (int) lastChapter.getValue(); + } + } + autoNovel.downloadChapters(); // Throws exception if grabbing was stopped + autoNovel.createCoverPage(); + autoNovel.createToc(); + autoNovel.createDescPage(); + autoNovel.createEPUB(); + autoNovel.report(); + } catch (Exception err) { + appendText("auto", "[ERROR]"+err.getMessage()); + err.printStackTrace(); + autoNovel.killTask = false; + } + progressBar.setStringPainted(false); + progressBar.setValue(0); + grabChaptersButton.setEnabled(true); + grabChaptersButton.setVisible(true); + stopButton.setEnabled(false); + stopButton.setVisible(false); + + })); browseButton.addActionListener(arg0 -> { JFileChooser chooser = new JFileChooser(); @@ -164,6 +270,29 @@ public GUI() { } }); + autoEditBlacklistBtn.addActionListener(e -> autoSetBlacklistedTags.main(autoNovel)); + + autoEditMetaBtn.addActionListener(e -> autoEditMetadata.main(autoNovel)); + + + autoChapterToChapterNumberField.addFocusListener(new FocusListener() { + @Override + public void focusGained(FocusEvent e) { + if (autoChapterToChapterNumberField.getText().equals("Number")) { + autoChapterToChapterNumberField.setText(""); + autoChapterToChapterNumberField.setForeground(Color.BLACK); + } + } + + @Override + public void focusLost(FocusEvent e) { + if (autoChapterToChapterNumberField.getText().isEmpty()) { + autoChapterToChapterNumberField.setForeground(Color.GRAY); + autoChapterToChapterNumberField.setText("Number"); + } + } + }); + autoVisitButton.addActionListener(arg0 -> { try { String toOpenHostSite; @@ -171,8 +300,8 @@ public GUI() { toOpenHostSite = "https://isohungrytls.com/"; } else { HostSettings emptyNovel = new HostSettings( - Objects.requireNonNull(autoHostSelection.getSelectedItem()).toString().toLowerCase().replace(" ", ""), ""); - toOpenHostSite = emptyNovel.host; + Objects.requireNonNull(autoHostSelection.getSelectedItem()).toString().toLowerCase().replace(" ", "")); + toOpenHostSite = emptyNovel.url; } URI uri = new URI(toOpenHostSite); openWebpage(uri); @@ -180,11 +309,12 @@ public GUI() { e.printStackTrace(); } }); + autoShowBlacklistedTagsBtn.addActionListener(arg0 -> { DefaultListModel tempListModel = new DefaultListModel<>(); JList tempJList = new JList<>(tempListModel); - HostSettings tempSettings = new HostSettings(autoHostSelection.getSelectedItem().toString().toLowerCase().replace(" ", ""), ""); + HostSettings tempSettings = new HostSettings(autoHostSelection.getSelectedItem().toString().toLowerCase().replace(" ", "")); JScrollPane tagScrollPane = new JScrollPane(tempJList); tagScrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS); tagScrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED); @@ -201,97 +331,7 @@ public GUI() { JOptionPane.PLAIN_MESSAGE, null, null, null); }); - grabChaptersButton.addActionListener(arg0 -> Executors.newSingleThreadExecutor().execute(() -> { - // input validation - if (chapterListURL.getText().isEmpty()) { - showPopup("URL field is empty.", "warning"); - chapterListURL.requestFocusInWindow(); - return; - } - if (saveLocation.getText().isEmpty()) { - showPopup("Save directory field is empty.", "warning"); - saveLocation.requestFocusInWindow(); - return; - } - if (!autoNovel.autoChapterToChapter) { - if ((!chapterAllCheckBox.isSelected()) && (!toLastChapter.isSelected()) - && (((Integer) firstChapter.getValue() < 1) - || ((Integer) lastChapter.getValue()) < 1)) { - showPopup("Chapter numbers can't be lower than 1.", "warning"); - return; - } - if ((!chapterAllCheckBox.isSelected()) && (!toLastChapter.isSelected()) - && ((Integer) lastChapter.getValue()) < (Integer) firstChapter.getValue()) { - showPopup("Last chapter can't be lower than first chapter.", "warning"); - return; - } - if ((!chapterAllCheckBox.isSelected()) && (toLastChapter.isSelected()) - && ((Integer) firstChapter.getValue()) < 1) { - showPopup("First chapter number can't be lower than 1.", "warning"); - return; - } - } else { - if (autoFirstChapterURL.getText().isEmpty() && !useHeaderlessBrowserCheckBox.isSelected()) { - showPopup("First chapter URL is empty.", "warning"); - return; - } - if (autoLastChapterURL.getText().isEmpty() && !useHeaderlessBrowserCheckBox.isSelected()) { - showPopup("Last chapter URL is empty.", "warning"); - return; - } - } - if (waitTime.getText().isEmpty()) { - showPopup("Wait time cannot be empty.", "warning"); - return; - } - if (!waitTime.getText().matches("\\d+") && !waitTime.getText().isEmpty()) { - showPopup("Wait time must contain numbers.", "warning"); - return; - } - if ((!saveLocation.getText().isEmpty()) && (!chapterListURL.getText().isEmpty())) { - pagesLbl.setVisible(true); - pagesCountLbl.setVisible(true); - grabChaptersButton.setEnabled(false); - grabChaptersButton.setVisible(false); - stopButton.setEnabled(true); - stopButton.setVisible(true); - // Chapter grabbing - try { - autoNovel.startDownload(); - } catch (NullPointerException | IllegalArgumentException err) { - appendText("auto", err.getMessage()); - err.printStackTrace(); - } finally { - progressBar.setStringPainted(false); - progressBar.setValue(0); - grabChaptersButton.setEnabled(true); - grabChaptersButton.setVisible(true); - stopButton.setEnabled(false); - stopButton.setVisible(false); - } - } - })); - autoCheckAvailability.addActionListener(e -> Executors.newSingleThreadExecutor().execute(() -> { - if (!chapterListURL.getText().isEmpty()) { - autoBusyLabel.setVisible(true); - autoNovel = new AutoNovel(this); - if (!autoNovel.chapterLinks.isEmpty()) { - grabChaptersButton.setEnabled(true); - autoGetNumberButton.setEnabled(true); - autoEditMetaBtn.setEnabled(true); - autoEditBlacklistBtn.setEnabled(true); - pagesCountLbl.setText(""); - pagesCountLbl.setVisible(false); - pagesLbl.setVisible(false); - } - if (autoNovel.autoChapterToChapter) { - grabChaptersButton.setEnabled(true); - autoEditMetaBtn.setEnabled(true); - autoEditBlacklistBtn.setEnabled(true); - } - autoBusyLabel.setVisible(false); - } - })); + chapterAllCheckBox.addActionListener(arg0 -> { if (chapterAllCheckBox.isSelected()) { firstChapter.setEnabled(false); @@ -303,6 +343,7 @@ public GUI() { toLastChapter.setEnabled(true); } }); + toLastChapter.addActionListener(arg0 -> { if (toLastChapter.isSelected()) { chapterAllCheckBox.setEnabled(false); @@ -317,29 +358,35 @@ public GUI() { stopButton.setEnabled(false); autoNovel.killTask = true; }); - // Get chapter number - autoGetNumberButton.addActionListener(e -> Executors.newSingleThreadExecutor().execute(() -> getChapterNumber.main(this, autoNovel))); - chaptersFromLinksRadioButton.addActionListener(e -> { - if (chaptersFromLinksRadioButton.isSelected()) { - chapterToChapterRadioButton.setSelected(false); - manNovelURL.setVisible(true); - getLinksButton.setVisible(true); - manTocURLlbl.setVisible(true); - chapterToChapterButton.setVisible(false); - manInvertOrder.setEnabled(true); + autoGetNumberButton.addActionListener(e -> Executors.newSingleThreadExecutor().execute(() -> getChapterNumber.main(autoNovel))); + + autoHostSelection.addItemListener(e -> { + String selection = autoHostSelection.getSelectedItem().toString(); + if (HostSettings.headerlessBrowserWebsitesList.contains(selection)) { + useHeaderlessBrowserCheckBox.setSelected(true); + useHeaderlessBrowserCheckBox.setEnabled(false); + } else { + useHeaderlessBrowserCheckBox.setEnabled(true); } - }); - chapterToChapterRadioButton.addActionListener(e -> { - if (chapterToChapterRadioButton.isSelected()) { - chaptersFromLinksRadioButton.setSelected(false); - manNovelURL.setVisible(false); - getLinksButton.setVisible(false); - manTocURLlbl.setVisible(false); - chapterToChapterButton.setVisible(true); - manInvertOrder.setEnabled(false); + chapterAllCheckBox.setEnabled(true); + firstChapter.setEnabled(true); + lastChapter.setEnabled(true); + toLastChapter.setEnabled(true); + checkInvertOrder.setEnabled(true); + autoChapterToChapterNumberField.setVisible(false); + autoFirstChapterLbl.setVisible(false); + autoFirstChapterURL.setVisible(false); + autoLastChapterLbl.setVisible(false); + autoLastChapterURL.setVisible(false); + if (HostSettings.noHeaderlessBrowserWebsitesList.contains(selection)) { + useHeaderlessBrowserCheckBox.setSelected(false); + useHeaderlessBrowserCheckBox.setEnabled(false); } }); + + + // manual chapter download getLinksButton.addActionListener(e -> { if (manNovelURL.getText().isEmpty()) { JOptionPane.showMessageDialog(window, "URL field is empty.", "Warning", @@ -348,7 +395,9 @@ public GUI() { } if (!manNovelURL.getText().isEmpty()) { try { - ManNovel.retrieveLinks(this); + manNovel = new ManNovel(this); + manNovel.novelLink = manNovelURL.getText(); + manNovel.retrieveLinks(); } catch (NullPointerException | IllegalArgumentException | IOException err) { err.printStackTrace(); appendText("manual", "[ERROR]" + err.getMessage()); @@ -360,22 +409,6 @@ public GUI() { } }); - manSetMetadataButton.addActionListener(arg0 -> manSetMetadata.main()); - - manRemoveLinksButton.addActionListener(arg0 -> { - if (!listModelChapterLinks.isEmpty()) { - int[] indices = manLinkList.getSelectedIndices(); - for (int i = indices.length - 1; i >= 0; i--) { - listModelChapterLinks.removeElementAt(indices[i]); - ManNovel.chapterLinks.remove(indices[i]); - } - if (listModelChapterLinks.isEmpty()) { - manRemoveLinksButton.setEnabled(false); - } - appendText("manual", indices.length + " links removed."); - } - }); - // manual chapter download manGrabChaptersButton.addActionListener(e -> Executors.newSingleThreadExecutor().execute(() -> { // Chapter-To-Chapter // input validation @@ -399,13 +432,33 @@ public GUI() { manGrabChaptersButton.setVisible(false); manStopButton.setEnabled(true); manStopButton.setVisible(true); + manProgressBar.setStringPainted(true); try { - manProgressBar.setStringPainted(true); - manNovel = new ManNovel(this, "chapterToChapter"); - // Exception handling - } catch (NullPointerException | IllegalArgumentException err) { - appendText("manual", err.getMessage()); + // Needed + manNovel = new ManNovel(this); + manNovel.options.saveLocation = manSaveLocation.getText(); + manNovel.host.chapterContainer = manChapterContainer.getText(); + manNovel.host.blacklistedTags = GUI.blacklistedTags; + manNovel.options.window = "manual"; + //Optional + manNovel.options.waitTime = Integer.parseInt(manWaitTime.getText()); + manNovel.options.displayChapterTitle = manDispalyChapterTitleCheckbox.isSelected(); + manNovel.options.invertOrder = manInvertOrder.isSelected(); + manNovel.options.headless = manUseHeaderlessBrowser.isSelected(); + manNovel.options.browser = manBrowserCombobox.getSelectedItem().toString(); + + manNovel.manGetMetadata(); + manNovel.processChaptersToChapters(chapterToChapterArgs); + + manNovel.createCoverPage(); + manNovel.createToc(); + manNovel.createDescPage(); + manNovel.createEPUB(); + manNovel.report(); + } catch (Exception err) { + appendText("manual", "[ERROR]"+err.getMessage()); err.printStackTrace(); + manNovel.killTask = false; } finally { manProgressBar.setStringPainted(false); manProgressBar.setValue(0); @@ -415,6 +468,7 @@ public GUI() { manStopButton.setVisible(false); } } + // Download chapters from link list // input validation } else { if (manNovelURL.getText().isEmpty()) { @@ -443,11 +497,31 @@ public GUI() { manStopButton.setVisible(true); manProgressBar.setStringPainted(true); try { - manNovel = new ManNovel(this, "chaptersFromList"); - // Exception handling - } catch (NullPointerException | IllegalArgumentException err) { - appendText("manual", err.getMessage()); + // Needed + manNovel.options.saveLocation = manSaveLocation.getText(); + manNovel.host.chapterContainer = manChapterContainer.getText(); + manNovel.host.blacklistedTags = GUI.blacklistedTags; + manNovel.options.window = "manual"; + //Optional + manNovel.options.waitTime = Integer.parseInt(manWaitTime.getText()); + manNovel.options.displayChapterTitle = manDispalyChapterTitleCheckbox.isSelected(); + manNovel.options.invertOrder = manInvertOrder.isSelected(); + manNovel.options.headless = manUseHeaderlessBrowser.isSelected(); + manNovel.options.browser = manBrowserCombobox.getSelectedItem().toString(); + + // new Novel was created when retrieving links + manNovel.manGetMetadata(); + manNovel.processChaptersFromList(); + + manNovel.createCoverPage(); + manNovel.createToc(); + manNovel.createDescPage(); + manNovel.createEPUB(); + manNovel.report(); + } catch (Exception err) { + appendText("manual", "[ERROR]"+err.getMessage()); err.printStackTrace(); + manNovel.killTask = false; } finally { manProgressBar.setStringPainted(false); manProgressBar.setValue(0); @@ -459,6 +533,43 @@ public GUI() { } } })); + + chaptersFromLinksRadioButton.addActionListener(e -> { + if (chaptersFromLinksRadioButton.isSelected()) { + chapterToChapterRadioButton.setSelected(false); + manNovelURL.setVisible(true); + getLinksButton.setVisible(true); + manTocURLlbl.setVisible(true); + chapterToChapterButton.setVisible(false); + manInvertOrder.setEnabled(true); + } + }); + + chapterToChapterRadioButton.addActionListener(e -> { + if (chapterToChapterRadioButton.isSelected()) { + chaptersFromLinksRadioButton.setSelected(false); + manNovelURL.setVisible(false); + getLinksButton.setVisible(false); + manTocURLlbl.setVisible(false); + chapterToChapterButton.setVisible(true); + manInvertOrder.setEnabled(false); + } + }); + + manRemoveLinksButton.addActionListener(arg0 -> { + if (!listModelChapterLinks.isEmpty()) { + int[] indices = manLinkList.getSelectedIndices(); + for (int i = indices.length - 1; i >= 0; i--) { + listModelChapterLinks.removeElementAt(indices[i]); + manNovel.chapters.remove(indices[i]); + } + if (listModelChapterLinks.isEmpty()) { + manRemoveLinksButton.setEnabled(false); + } + appendText("manual", indices.length + " links removed."); + } + }); + manBrowseLocationButton.addActionListener(arg0 -> { JFileChooser chooser = new JFileChooser(); chooser.setCurrentDirectory(new File(".")); @@ -470,64 +581,18 @@ public GUI() { manSaveLocation.setText(chooser.getSelectedFile().toString()); } }); + manSetMetadataButton.addActionListener(arg0 -> manSetMetadata.main()); + manBlackListedTags.addActionListener(e -> manSetBlacklistedTags.main()); - chapterToChapterButton.addActionListener(e -> ChapterToChapter.main()); - updateButton.addActionListener(e -> Executors.newSingleThreadExecutor().execute(() -> { - updaterStatus.setVisible(true); - updateButton.setVisible(false); - checkForUpdatesButton.setVisible(false); - updaterStatus.setText("Updating..."); - updater.updateJar(); - })); - checkAddNewEntryBtn.addActionListener(arg0 -> { - String host = (String) JOptionPane.showInputDialog(this, - "Pick host:", "Add a autoNovel to check", JOptionPane.PLAIN_MESSAGE, null, HostSettings.websites, "wuxiaworld"); - String checkUrl = JOptionPane.showInputDialog(this, - "Novel URL:", "Add a autoNovel to check", JOptionPane.PLAIN_MESSAGE); - if (!(checkUrl == null) && !(host == null)) { - if (!host.isEmpty() && !checkUrl.isEmpty()) { - if (HostSettings.autoChapterToChapterWebsitesList.contains(host)) { - appendText("checker", host + " is not supported."); - return; - } - host = host.toLowerCase().replace(" ", ""); - listModelCheckerLinks.addElement("[" + checkUrl + "]"); - chapterChecker.hosts.add(host); - chapterChecker.urls.add(checkUrl); - checkRemoveEntry.setEnabled(true); - checkPollStartBtn.setEnabled(true); - } - } - }); - checkPollStartBtn.addActionListener(g -> { - if (chapterChecker.urls.isEmpty() || chapterChecker.hosts.isEmpty()) { - showPopup("No checkers defined", "warning"); - } else { - startPolling(); - } - }); - checkStopPollingBtn.addActionListener(g -> stopPolling()); + chapterToChapterButton.addActionListener(e -> ChapterToChapter.main()); - checkRemoveEntry.addActionListener(gc -> { - int[] indices = checkerList.getSelectedIndices(); - for (int i = indices.length - 1; i >= 0; i--) { - listModelCheckerLinks.removeElementAt(indices[i]); - chapterChecker.hosts.remove(indices[i]); - chapterChecker.urls.remove(indices[i]); - } - if (listModelCheckerLinks.isEmpty()) { - checkRemoveEntry.setEnabled(false); - checkPollStartBtn.setEnabled(false); - } - }); - autoEditMetadataButton.addActionListener(e -> { - }); manStopButton.addActionListener(e -> { manStopButton.setEnabled(false); manNovel.killTask = true; }); + manJsoupInfoButton.addActionListener(e -> { try { openWebpage(new URI("https://jsoup.org/cookbook/extracting-data/selector-syntax")); @@ -535,65 +600,27 @@ public GUI() { ex.printStackTrace(); } }); - autoHostSelection.addItemListener(e -> { - String selection = autoHostSelection.getSelectedItem().toString(); - if (HostSettings.headerlessBrowserWebsitesList.contains(selection)) { - useHeaderlessBrowserCheckBox.setSelected(true); - useHeaderlessBrowserCheckBox.setEnabled(false); - } else { - useHeaderlessBrowserCheckBox.setEnabled(true); - } - if (HostSettings.autoChapterToChapterWebsitesList.contains(selection)) { - chapterAllCheckBox.setEnabled(false); - firstChapter.setEnabled(false); - lastChapter.setEnabled(false); - toLastChapter.setEnabled(false); - checkInvertOrder.setEnabled(false); - autoChapterToChapterNumberField.setVisible(true); - autoFirstChapterLbl.setVisible(true); - autoFirstChapterURL.setVisible(true); - autoLastChapterLbl.setVisible(true); - autoLastChapterURL.setVisible(true); - } else { - chapterAllCheckBox.setEnabled(true); - firstChapter.setEnabled(true); - lastChapter.setEnabled(true); - toLastChapter.setEnabled(true); - checkInvertOrder.setEnabled(true); - autoChapterToChapterNumberField.setVisible(false); - autoFirstChapterLbl.setVisible(false); - autoFirstChapterURL.setVisible(false); - autoLastChapterLbl.setVisible(false); - autoLastChapterURL.setVisible(false); - } - if (HostSettings.noHeaderlessBrowserWebsitesList.contains(selection)) { - useHeaderlessBrowserCheckBox.setSelected(false); - useHeaderlessBrowserCheckBox.setEnabled(false); - } - }); - autoEditBlacklistBtn.addActionListener(e -> autoSetBlacklistedTags.main(autoNovel)); - autoEditMetaBtn.addActionListener(e -> autoEditMetadata.main(autoNovel)); - checkForUpdatesButton.addActionListener(e -> Executors.newSingleThreadExecutor().execute(this::checkForNewReleases)); - autoChapterToChapterNumberField.addFocusListener(new FocusListener() { + manAddChapterButton.addActionListener(new ActionListener() { @Override - public void focusGained(FocusEvent e) { - if (autoChapterToChapterNumberField.getText().equals("Number")) { - autoChapterToChapterNumberField.setText(""); - autoChapterToChapterNumberField.setForeground(Color.BLACK); - } - } + public void actionPerformed(ActionEvent actionEvent) { - @Override - public void focusLost(FocusEvent e) { - if (autoChapterToChapterNumberField.getText().isEmpty()) { - autoChapterToChapterNumberField.setForeground(Color.GRAY); - autoChapterToChapterNumberField.setText("Number"); - } } }); + + updateButton.addActionListener(e -> Executors.newSingleThreadExecutor().execute(() -> { + updaterStatus.setVisible(true); + updateButton.setVisible(false); + checkForUpdatesButton.setVisible(false); + updaterStatus.setText("Downloading..."); + Updater.updateJar(); + })); + + checkForUpdatesButton.addActionListener(e -> Executors.newSingleThreadExecutor().execute(this::checkForNewReleases)); + } + // GUI functions public static void main(String[] args) { EventQueue.invokeLater(() -> { try { @@ -606,6 +633,25 @@ public static void main(String[] args) { }); } + private void initialize() { + add(rootPanel); + setTitle("Novel-Grabber " + versionNumber); + ImageIcon favicon = new ImageIcon(getClass().getResource("/files//images/favicon.png")); + setIconImage(favicon.getImage()); + setMinimumSize(new Dimension(923, 683)); + Tray(); + setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE); + if (!SystemTray.isSupported()) { + setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + } + addWindowListener(new WindowAdapter() { + @Override + public void windowClosing(WindowEvent e) { + setVisible(false); + } + }); + } + private static void openWebpage(URI uri) { Desktop desktop = Desktop.isDesktopSupported() ? Desktop.getDesktop() : null; if (desktop != null && desktop.isSupported(Desktop.Action.BROWSE)) { @@ -637,25 +683,7 @@ private void showMenu(MouseEvent e) { }); } - private void initialize() { - add(rootPanel); - setTitle("Novel-Grabber " + versionNumber); - ImageIcon favicon = new ImageIcon(getClass().getResource("/images/favicon.png")); - setIconImage(favicon.getImage()); - setMinimumSize(new Dimension(923, 683)); - Tray(); - setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE); - if (!SystemTray.isSupported()) { - setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); - tabbedPane.setEnabledAt(2, false); - } - addWindowListener(new WindowAdapter() { - @Override - public void windowClosing(WindowEvent e) { - setVisible(false); - } - }); - } + private void Tray() { if (!SystemTray.isSupported()) { @@ -663,7 +691,7 @@ private void Tray() { return; } SystemTray tray = SystemTray.getSystemTray(); - Image image = Toolkit.getDefaultToolkit().getImage(getClass().getResource("/images/favicon.png")); + Image image = Toolkit.getDefaultToolkit().getImage(getClass().getResource("/files//images/favicon.png")); ActionListener exitListener = e -> System.exit(0); ActionListener openWindow = e -> setVisible(true); @@ -689,13 +717,6 @@ private void Tray() { }); popup.add(aboutLabel); - - popup.addSeparator(); - defaultItem0 = new MenuItem("checker not active"); - defaultItem0.addActionListener(arg0 -> { - if (chapterChecker.checkerRunning) stopPolling(); - }); - popup.add(defaultItem0); popup.addSeparator(); MenuItem defaultItem2 = new MenuItem("Open"); defaultItem2.addActionListener(openWindow); @@ -715,67 +736,6 @@ private void Tray() { } } - public void stopPolling() { - checkStatusLbl.setText("Stopping polling..."); - checkStopPollingBtn.setEnabled(false); - chapterChecker.checkerRunning = false; - defaultItem0.setLabel("checker not active"); - Executors.newSingleThreadExecutor().execute(() -> chapterChecker.killTask(this)); - } - - private void startPolling() { - appendText("checker", "Started polling."); - checkPollStartBtn.setEnabled(false); - checkPollStartBtn.setVisible(false); - checkStopPollingBtn.setVisible(true); - checkStopPollingBtn.setEnabled(false); - checkAddNewEntryBtn.setEnabled(false); - checkRemoveEntry.setEnabled(false); - defaultItem0.setLabel("Stop polling"); - checkBusyIcon.setVisible(true); - checkStatusLbl.setVisible(true); - Executors.newSingleThreadExecutor().execute(() -> chapterChecker.chapterPolling(this)); - } - - public void resetCheckerGUIButtons() { - if (chapterChecker.urls.isEmpty()) { - checkRemoveEntry.setEnabled(false); - checkPollStartBtn.setEnabled(false); - } else { - checkRemoveEntry.setEnabled(true); - checkPollStartBtn.setEnabled(true); - } - checkPollStartBtn.setVisible(true); - checkAddNewEntryBtn.setEnabled(true); - checkBusyIcon.setVisible(false); - checkStopPollingBtn.setVisible(false); - checkStatusLbl.setVisible(false); - } - - private void loadDefaultCheckerList() { - File filepath = new File(appdataPath + File.separator + "default.json"); - if (filepath.exists()) { - checkDefaultFileLabel.setVisible(false); - checkDefaultFileLabel.setEnabled(false); - JSONParser parser = new JSONParser(); - try { - JSONArray a = (JSONArray) parser.parse(new FileReader(filepath)); - for (Object o : a) { - JSONObject checker = (JSONObject) o; - chapterChecker.hosts.add((String) checker.get("HOST")); - chapterChecker.urls.add((String) checker.get("URL")); - listModelCheckerLinks.addElement("[" + checker.get("URL") + "]"); - } - } catch (IOException | ParseException ec) { - ec.printStackTrace(); - } - if (!listModelCheckerLinks.isEmpty()) { - appendText("checker", "Loaded default checker list."); - startPolling(); - } - } - } - public void appendText(String logWindow, String logMsg) { switch (logWindow) { case "auto": @@ -797,8 +757,8 @@ public void appendText(String logWindow, String logMsg) { } } - public void setMaxProgress(String progressBarSelect, int progressAmount) { - switch (progressBarSelect) { + public void setMaxProgress(String window, int progressAmount) { + switch (window) { case "auto": progressBar.setMaximum(progressAmount); progressBar.setString("0 / " + progressAmount); @@ -812,8 +772,8 @@ public void setMaxProgress(String progressBarSelect, int progressAmount) { } } - public void updateProgress(String progressBarSelect) { - switch (progressBarSelect) { + public void updateProgress(String window) { + switch (window) { case "auto": progressBar.setValue(progressBar.getValue() + 1); if (progressBar.getValue() <= progressBar.getMaximum()) { @@ -849,7 +809,7 @@ private void checkForNewReleases() { Element versionString = doc.select("a[title]").first(); String oldVersionString = versionNumber; String newVersionString = versionString.attr("title"); - if (updater.compareStrings(oldVersionString, newVersionString) == -1) { + if (Updater.compareStrings(oldVersionString, newVersionString) == -1) { updateTextArea.setText(""); updateStatusLbl.setText("A new update of Novel-Grabber was released. The latest version is: " + newVersionString); setTitle("Novel-Grabber " + versionNumber + " - New version released"); @@ -872,7 +832,7 @@ private void checkForNewReleases() { public void setBufferedCover(BufferedImage bufferedImage) { if (bufferedImage == null) - coverImage.setIcon(new ImageIcon(getClass().getResource("/images/cover_placeholder.png"))); + coverImage.setIcon(new ImageIcon(getClass().getResource("/files//images/cover_placeholder.png"))); else coverImage.setIcon(new ImageIcon(new ImageIcon(bufferedImage).getImage().getScaledInstance(100, 133, Image.SCALE_DEFAULT))); } @@ -886,16 +846,16 @@ private void createUIComponents() { autoChapterToChapterNumberField = new JTextField("Number"); autoChapterToChapterNumberField.setForeground(Color.GRAY); - autoShowBlacklistedTagsBtn = new JButton(new ImageIcon(getClass().getResource("/images/block.png"))); + autoShowBlacklistedTagsBtn = new JButton(new ImageIcon(getClass().getResource("/files//images/block.png"))); autoShowBlacklistedTagsBtn.setBorder(BorderFactory.createEmptyBorder()); autoShowBlacklistedTagsBtn.setContentAreaFilled(false); - autoCheckAvailability = new JButton(new ImageIcon(getClass().getResource("/images/check_icon.png"))); + autoCheckAvailability = new JButton(new ImageIcon(getClass().getResource("/files//images/check_icon.png"))); autoCheckAvailability.setBorder(BorderFactory.createEmptyBorder()); autoCheckAvailability.setContentAreaFilled(false); chapterListURL = new JTextField(); - // Listen for changes in the text + // Listen for changes in the novel link field and disable the grabbing button chapterListURL.getDocument().addDocumentListener(new DocumentListener() { public void changedUpdate(DocumentEvent e) { warn(); @@ -914,37 +874,35 @@ void warn() { } }); - autoVisitButton = new JButton(new ImageIcon(getClass().getResource("/images/website_icon.png"))); + autoVisitButton = new JButton(new ImageIcon(getClass().getResource("/files//images/website_icon.png"))); autoVisitButton.setBorder(BorderFactory.createEmptyBorder()); autoVisitButton.setContentAreaFilled(false); - autoBusyLabel = new JLabel(new ImageIcon(getClass().getResource("/images/busy.gif"))); + autoBusyLabel = new JLabel(new ImageIcon(getClass().getResource("/files//images/busy.gif"))); - browseButton = new JButton(new ImageIcon(getClass().getResource("/images/folder_icon.png"))); + browseButton = new JButton(new ImageIcon(getClass().getResource("/files//images/folder_icon.png"))); browseButton.setBorder(BorderFactory.createEmptyBorder()); browseButton.setContentAreaFilled(false); - coverImage = new JLabel(new ImageIcon(getClass().getResource("/images/cover_placeholder.png"))); + coverImage = new JLabel(new ImageIcon(getClass().getResource("/files//images/cover_placeholder.png"))); coverImage.setBorder(BorderFactory.createEmptyBorder()); - autoEditMetadataButton = new JButton(new ImageIcon(getClass().getResource("/images/settings_icon.png"))); + autoEditMetadataButton = new JButton(new ImageIcon(getClass().getResource("/files//images/settings_icon.png"))); autoEditMetadataButton.setBorder(BorderFactory.createEmptyBorder()); autoEditMetadataButton.setContentAreaFilled(false); - autoEditMetaBtn = new JButton(new ImageIcon(getClass().getResource("/images/edit.png"))); + autoEditMetaBtn = new JButton(new ImageIcon(getClass().getResource("/files//images/edit.png"))); autoEditMetaBtn.setBorder(BorderFactory.createEmptyBorder()); autoEditMetaBtn.setContentAreaFilled(false); - autoEditBlacklistBtn = new JButton(new ImageIcon(getClass().getResource("/images/block.png"))); + autoEditBlacklistBtn = new JButton(new ImageIcon(getClass().getResource("/files//images/block.png"))); autoEditBlacklistBtn.setBorder(BorderFactory.createEmptyBorder()); autoEditBlacklistBtn.setContentAreaFilled(false); - autoGetNumberButton = new JButton(new ImageIcon(getClass().getResource("/images/search_icon.png"))); + autoGetNumberButton = new JButton(new ImageIcon(getClass().getResource("/files//images/search_icon.png"))); autoGetNumberButton.setBorder(BorderFactory.createEmptyBorder()); autoGetNumberButton.setContentAreaFilled(false); - exportSelection = new JComboBox<>(exportFormats); - waitTime = new JTextField("0"); waitTime.setHorizontalAlignment(SwingConstants.CENTER); @@ -961,15 +919,15 @@ void warn() { // Manual Tab manBrowserCombobox = new JComboBox(browserList); - manSetMetadataButton = new JButton(new ImageIcon(getClass().getResource("/images/edit.png"))); + manSetMetadataButton = new JButton(new ImageIcon(getClass().getResource("/files//images/edit.png"))); manSetMetadataButton.setBorder(BorderFactory.createEmptyBorder()); manSetMetadataButton.setContentAreaFilled(false); - manBlackListedTags = new JButton(new ImageIcon(getClass().getResource("/images/block.png"))); + manBlackListedTags = new JButton(new ImageIcon(getClass().getResource("/files//images/block.png"))); manBlackListedTags.setBorder(BorderFactory.createEmptyBorder()); manBlackListedTags.setContentAreaFilled(false); - manRemoveLinksButton = new JButton(new ImageIcon(getClass().getResource("/images/remove_icon.png"))); + manRemoveLinksButton = new JButton(new ImageIcon(getClass().getResource("/files//images/remove_icon.png"))); manRemoveLinksButton.setBorder(BorderFactory.createEmptyBorder()); manRemoveLinksButton.setContentAreaFilled(false); @@ -981,16 +939,14 @@ void warn() { manLogArea.setWrapStyleWord(true); manLogScrollPane = new JScrollPane(manLogArea, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); - manJsoupInfoButton = new JButton(new ImageIcon(getClass().getResource("/images/info_icon.png"))); + manJsoupInfoButton = new JButton(new ImageIcon(getClass().getResource("/files//images/info_icon.png"))); manJsoupInfoButton.setBorder(BorderFactory.createEmptyBorder()); manJsoupInfoButton.setContentAreaFilled(false); - manBrowseLocationButton = new JButton(new ImageIcon(getClass().getResource("/images/folder_icon.png"))); + manBrowseLocationButton = new JButton(new ImageIcon(getClass().getResource("/files//images/folder_icon.png"))); manBrowseLocationButton.setBorder(BorderFactory.createEmptyBorder()); manBrowseLocationButton.setContentAreaFilled(false); - manExportSelection = new JComboBox<>(exportFormats); - manWaitTime = new JTextField("0"); manWaitTime.setHorizontalAlignment(SwingConstants.CENTER); @@ -999,107 +955,5 @@ void warn() { updateTextArea.setLineWrap(true); updateTextArea.setWrapStyleWord(true); updateScrollPane = new JScrollPane(updateTextArea, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); - - // Checker - checkRemoveEntry = new JButton(new ImageIcon(getClass().getResource("/images/remove_icon.png"))); - checkRemoveEntry.setBorder(BorderFactory.createEmptyBorder()); - checkRemoveEntry.setContentAreaFilled(false); - - checkAddNewEntryBtn = new JButton(new ImageIcon(getClass().getResource("/images/add_icon.png"))); - checkAddNewEntryBtn.setBorder(BorderFactory.createEmptyBorder()); - checkAddNewEntryBtn.setContentAreaFilled(false); - - checkPollStartBtn = new JButton(new ImageIcon(getClass().getResource("/images/start_icon.png"))); - checkPollStartBtn.setBorder(BorderFactory.createEmptyBorder()); - checkPollStartBtn.setContentAreaFilled(false); - - checkStopPollingBtn = new JButton(new ImageIcon(getClass().getResource("/images/stop_icon.png"))); - checkStopPollingBtn.setBorder(BorderFactory.createEmptyBorder()); - checkStopPollingBtn.setContentAreaFilled(false); - - checkerList = new JList(listModelCheckerLinks); - checkerListScrollPane = new JScrollPane(checkerList, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); - - checkBusyIcon = new JLabel(new ImageIcon(getClass().getResource("/images/busy.gif"))); - - checkerLogArea = new JTextArea(); - checkerLogArea.setLineWrap(true); - checkerLogArea.setWrapStyleWord(true); - checkerLogScrollPane = new JScrollPane(checkerLogArea, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); - - JPopupMenu checkPopUp = new JPopupMenu(); - addPopup(checkerList, checkPopUp); - - JMenuItem checkLoadFromFile = new JMenuItem("Load Checkers from file"); - checkLoadFromFile.addActionListener(e -> { - JFileChooser chooser = new JFileChooser(); - chooser.setCurrentDirectory(new File(appdataPath)); - chooser.setDialogTitle("Open File"); - chooser.setFileSelectionMode(JFileChooser.FILES_ONLY); - chooser.setAcceptAllFileFilterUsed(false); - FileNameExtensionFilter filter = new FileNameExtensionFilter("*.json", "json", "JSON"); - chooser.setFileFilter(filter); - String filepath; - if (chooser.showOpenDialog(null) == JFileChooser.APPROVE_OPTION) { - listModelCheckerLinks.clear(); - chapterChecker.hosts.clear(); - chapterChecker.urls.clear(); - filepath = chooser.getSelectedFile().toString(); - JSONParser parser = new JSONParser(); - try { - JSONArray a = (JSONArray) parser.parse(new FileReader(filepath)); - for (Object o : a) { - JSONObject checker = (JSONObject) o; - chapterChecker.hosts.add((String) checker.get("HOST")); - chapterChecker.urls.add((String) checker.get("URL")); - listModelCheckerLinks.addElement("[" + checker.get("URL") + "]"); - } - } catch (IOException | ParseException ec) { - ec.printStackTrace(); - } - if (!listModelCheckerLinks.isEmpty()) { - checkRemoveEntry.setEnabled(true); - checkPollStartBtn.setEnabled(true); - } - appendText("checker", "Loaded checkers from file."); - } - }); - checkLoadFromFile.setFont(new Font("Segoe UI", Font.PLAIN, 11)); - checkPopUp.add(checkLoadFromFile); - - JSeparator separator_12 = new JSeparator(); - checkPopUp.add(separator_12); - - JMenuItem checkToFile = new JMenuItem("Save to file"); - checkToFile.setToolTipText( - "

Save checkers to file. \"default.txt\" will be loaded and started on startup.

"); - checkToFile.addActionListener(e -> { - if (chapterChecker.urls.isEmpty()) { - showPopup("checker list is empty", "warning"); - return; - } - File dir = new File(appdataPath); - if (!dir.exists()) dir.mkdirs(); - JFileChooser chooser = new JFileChooser(); - chooser.setCurrentDirectory(new File(appdataPath)); - chooser.setDialogTitle("Save As"); - chooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES); - chooser.setAcceptAllFileFilterUsed(false); - FileNameExtensionFilter filter = new FileNameExtensionFilter("*.json", "json", "JSON"); - chooser.setFileFilter(filter); - if (chooser.showSaveDialog(null) == JFileChooser.APPROVE_OPTION) { - String filepath = chooser.getSelectedFile().toString(); - if (!filepath.endsWith(".json")) filepath = filepath + ".json"; - chapterChecker.writeDataToJSON(filepath, false); - if ("default.json".equals(filepath)) { - checkDefaultFileLabel.setVisible(false); - checkDefaultFileLabel.setEnabled(false); - appendText("checker", "Set new default checkers list."); - } - appendText("checker", "Saved checkers to file."); - } - }); - checkToFile.setFont(new Font("Segoe UI", Font.PLAIN, 11)); - checkPopUp.add(checkToFile); } } diff --git a/src/gui/autoEditMetadata.form b/src/gui/autoEditMetadata.form index f079ab9..a4d1d5e 100644 --- a/src/gui/autoEditMetadata.form +++ b/src/gui/autoEditMetadata.form @@ -1,183 +1,183 @@ - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/src/gui/autoEditMetadata.java b/src/gui/autoEditMetadata.java index d4feb1a..a5de5fe 100644 --- a/src/gui/autoEditMetadata.java +++ b/src/gui/autoEditMetadata.java @@ -1,166 +1,166 @@ -package gui; - -import grabber.AutoNovel; - -import javax.imageio.ImageIO; -import javax.swing.*; -import javax.swing.filechooser.FileNameExtensionFilter; -import java.awt.*; -import java.awt.event.*; -import java.awt.image.BufferedImage; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -public class autoEditMetadata extends JDialog { - public static List manMetadataTags = new ArrayList<>(); - private JPanel contentPane; - private JButton buttonOK; - private JButton buttonCancel; - private JButton manMetadataImageButton; - private JTextField manSetMetadataTitleField; - private JTextField manSetMetadataAuthorField; - private JTextField manSetMetadataTags; - private JScrollPane autoEditMetadataDescScrollPane; - private JTextArea autoEditMetadataDescArea; - private JCheckBox ignoreDescriptionCheckBox; - private AutoNovel currGrab; - - private autoEditMetadata(AutoNovel currGrab) { - this.currGrab = currGrab; - setContentPane(contentPane); - setModal(true); - setTitle("Edit EPUB metadata"); - ImageIcon favicon = new ImageIcon(getClass().getResource("/images/favicon.png")); - setIconImage(favicon.getImage()); - getRootPane().setDefaultButton(buttonOK); - - buttonOK.addActionListener(e -> onOK()); - - buttonCancel.addActionListener(e -> onCancel()); - - // call onCancel() when cross is clicked - setDefaultCloseOperation(DO_NOTHING_ON_CLOSE); - addWindowListener(new WindowAdapter() { - public void windowClosing(WindowEvent e) { - onCancel(); - } - }); - - // call onCancel() on ESCAPE - contentPane.registerKeyboardAction(e -> onCancel(), KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT); - manMetadataImageButton.addComponentListener(new ComponentAdapter() { - }); - manMetadataImageButton.addActionListener(arg01 -> { - JFileChooser chooser = new JFileChooser(); - chooser.setDialogTitle("Open File"); - chooser.setFileSelectionMode(JFileChooser.FILES_ONLY); - chooser.setAcceptAllFileFilterUsed(false); - FileNameExtensionFilter filter = new FileNameExtensionFilter("jpg png gif", "png", "jpg", "gif"); - chooser.setFileFilter(filter); - if (chooser.showOpenDialog(null) == JFileChooser.APPROVE_OPTION) { - currGrab.bookCover = chooser.getSelectedFile().toString(); - try { - BufferedImage imageInput = ImageIO.read(chooser.getSelectedFile()); - currGrab.bufferedCover = imageInput; - currGrab.bufferedCoverName = chooser.getSelectedFile().getName(); - currGrab.bookCover = chooser.getSelectedFile().getName(); - } catch (IOException e) { - currGrab.gui.appendText("auto", e.getMessage()); - } - manMetadataImageButton.setIcon(new ImageIcon(new ImageIcon(currGrab.bufferedCover).getImage().getScaledInstance(100, 133, Image.SCALE_DEFAULT))); - } - }); - ignoreDescriptionCheckBox.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - if (ignoreDescriptionCheckBox.isSelected()) autoEditMetadataDescArea.setEnabled(false); - else { - autoEditMetadataDescArea.setEnabled(true); - } - } - }); - } - - static void main(AutoNovel currGrab) { - autoEditMetadata dialog = new autoEditMetadata(currGrab); - dialog.pack(); - dialog.setVisible(true); - } - - private void onOK() { - // Adjust the metadata on the GUI - // Book Title - currGrab.bookTitle = manSetMetadataTitleField.getText(); - currGrab.gui.autoBookTitle.setText(currGrab.bookTitle); - // Book Description - currGrab.bookDesc.set(0, autoEditMetadataDescArea.getText()); - // Book Author - currGrab.bookAuthor = manSetMetadataAuthorField.getText(); - currGrab.gui.autoAuthor.setText(currGrab.bookAuthor); - currGrab.bookSubjects = Arrays.asList(manSetMetadataTags.getText().split(",")); - // No description - currGrab.noDescription = ignoreDescriptionCheckBox.isSelected(); - // Book Tags - manSetMetadataTags.setText(""); - int maxNumberOfSubjects = 0; - currGrab.gui.autoBookSubjects.setText(""); - for (String eachTag : currGrab.bookSubjects) { - currGrab.gui.autoBookSubjects.setText(currGrab.gui.autoBookSubjects.getText() + eachTag + ", "); - maxNumberOfSubjects++; - if (maxNumberOfSubjects == 4) { - maxNumberOfSubjects = 0; - currGrab.gui.autoBookSubjects.setText(currGrab.gui.autoBookSubjects.getText() + "
"); - } - } - if (!currGrab.gui.autoBookSubjects.getText().isEmpty()) { - currGrab.gui.autoBookSubjects.setText( - currGrab.gui.autoBookSubjects.getText().substring(0, - currGrab.gui.autoBookSubjects.getText().lastIndexOf(","))); - } - // Book Cover - if (currGrab.bufferedCover != null) currGrab.gui.setBufferedCover(currGrab.bufferedCover); - dispose(); - } - - private void onCancel() { - dispose(); - } - - private void createUIComponents() { - ignoreDescriptionCheckBox = new JCheckBox(); - ignoreDescriptionCheckBox.setSelected(currGrab.noDescription); - autoEditMetadataDescArea = new JTextArea(currGrab.bookDesc.get(0)); - autoEditMetadataDescArea.setLineWrap(true); - autoEditMetadataDescArea.setWrapStyleWord(true); - autoEditMetadataDescArea.setEnabled(!ignoreDescriptionCheckBox.isSelected()); - autoEditMetadataDescScrollPane = new JScrollPane(autoEditMetadataDescArea, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED); - if (currGrab.bookSubjects != null && currGrab.bookTitle != null && currGrab.bookAuthor != null) { - manSetMetadataTitleField = new JTextField(currGrab.bookTitle); - manSetMetadataAuthorField = new JTextField(currGrab.bookAuthor); - manSetMetadataTags = new JTextField(); - for (String tag : currGrab.bookSubjects) { - manSetMetadataTags.setText(manSetMetadataTags.getText() + tag + ","); - } - // Removes last ',' from string - if (!manSetMetadataTags.getText().isEmpty()) { - manSetMetadataTags.setText( - manSetMetadataTags.getText().substring(0, - manSetMetadataTags.getText().lastIndexOf(","))); - } - } - - if (currGrab.bookCover == null) { - manMetadataImageButton = new JButton(); - manMetadataImageButton.setIcon(new ImageIcon(getClass().getResource("/images/cover_placeholder.png"))); - manMetadataImageButton.setBorder(BorderFactory.createEmptyBorder()); - manMetadataImageButton.setContentAreaFilled(false); - } else { - manMetadataImageButton = new JButton(); - manMetadataImageButton.setIcon(new ImageIcon(new ImageIcon(currGrab.bufferedCover).getImage().getScaledInstance(100, 133, Image.SCALE_DEFAULT))); - manMetadataImageButton.setBorder(BorderFactory.createEmptyBorder()); - manMetadataImageButton.setContentAreaFilled(false); - } - } -} +package gui; + +import grabber.Novel; + +import javax.imageio.ImageIO; +import javax.swing.*; +import javax.swing.filechooser.FileNameExtensionFilter; +import java.awt.*; +import java.awt.event.*; +import java.awt.image.BufferedImage; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public class autoEditMetadata extends JDialog { + public static List manMetadataTags = new ArrayList<>(); + private JPanel contentPane; + private JButton buttonOK; + private JButton buttonCancel; + private JButton manMetadataImageButton; + private JTextField manSetMetadataTitleField; + private JTextField manSetMetadataAuthorField; + private JTextField manSetMetadataTags; + private JScrollPane autoEditMetadataDescScrollPane; + private JTextArea autoEditMetadataDescArea; + private JCheckBox ignoreDescriptionCheckBox; + private Novel novel; + + private autoEditMetadata(Novel novel) { + this.novel = novel; + setContentPane(contentPane); + setModal(true); + setTitle("Edit EPUB metadata"); + ImageIcon favicon = new ImageIcon(getClass().getResource("/files/images/favicon.png")); + setIconImage(favicon.getImage()); + getRootPane().setDefaultButton(buttonOK); + + buttonOK.addActionListener(e -> onOK()); + + buttonCancel.addActionListener(e -> onCancel()); + + // call onCancel() when cross is clicked + setDefaultCloseOperation(DO_NOTHING_ON_CLOSE); + addWindowListener(new WindowAdapter() { + public void windowClosing(WindowEvent e) { + onCancel(); + } + }); + + // call onCancel() on ESCAPE + contentPane.registerKeyboardAction(e -> onCancel(), KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT); + manMetadataImageButton.addComponentListener(new ComponentAdapter() { + }); + manMetadataImageButton.addActionListener(arg01 -> { + JFileChooser chooser = new JFileChooser(); + chooser.setDialogTitle("Open File"); + chooser.setFileSelectionMode(JFileChooser.FILES_ONLY); + chooser.setAcceptAllFileFilterUsed(false); + FileNameExtensionFilter filter = new FileNameExtensionFilter("jpg png gif", "png", "jpg", "gif"); + chooser.setFileFilter(filter); + if (chooser.showOpenDialog(null) == JFileChooser.APPROVE_OPTION) { + novel.metadata.bookCover = chooser.getSelectedFile().toString(); + try { + BufferedImage imageInput = ImageIO.read(chooser.getSelectedFile()); + novel.metadata.bufferedCover = imageInput; + novel.metadata.bufferedCoverName = chooser.getSelectedFile().getName(); + novel.metadata.bookCover = chooser.getSelectedFile().getName(); + } catch (IOException e) { + novel.gui.appendText("auto", e.getMessage()); + } + manMetadataImageButton.setIcon(new ImageIcon(new ImageIcon(novel.metadata.bufferedCover).getImage().getScaledInstance(100, 133, Image.SCALE_DEFAULT))); + } + }); + ignoreDescriptionCheckBox.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + if (ignoreDescriptionCheckBox.isSelected()) autoEditMetadataDescArea.setEnabled(false); + else { + autoEditMetadataDescArea.setEnabled(true); + } + } + }); + } + + static void main(Novel currGrab) { + autoEditMetadata dialog = new autoEditMetadata(currGrab); + dialog.pack(); + dialog.setVisible(true); + } + + private void onOK() { + // Adjust the metadata on the GUI + // Book Title + novel.metadata.bookTitle = manSetMetadataTitleField.getText(); + novel.gui.autoBookTitle.setText(novel.metadata.bookTitle); + // Book Description + novel.metadata.bookDesc.set(0, autoEditMetadataDescArea.getText()); + // Book Author + novel.metadata.bookAuthor = manSetMetadataAuthorField.getText(); + novel.gui.autoAuthor.setText(novel.metadata.bookAuthor); + novel.metadata.bookSubjects = Arrays.asList(manSetMetadataTags.getText().split(",")); + // No description + novel.options.noDescription = ignoreDescriptionCheckBox.isSelected(); + // Book Tags + manSetMetadataTags.setText(""); + int maxNumberOfSubjects = 0; + novel.gui.autoBookSubjects.setText(""); + for (String eachTag : novel.metadata.bookSubjects) { + novel.gui.autoBookSubjects.setText(novel.gui.autoBookSubjects.getText() + eachTag + ", "); + maxNumberOfSubjects++; + if (maxNumberOfSubjects == 4) { + maxNumberOfSubjects = 0; + novel.gui.autoBookSubjects.setText(novel.gui.autoBookSubjects.getText() + "
"); + } + } + if (!novel.gui.autoBookSubjects.getText().isEmpty()) { + novel.gui.autoBookSubjects.setText( + novel.gui.autoBookSubjects.getText().substring(0, + novel.gui.autoBookSubjects.getText().lastIndexOf(","))); + } + // Book Cover + if (novel.metadata.bufferedCover != null) novel.gui.setBufferedCover(novel.metadata.bufferedCover); + dispose(); + } + + private void onCancel() { + dispose(); + } + + private void createUIComponents() { + ignoreDescriptionCheckBox = new JCheckBox(); + ignoreDescriptionCheckBox.setSelected(novel.options.noDescription); + autoEditMetadataDescArea = new JTextArea(novel.metadata.bookDesc.get(0).toString()); + autoEditMetadataDescArea.setLineWrap(true); + autoEditMetadataDescArea.setWrapStyleWord(true); + autoEditMetadataDescArea.setEnabled(!ignoreDescriptionCheckBox.isSelected()); + autoEditMetadataDescScrollPane = new JScrollPane(autoEditMetadataDescArea, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED); + if (novel.metadata.bookSubjects != null && novel.metadata.bookTitle != null && novel.metadata.bookAuthor != null) { + manSetMetadataTitleField = new JTextField(novel.metadata.bookTitle); + manSetMetadataAuthorField = new JTextField(novel.metadata.bookAuthor); + manSetMetadataTags = new JTextField(); + for (String tag : novel.metadata.bookSubjects) { + manSetMetadataTags.setText(manSetMetadataTags.getText() + tag + ","); + } + // Removes last ',' from string + if (!manSetMetadataTags.getText().isEmpty()) { + manSetMetadataTags.setText( + manSetMetadataTags.getText().substring(0, + manSetMetadataTags.getText().lastIndexOf(","))); + } + } + + if (novel.metadata.bookCover == null) { + manMetadataImageButton = new JButton(); + manMetadataImageButton.setIcon(new ImageIcon(getClass().getResource("/files/images/cover_placeholder.png"))); + manMetadataImageButton.setBorder(BorderFactory.createEmptyBorder()); + manMetadataImageButton.setContentAreaFilled(false); + } else { + manMetadataImageButton = new JButton(); + manMetadataImageButton.setIcon(new ImageIcon(new ImageIcon(novel.metadata.bufferedCover).getImage().getScaledInstance(100, 133, Image.SCALE_DEFAULT))); + manMetadataImageButton.setBorder(BorderFactory.createEmptyBorder()); + manMetadataImageButton.setContentAreaFilled(false); + } + } +} diff --git a/src/gui/autoSetBlacklistedTags.form b/src/gui/autoSetBlacklistedTags.form index b08206b..09b5f09 100644 --- a/src/gui/autoSetBlacklistedTags.form +++ b/src/gui/autoSetBlacklistedTags.form @@ -1,146 +1,146 @@ - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/src/gui/autoSetBlacklistedTags.java b/src/gui/autoSetBlacklistedTags.java index b455817..a596298 100644 --- a/src/gui/autoSetBlacklistedTags.java +++ b/src/gui/autoSetBlacklistedTags.java @@ -1,86 +1,86 @@ -package gui; - -import grabber.AutoNovel; - -import javax.swing.*; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.util.Arrays; - -public class autoSetBlacklistedTags extends JDialog { - DefaultListModel blacklistedTagsListModel; - private JPanel contentPane; - private JButton buttonOK; - private JTextField manBlacklistField; - private JButton addButton; - private JButton setBlacklistRemoveButton; - private JList list1; - private JScrollPane scrollPane1; - private AutoNovel currGrab; - - private autoSetBlacklistedTags(AutoNovel currGrab) { - this.currGrab = currGrab; - setContentPane(contentPane); - setModal(true); - setTitle("Edit blacklisted tags"); - ImageIcon favicon = new ImageIcon(getClass().getResource("/images/favicon.png")); - setIconImage(favicon.getImage()); - getRootPane().setDefaultButton(buttonOK); - - buttonOK.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - onOK(); - } - }); - - // call onCancel() when cross is clicked - setDefaultCloseOperation(DISPOSE_ON_CLOSE); - - addButton.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - if (!(manBlacklistField.getText() == null || manBlacklistField.getText().isEmpty())) { - currGrab.currHostSettings.blacklistedTags.addAll(Arrays.asList(manBlacklistField.getText().split(","))); - } - blacklistedTagsListModel.clear(); - for (String tag : currGrab.currHostSettings.blacklistedTags) { - blacklistedTagsListModel.addElement(tag); - } - } - }); - setBlacklistRemoveButton.addActionListener(arg1 -> { - if (!blacklistedTagsListModel.isEmpty()) { - int[] indices = list1.getSelectedIndices(); - for (int i = indices.length - 1; i >= 0; i--) { - blacklistedTagsListModel.removeElementAt(indices[i]); - currGrab.currHostSettings.blacklistedTags.remove(indices[i]); - } - } - }); - } - - static void main(AutoNovel currGrab) { - autoSetBlacklistedTags dialog = new autoSetBlacklistedTags(currGrab); - dialog.pack(); - dialog.setVisible(true); - } - - private void onOK() { - dispose(); - } - - private void createUIComponents() { - if (currGrab.currHostSettings.blacklistedTags != null) { - blacklistedTagsListModel = new DefaultListModel(); - for (String tag : currGrab.currHostSettings.blacklistedTags) { - blacklistedTagsListModel.addElement(tag); - } - list1 = new JList(blacklistedTagsListModel); - } - scrollPane1 = new JScrollPane(list1, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); - - setBlacklistRemoveButton = new JButton(new ImageIcon(getClass().getResource("/images/remove_icon.png"))); - setBlacklistRemoveButton.setBorder(BorderFactory.createEmptyBorder()); - setBlacklistRemoveButton.setContentAreaFilled(false); - } -} +package gui; + +import grabber.Novel; + +import javax.swing.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.util.Arrays; + +public class autoSetBlacklistedTags extends JDialog { + DefaultListModel blacklistedTagsListModel; + private JPanel contentPane; + private JButton buttonOK; + private JTextField manBlacklistField; + private JButton addButton; + private JButton setBlacklistRemoveButton; + private JList list1; + private JScrollPane scrollPane1; + private Novel novel; + + private autoSetBlacklistedTags(Novel currGrab) { + this.novel = currGrab; + setContentPane(contentPane); + setModal(true); + setTitle("Edit blacklisted tags"); + ImageIcon favicon = new ImageIcon(getClass().getResource("/files/images/favicon.png")); + setIconImage(favicon.getImage()); + getRootPane().setDefaultButton(buttonOK); + + buttonOK.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + onOK(); + } + }); + + // call onCancel() when cross is clicked + setDefaultCloseOperation(DISPOSE_ON_CLOSE); + + addButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + if (!(manBlacklistField.getText() == null || manBlacklistField.getText().isEmpty())) { + currGrab.host.blacklistedTags.addAll(Arrays.asList(manBlacklistField.getText().split(","))); + } + blacklistedTagsListModel.clear(); + for (String tag : currGrab.host.blacklistedTags) { + blacklistedTagsListModel.addElement(tag); + } + } + }); + setBlacklistRemoveButton.addActionListener(arg1 -> { + if (!blacklistedTagsListModel.isEmpty()) { + int[] indices = list1.getSelectedIndices(); + for (int i = indices.length - 1; i >= 0; i--) { + blacklistedTagsListModel.removeElementAt(indices[i]); + currGrab.host.blacklistedTags.remove(indices[i]); + } + } + }); + } + + static void main(Novel currGrab) { + autoSetBlacklistedTags dialog = new autoSetBlacklistedTags(currGrab); + dialog.pack(); + dialog.setVisible(true); + } + + private void onOK() { + dispose(); + } + + private void createUIComponents() { + if (novel.host.blacklistedTags != null) { + blacklistedTagsListModel = new DefaultListModel(); + for (String tag : novel.host.blacklistedTags) { + blacklistedTagsListModel.addElement(tag); + } + list1 = new JList(blacklistedTagsListModel); + } + scrollPane1 = new JScrollPane(list1, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); + + setBlacklistRemoveButton = new JButton(new ImageIcon(getClass().getResource("/files/images/remove_icon.png"))); + setBlacklistRemoveButton.setBorder(BorderFactory.createEmptyBorder()); + setBlacklistRemoveButton.setContentAreaFilled(false); + } +} diff --git a/src/gui/getChapterNumber.form b/src/gui/getChapterNumber.form index 75f80f5..12b0821 100644 --- a/src/gui/getChapterNumber.form +++ b/src/gui/getChapterNumber.form @@ -1,97 +1,97 @@ - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/src/gui/getChapterNumber.java b/src/gui/getChapterNumber.java index 1e1530c..5283de9 100644 --- a/src/gui/getChapterNumber.java +++ b/src/gui/getChapterNumber.java @@ -1,155 +1,153 @@ -package gui; - -import grabber.AutoNovel; - -import javax.swing.*; -import java.awt.datatransfer.DataFlavor; -import java.awt.datatransfer.StringSelection; -import java.awt.datatransfer.Transferable; -import java.awt.datatransfer.UnsupportedFlavorException; -import java.awt.event.KeyEvent; -import java.awt.event.WindowAdapter; -import java.awt.event.WindowEvent; -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; - -public class getChapterNumber extends JDialog { - private static getChapterNumber dialog; - private JPanel contentPane; - private JButton buttonOK; - private JButton buttonCancel; - private static DefaultListModel chapterListModel; - private JScrollPane chapterListScrollPane; - private JList chapterList; - private JButton removeChapter; - private JButton addChapter; - - private getChapterNumber(GUI gui, AutoNovel novel) { - ImageIcon favicon = new ImageIcon(getClass().getResource("/images/favicon.png")); - setIconImage(favicon.getImage()); - setContentPane(contentPane); - setModal(true); - getRootPane().setDefaultButton(buttonOK); - - buttonOK.addActionListener(e -> onOK(gui, novel)); - - buttonCancel.addActionListener(e -> onCancel()); - - setDefaultCloseOperation(DO_NOTHING_ON_CLOSE); - addWindowListener(new WindowAdapter() { - public void windowClosing(WindowEvent e) { - onCancel(); - } - }); - - contentPane.registerKeyboardAction(e -> onCancel(), KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT); - removeChapter.addActionListener(arg0 -> { - int selectedIndex = chapterList.getSelectedIndex(); - if (selectedIndex != -1) { - chapterListModel.remove(selectedIndex); - } - }); - addChapter.addActionListener(arg0 -> { - String chapterName = JOptionPane.showInputDialog(this, - "Enter chapter name:", "Add a new chapter", JOptionPane.PLAIN_MESSAGE); - String chapterLink = JOptionPane.showInputDialog(this, - "Enter chapter URL:", "Add a new chapter", JOptionPane.PLAIN_MESSAGE); - if (!(chapterName == null) && !(chapterLink == null)) { - if (!chapterName.isEmpty() && !chapterLink.isEmpty()) { - chapterListModel.addElement(chapterName + " | " + chapterLink); - } - } - }); - } - - - static void main(GUI gui, AutoNovel novel) { - chapterListModel = new DefaultListModel<>(); - for (int i = 0; i < novel.chapterLinks.size(); i++) { - chapterListModel.addElement(novel.chaptersNames.get(i) + " | " + novel.chapterLinks.get(i)); - } - - dialog = new getChapterNumber(gui, novel); - dialog.setTitle("Edit chapter order"); - dialog.pack(); - dialog.setVisible(true); - } - - private void onOK(GUI gui, AutoNovel novel) { - List newNames = new ArrayList<>(); - List newLinks = new ArrayList<>(); - String[] substring; - for (int i = 0; i < chapterListModel.size(); i++) { - substring = chapterListModel.get(i).split(" \\| "); - newNames.add(substring[0]); - newLinks.add(substring[1]); - } - novel.chaptersNames = newNames; - novel.chapterLinks = newLinks; - if (!novel.chapterLinks.isEmpty()) { - gui.autoChapterAmount.setText(String.valueOf(novel.chapterLinks.size())); - } - dialog.dispose(); - } - - private void onCancel() { - dialog.dispose(); - } - - private void createUIComponents() { - addChapter = new JButton("Add"); - removeChapter = new JButton("Remove"); - - chapterList = new JList<>(chapterListModel); - chapterList.setDragEnabled(true); - chapterList.setDropMode(DropMode.INSERT); - chapterList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); - chapterList.setTransferHandler(new TransferHandler() { - private int index; - private boolean beforeIndex = false; //Start with `false` therefore if it is removed from or added to the list it still works - - @Override - public int getSourceActions(JComponent comp) { - return MOVE; - } - - @Override - public Transferable createTransferable(JComponent comp) { - index = chapterList.getSelectedIndex(); - return new StringSelection(chapterList.getSelectedValue()); - } - - @Override - public void exportDone(JComponent comp, Transferable trans, int action) { - if (action == MOVE) { - if (beforeIndex) - chapterListModel.remove(index + 1); - else - chapterListModel.remove(index); - } - } - - @Override - public boolean canImport(TransferHandler.TransferSupport support) { - return support.isDataFlavorSupported(DataFlavor.stringFlavor); - } - - @Override - public boolean importData(TransferHandler.TransferSupport support) { - try { - String s = (String) support.getTransferable().getTransferData(DataFlavor.stringFlavor); - JList.DropLocation dl = (JList.DropLocation) support.getDropLocation(); - chapterListModel.add(dl.getIndex(), s); - beforeIndex = dl.getIndex() < index; - return true; - } catch (UnsupportedFlavorException | IOException e) { - e.printStackTrace(); - } - - return false; - } - }); - chapterListScrollPane = new JScrollPane(chapterList, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); - } +package gui; + +import grabber.Chapter; +import grabber.Novel; + +import javax.swing.*; +import java.awt.datatransfer.DataFlavor; +import java.awt.datatransfer.StringSelection; +import java.awt.datatransfer.Transferable; +import java.awt.datatransfer.UnsupportedFlavorException; +import java.awt.event.KeyEvent; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +public class getChapterNumber extends JDialog { + private static getChapterNumber dialog; + private JPanel contentPane; + private JButton buttonOK; + private JButton buttonCancel; + private static DefaultListModel chapterListModel; + private JScrollPane chapterListScrollPane; + private JList chapterList; + private JButton removeChapter; + private JButton addChapter; + private Novel novel; + + + private getChapterNumber(Novel novel) { + this.novel = novel; + ImageIcon favicon = new ImageIcon(getClass().getResource("/files/images/favicon.png")); + setIconImage(favicon.getImage()); + setContentPane(contentPane); + setModal(true); + getRootPane().setDefaultButton(buttonOK); + + buttonOK.addActionListener(e -> onOK()); + + buttonCancel.addActionListener(e -> onCancel()); + + setDefaultCloseOperation(DO_NOTHING_ON_CLOSE); + addWindowListener(new WindowAdapter() { + public void windowClosing(WindowEvent e) { + onCancel(); + } + }); + + contentPane.registerKeyboardAction(e -> onCancel(), KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT); + removeChapter.addActionListener(arg0 -> { + int selectedIndex = chapterList.getSelectedIndex(); + if (selectedIndex != -1) { + chapterListModel.remove(selectedIndex); + } + }); + addChapter.addActionListener(arg0 -> { + String chapterName = JOptionPane.showInputDialog(this, + "Enter chapter name:", "Add a new chapter", JOptionPane.PLAIN_MESSAGE); + String chapterLink = JOptionPane.showInputDialog(this, + "Enter chapter URL:", "Add a new chapter", JOptionPane.PLAIN_MESSAGE); + if (!(chapterName == null) && !(chapterLink == null)) { + if (!chapterName.isEmpty() && !chapterLink.isEmpty()) { + chapterListModel.addElement(chapterName + " | " + chapterLink); + } + } + }); + } + + + static void main(Novel novel) { + dialog = new getChapterNumber(novel); + dialog.setTitle("Edit chapter order"); + dialog.pack(); + dialog.setVisible(true); + } + + private void onOK() { + List newChapters = new ArrayList<>(); + String[] substring; + for (int i = 0; i < chapterListModel.size(); i++) { + substring = chapterListModel.get(i).split(" \\| "); + newChapters.add(new Chapter(substring[0],substring[1])); + } + novel.gui.autoChapterAmount.setText(String.valueOf(newChapters.size())); + novel.chapters = newChapters; + dialog.dispose(); + } + + private void onCancel() { + dialog.dispose(); + } + + private void createUIComponents() { + addChapter = new JButton("Add"); + removeChapter = new JButton("Remove"); + + chapterListModel = new DefaultListModel<>(); + for (Chapter chapter: novel.chapters) { + chapterListModel.addElement(chapter.toString()); + } + chapterList = new JList<>(chapterListModel); + chapterList.setDragEnabled(true); + chapterList.setDropMode(DropMode.INSERT); + chapterList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); + chapterList.setTransferHandler(new TransferHandler() { + private int index; + private boolean beforeIndex = false; //Start with `false` therefore if it is removed from or added to the list it still works + + @Override + public int getSourceActions(JComponent comp) { + return MOVE; + } + + @Override + public Transferable createTransferable(JComponent comp) { + index = chapterList.getSelectedIndex(); + return new StringSelection(chapterList.getSelectedValue()); + } + + @Override + public void exportDone(JComponent comp, Transferable trans, int action) { + if (action == MOVE) { + if (beforeIndex) + chapterListModel.remove(index + 1); + else + chapterListModel.remove(index); + } + } + + @Override + public boolean canImport(TransferSupport support) { + return support.isDataFlavorSupported(DataFlavor.stringFlavor); + } + + @Override + public boolean importData(TransferSupport support) { + try { + String s = (String) support.getTransferable().getTransferData(DataFlavor.stringFlavor); + JList.DropLocation dl = (JList.DropLocation) support.getDropLocation(); + chapterListModel.add(dl.getIndex(), s); + beforeIndex = dl.getIndex() < index; + return true; + } catch (UnsupportedFlavorException | IOException e) { + e.printStackTrace(); + } + + return false; + } + }); + chapterListScrollPane = new JScrollPane(chapterList, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); + } } \ No newline at end of file diff --git a/src/gui/manSetBlacklistedTags.form b/src/gui/manSetBlacklistedTags.form index 219e586..abec978 100644 --- a/src/gui/manSetBlacklistedTags.form +++ b/src/gui/manSetBlacklistedTags.form @@ -1,146 +1,146 @@ - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/src/gui/manSetBlacklistedTags.java b/src/gui/manSetBlacklistedTags.java index 46ac814..eeb2969 100644 --- a/src/gui/manSetBlacklistedTags.java +++ b/src/gui/manSetBlacklistedTags.java @@ -1,81 +1,81 @@ -package gui; - -import javax.swing.*; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.util.Arrays; - -public class manSetBlacklistedTags extends JDialog { - DefaultListModel blacklistedTagsListModel; - private JPanel contentPane; - private JButton buttonOK; - private JTextField manBlacklistField; - private JButton addButton; - private JButton setBlacklistRemoveButton; - private JList list1; - private JScrollPane scrollPane1; - - private manSetBlacklistedTags() { - setContentPane(contentPane); - setModal(true); - setTitle("Add blacklisted tags"); - ImageIcon favicon = new ImageIcon(getClass().getResource("/images/favicon.png")); - setIconImage(favicon.getImage()); - getRootPane().setDefaultButton(buttonOK); - - buttonOK.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - onOK(); - } - }); - - // call onCancel() when cross is clicked - setDefaultCloseOperation(DISPOSE_ON_CLOSE); - - addButton.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - if (!(manBlacklistField.getText() == null || manBlacklistField.getText().isEmpty())) { - GUI.blacklistedTags.addAll(Arrays.asList(manBlacklistField.getText().split(","))); - } - blacklistedTagsListModel.clear(); - for (String tag : GUI.blacklistedTags) { - blacklistedTagsListModel.addElement(tag); - } - System.out.println(GUI.blacklistedTags.toString()); - } - }); - setBlacklistRemoveButton.addActionListener(arg1 -> { - if (!blacklistedTagsListModel.isEmpty()) { - int[] indices = list1.getSelectedIndices(); - for (int i = indices.length - 1; i >= 0; i--) { - blacklistedTagsListModel.removeElementAt(indices[i]); - GUI.blacklistedTags.remove(indices[i]); - } - } - }); - } - - static void main() { - manSetBlacklistedTags dialog = new manSetBlacklistedTags(); - dialog.pack(); - dialog.setVisible(true); - } - - private void onOK() { - dispose(); - } - - private void createUIComponents() { - blacklistedTagsListModel = new DefaultListModel(); - for (String tag : GUI.blacklistedTags) { - blacklistedTagsListModel.addElement(tag); - } - list1 = new JList(blacklistedTagsListModel); - scrollPane1 = new JScrollPane(list1, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); - - setBlacklistRemoveButton = new JButton(new ImageIcon(getClass().getResource("/images/remove_icon.png"))); - setBlacklistRemoveButton.setBorder(BorderFactory.createEmptyBorder()); - setBlacklistRemoveButton.setContentAreaFilled(false); - } -} +package gui; + +import javax.swing.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.util.Arrays; + +public class manSetBlacklistedTags extends JDialog { + DefaultListModel blacklistedTagsListModel; + private JPanel contentPane; + private JButton buttonOK; + private JTextField manBlacklistField; + private JButton addButton; + private JButton setBlacklistRemoveButton; + private JList list1; + private JScrollPane scrollPane1; + + private manSetBlacklistedTags() { + setContentPane(contentPane); + setModal(true); + setTitle("Add blacklisted tags"); + ImageIcon favicon = new ImageIcon(getClass().getResource("/files/images/favicon.png")); + setIconImage(favicon.getImage()); + getRootPane().setDefaultButton(buttonOK); + + buttonOK.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + onOK(); + } + }); + + // call onCancel() when cross is clicked + setDefaultCloseOperation(DISPOSE_ON_CLOSE); + + addButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + if (!(manBlacklistField.getText() == null || manBlacklistField.getText().isEmpty())) { + GUI.blacklistedTags.addAll(Arrays.asList(manBlacklistField.getText().split(","))); + } + blacklistedTagsListModel.clear(); + for (String tag : GUI.blacklistedTags) { + blacklistedTagsListModel.addElement(tag); + } + System.out.println(GUI.blacklistedTags.toString()); + } + }); + setBlacklistRemoveButton.addActionListener(arg1 -> { + if (!blacklistedTagsListModel.isEmpty()) { + int[] indices = list1.getSelectedIndices(); + for (int i = indices.length - 1; i >= 0; i--) { + blacklistedTagsListModel.removeElementAt(indices[i]); + GUI.blacklistedTags.remove(indices[i]); + } + } + }); + } + + static void main() { + manSetBlacklistedTags dialog = new manSetBlacklistedTags(); + dialog.pack(); + dialog.setVisible(true); + } + + private void onOK() { + dispose(); + } + + private void createUIComponents() { + blacklistedTagsListModel = new DefaultListModel(); + for (String tag : GUI.blacklistedTags) { + blacklistedTagsListModel.addElement(tag); + } + list1 = new JList(blacklistedTagsListModel); + scrollPane1 = new JScrollPane(list1, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); + + setBlacklistRemoveButton = new JButton(new ImageIcon(getClass().getResource("/files/images/remove_icon.png"))); + setBlacklistRemoveButton.setBorder(BorderFactory.createEmptyBorder()); + setBlacklistRemoveButton.setContentAreaFilled(false); + } +} diff --git a/src/gui/manSetMetadata.form b/src/gui/manSetMetadata.form index 8034a34..f5c5579 100644 --- a/src/gui/manSetMetadata.form +++ b/src/gui/manSetMetadata.form @@ -1,186 +1,186 @@ - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/src/gui/manSetMetadata.java b/src/gui/manSetMetadata.java index a86bd20..c9cac08 100644 --- a/src/gui/manSetMetadata.java +++ b/src/gui/manSetMetadata.java @@ -1,145 +1,145 @@ -package gui; - -import javax.swing.*; -import javax.swing.filechooser.FileNameExtensionFilter; -import java.awt.*; -import java.awt.event.*; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -public class manSetMetadata extends JDialog { - public static String[] manMetadataInfo = new String[]{"", "", "", ""}; - public static boolean noDescription = false; - public static List manMetadataTags = new ArrayList<>(); - private JPanel contentPane; - private JButton buttonOK; - private JButton buttonCancel; - private JButton manMetadataImageButton; - private JTextField manSetMetadataTitleField; - private JTextField manSetMetadataAuthorField; - private JTextField manSetMetadataTags; - private JScrollPane autoEditMetadataDescScrollPane; - private JTextArea autoEditMetadataDescArea; - private JCheckBox ignoreDescriptionCheckBox; - - public manSetMetadata() { - setContentPane(contentPane); - setModal(true); - setTitle("Edit EPUB metadata"); - ImageIcon favicon = new ImageIcon(getClass().getResource("/images/favicon.png")); - setIconImage(favicon.getImage()); - getRootPane().setDefaultButton(buttonOK); - - buttonOK.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - onOK(); - } - }); - - buttonCancel.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - onCancel(); - } - }); - - // call onCancel() when cross is clicked - setDefaultCloseOperation(DO_NOTHING_ON_CLOSE); - addWindowListener(new WindowAdapter() { - public void windowClosing(WindowEvent e) { - onCancel(); - } - }); - - // call onCancel() on ESCAPE - contentPane.registerKeyboardAction(new ActionListener() { - public void actionPerformed(ActionEvent e) { - onCancel(); - } - }, KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT); - manMetadataImageButton.addComponentListener(new ComponentAdapter() { - }); - // Add image - manMetadataImageButton.addActionListener(arg01 -> { - JFileChooser chooser = new JFileChooser(); - chooser.setDialogTitle("Open File"); - chooser.setFileSelectionMode(JFileChooser.FILES_ONLY); - chooser.setAcceptAllFileFilterUsed(false); - FileNameExtensionFilter filter = new FileNameExtensionFilter("jpg png gif", "png", "jpg", "gif"); - chooser.setFileFilter(filter); - if (chooser.showOpenDialog(null) == JFileChooser.APPROVE_OPTION) { - manMetadataInfo[2] = chooser.getSelectedFile().toString(); - manMetadataImageButton.setIcon(new ImageIcon(new ImageIcon(manMetadataInfo[2]).getImage().getScaledInstance(100, 133, Image.SCALE_DEFAULT))); - } - }); - ignoreDescriptionCheckBox.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - if (ignoreDescriptionCheckBox.isSelected()) autoEditMetadataDescArea.setEnabled(false); - else { - autoEditMetadataDescArea.setEnabled(true); - } - } - }); - } - - static void main() { - manSetMetadata dialog = new manSetMetadata(); - dialog.pack(); - dialog.setVisible(true); - } - - private void onOK() { - manMetadataInfo[0] = manSetMetadataTitleField.getText(); - manMetadataInfo[1] = manSetMetadataAuthorField.getText(); - manMetadataInfo[3] = autoEditMetadataDescArea.getText(); - manMetadataTags = Arrays.asList(manSetMetadataTags.getText().split(",")); - noDescription = ignoreDescriptionCheckBox.isSelected(); - dispose(); - } - - private void onCancel() { - dispose(); - } - - private void createUIComponents() { - ignoreDescriptionCheckBox = new JCheckBox(); - ignoreDescriptionCheckBox.setSelected(noDescription); - manSetMetadataTitleField = new JTextField(manMetadataInfo[0]); - manSetMetadataAuthorField = new JTextField(manMetadataInfo[1]); - manSetMetadataTags = new JTextField(); - for (String tag : manMetadataTags) { - manSetMetadataTags.setText(manSetMetadataTags.getText() + tag + ","); - } - if (!manSetMetadataTags.getText().isEmpty()) { - manSetMetadataTags.setText( - manSetMetadataTags.getText().substring(0, - manSetMetadataTags.getText().lastIndexOf(","))); - } - if (manMetadataInfo[2].isEmpty()) { - manMetadataImageButton = new JButton(); - manMetadataImageButton.setIcon(new ImageIcon(getClass().getResource("/images/cover_placeholder.png"))); - manMetadataImageButton.setBorder(BorderFactory.createEmptyBorder()); - manMetadataImageButton.setContentAreaFilled(false); - } else { - manMetadataImageButton = new JButton(); - manMetadataImageButton.setIcon(new ImageIcon(new ImageIcon(manMetadataInfo[2]).getImage().getScaledInstance(100, 133, Image.SCALE_DEFAULT))); - manMetadataImageButton.setBorder(BorderFactory.createEmptyBorder()); - manMetadataImageButton.setContentAreaFilled(false); - } - if (manMetadataInfo[3].isEmpty()) { - autoEditMetadataDescArea = new JTextArea(""); - autoEditMetadataDescArea.setLineWrap(true); - autoEditMetadataDescArea.setWrapStyleWord(true); - autoEditMetadataDescArea.setEnabled(!ignoreDescriptionCheckBox.isSelected()); - autoEditMetadataDescScrollPane = new JScrollPane(autoEditMetadataDescArea, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED); - } else { - autoEditMetadataDescArea = new JTextArea(manMetadataInfo[3]); - autoEditMetadataDescArea.setLineWrap(true); - autoEditMetadataDescArea.setWrapStyleWord(true); - autoEditMetadataDescArea.setEnabled(!ignoreDescriptionCheckBox.isSelected()); - autoEditMetadataDescScrollPane = new JScrollPane(autoEditMetadataDescArea, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED); - } - - } -} +package gui; + +import javax.swing.*; +import javax.swing.filechooser.FileNameExtensionFilter; +import java.awt.*; +import java.awt.event.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public class manSetMetadata extends JDialog { + public static String[] manMetadataInfo = new String[]{"", "", "", ""}; + public static boolean noDescription = false; + public static List manMetadataTags = new ArrayList<>(); + private JPanel contentPane; + private JButton buttonOK; + private JButton buttonCancel; + private JButton manMetadataImageButton; + private JTextField manSetMetadataTitleField; + private JTextField manSetMetadataAuthorField; + private JTextField manSetMetadataTags; + private JScrollPane autoEditMetadataDescScrollPane; + private JTextArea autoEditMetadataDescArea; + private JCheckBox ignoreDescriptionCheckBox; + + public manSetMetadata() { + setContentPane(contentPane); + setModal(true); + setTitle("Edit EPUB metadata"); + ImageIcon favicon = new ImageIcon(getClass().getResource("/files/images/favicon.png")); + setIconImage(favicon.getImage()); + getRootPane().setDefaultButton(buttonOK); + + buttonOK.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + onOK(); + } + }); + + buttonCancel.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + onCancel(); + } + }); + + // call onCancel() when cross is clicked + setDefaultCloseOperation(DO_NOTHING_ON_CLOSE); + addWindowListener(new WindowAdapter() { + public void windowClosing(WindowEvent e) { + onCancel(); + } + }); + + // call onCancel() on ESCAPE + contentPane.registerKeyboardAction(new ActionListener() { + public void actionPerformed(ActionEvent e) { + onCancel(); + } + }, KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT); + manMetadataImageButton.addComponentListener(new ComponentAdapter() { + }); + // Add image + manMetadataImageButton.addActionListener(arg01 -> { + JFileChooser chooser = new JFileChooser(); + chooser.setDialogTitle("Open File"); + chooser.setFileSelectionMode(JFileChooser.FILES_ONLY); + chooser.setAcceptAllFileFilterUsed(false); + FileNameExtensionFilter filter = new FileNameExtensionFilter("jpg png gif", "png", "jpg", "gif"); + chooser.setFileFilter(filter); + if (chooser.showOpenDialog(null) == JFileChooser.APPROVE_OPTION) { + manMetadataInfo[2] = chooser.getSelectedFile().toString(); + manMetadataImageButton.setIcon(new ImageIcon(new ImageIcon(manMetadataInfo[2]).getImage().getScaledInstance(100, 133, Image.SCALE_DEFAULT))); + } + }); + ignoreDescriptionCheckBox.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + if (ignoreDescriptionCheckBox.isSelected()) autoEditMetadataDescArea.setEnabled(false); + else { + autoEditMetadataDescArea.setEnabled(true); + } + } + }); + } + + static void main() { + manSetMetadata dialog = new manSetMetadata(); + dialog.pack(); + dialog.setVisible(true); + } + + private void onOK() { + manMetadataInfo[0] = manSetMetadataTitleField.getText(); + manMetadataInfo[1] = manSetMetadataAuthorField.getText(); + manMetadataInfo[3] = autoEditMetadataDescArea.getText(); + manMetadataTags = Arrays.asList(manSetMetadataTags.getText().split(",")); + noDescription = ignoreDescriptionCheckBox.isSelected(); + dispose(); + } + + private void onCancel() { + dispose(); + } + + private void createUIComponents() { + ignoreDescriptionCheckBox = new JCheckBox(); + ignoreDescriptionCheckBox.setSelected(noDescription); + manSetMetadataTitleField = new JTextField(manMetadataInfo[0]); + manSetMetadataAuthorField = new JTextField(manMetadataInfo[1]); + manSetMetadataTags = new JTextField(); + for (String tag : manMetadataTags) { + manSetMetadataTags.setText(manSetMetadataTags.getText() + tag + ","); + } + if (!manSetMetadataTags.getText().isEmpty()) { + manSetMetadataTags.setText( + manSetMetadataTags.getText().substring(0, + manSetMetadataTags.getText().lastIndexOf(","))); + } + if (manMetadataInfo[2].isEmpty()) { + manMetadataImageButton = new JButton(); + manMetadataImageButton.setIcon(new ImageIcon(getClass().getResource("/files/images/cover_placeholder.png"))); + manMetadataImageButton.setBorder(BorderFactory.createEmptyBorder()); + manMetadataImageButton.setContentAreaFilled(false); + } else { + manMetadataImageButton = new JButton(); + manMetadataImageButton.setIcon(new ImageIcon(new ImageIcon(manMetadataInfo[2]).getImage().getScaledInstance(100, 133, Image.SCALE_DEFAULT))); + manMetadataImageButton.setBorder(BorderFactory.createEmptyBorder()); + manMetadataImageButton.setContentAreaFilled(false); + } + if (manMetadataInfo[3].isEmpty()) { + autoEditMetadataDescArea = new JTextArea(""); + autoEditMetadataDescArea.setLineWrap(true); + autoEditMetadataDescArea.setWrapStyleWord(true); + autoEditMetadataDescArea.setEnabled(!ignoreDescriptionCheckBox.isSelected()); + autoEditMetadataDescScrollPane = new JScrollPane(autoEditMetadataDescArea, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED); + } else { + autoEditMetadataDescArea = new JTextArea(manMetadataInfo[3]); + autoEditMetadataDescArea.setLineWrap(true); + autoEditMetadataDescArea.setWrapStyleWord(true); + autoEditMetadataDescArea.setEnabled(!ignoreDescriptionCheckBox.isSelected()); + autoEditMetadataDescScrollPane = new JScrollPane(autoEditMetadataDescArea, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED); + } + + } +} diff --git a/src/updater/updater.java b/src/updater/Updater.java similarity index 85% rename from src/updater/updater.java rename to src/updater/Updater.java index 4ace9b6..aed4f4f 100644 --- a/src/updater/updater.java +++ b/src/updater/Updater.java @@ -1,103 +1,106 @@ -package updater; - -import gui.GUI; -import org.jsoup.Jsoup; -import org.jsoup.nodes.Document; -import org.jsoup.nodes.Element; - -import java.io.*; -import java.net.HttpURLConnection; -import java.net.URL; -import java.util.List; -import java.util.Map; - -public class updater { - - public static void updateJar() { - String oldVersionString = GUI.versionNumber; - String newVersionString = getLatestVersionString(); - if (compareStrings(oldVersionString, newVersionString) == -1) { - String jarLink = "https://github.com/Flameish/Novel-Grabber/releases/download/" + newVersionString + "/Novel-Grabber.jar"; - try { - downloadFileFromGitHub(jarLink); - startNovelGrabber(); - System.exit(0); - } catch (Throwable throwable) { - throwable.printStackTrace(); - } - } - } - - /** - * Gets the latest version from Github releases as a String. - */ - private static String getLatestVersionString() { - try { - Document doc = Jsoup.connect("https://github.com/Flameish/Novel-Grabber/releases").get(); - Element content = doc.select("a[title]").first(); - return content.attr("title"); - } catch (IOException e) { - e.printStackTrace(); - return "-1"; - } - } - - // Compare version strings - public static int compareStrings(String oldVersionString, String newVersionString) { - String[] oldStrings = oldVersionString.split("\\."); - String[] newStrings = newVersionString.split("\\."); - int length = Math.max(oldStrings.length, newStrings.length); - for (int i = 0; i < length; i++) { - int oldVersionNumber = i < oldStrings.length ? Integer.parseInt(oldStrings[i]) : 0; - int newVersionNumber = i < newStrings.length ? Integer.parseInt(newStrings[i]) : 0; - if (oldVersionNumber < newVersionNumber) - return -1; - if (oldVersionNumber > newVersionNumber) - return 1; - } - return 0; - } - - /** - * Starts the new downloaded Novel-Grabber.jar - */ - private static void startNovelGrabber() { - Process proc = null; - try { - proc = Runtime.getRuntime().exec("java -jar Novel-Grabber.jar"); - } catch (IOException e) { - e.printStackTrace(); - } - InputStream in = proc.getInputStream(); - InputStream err = proc.getErrorStream(); - } - - private static boolean isRedirected(Map> header) { - for (String hv : header.get(null)) { - if (hv.contains("301") || hv.contains("302")) return true; - } - return false; - } - - private static void downloadFileFromGitHub(String URL) throws Throwable { - String link = URL; - String fileName = "Novel-Grabber.jar"; - java.net.URL url = new URL(link); - HttpURLConnection http = (HttpURLConnection) url.openConnection(); - Map> header = http.getHeaderFields(); - while (isRedirected(header)) { - link = header.get("Location").get(0); - url = new URL(link); - http = (HttpURLConnection) url.openConnection(); - header = http.getHeaderFields(); - } - InputStream input = http.getInputStream(); - byte[] buffer = new byte[4096]; - int n; - try (OutputStream output = new FileOutputStream(new File(fileName))) { - while ((n = input.read(buffer)) != -1) { - output.write(buffer, 0, n); - } - } - } -} +package updater; + +import gui.GUI; +import org.jsoup.Jsoup; +import org.jsoup.nodes.Document; +import org.jsoup.nodes.Element; + +import java.io.*; +import java.net.HttpURLConnection; +import java.net.URL; +import java.util.List; +import java.util.Map; +import java.util.concurrent.Executors; + +public class Updater { + + public static void updateJar() { + String oldVersionString = GUI.versionNumber; + String newVersionString = getLatestVersionString(); + if (compareStrings(oldVersionString, newVersionString) == -1) { + String jarLink = "https://github.com/Flameish/Novel-Grabber/releases/download/" + newVersionString + "/Novel-Grabber.jar"; + Executors.newSingleThreadExecutor().execute(() -> { + try { + downloadFileFromGitHub(jarLink); + startNovelGrabber(); + System.exit(0); + } catch (Throwable throwable) { + throwable.printStackTrace(); + } + }); + } + } + + /** + * Gets the latest version from Github releases as a String. + */ + private static String getLatestVersionString() { + try { + Document doc = Jsoup.connect("https://github.com/Flameish/Novel-Grabber/releases").get(); + Element content = doc.select("a[title]").first(); + return content.attr("title"); + } catch (IOException e) { + e.printStackTrace(); + return "-1"; + } + } + + // Compare version strings + public static int compareStrings(String oldVersionString, String newVersionString) { + String[] oldStrings = oldVersionString.split("\\."); + String[] newStrings = newVersionString.split("\\."); + int length = Math.max(oldStrings.length, newStrings.length); + for (int i = 0; i < length; i++) { + int oldVersionNumber = i < oldStrings.length ? Integer.parseInt(oldStrings[i]) : 0; + int newVersionNumber = i < newStrings.length ? Integer.parseInt(newStrings[i]) : 0; + if (oldVersionNumber < newVersionNumber) + return -1; + if (oldVersionNumber > newVersionNumber) + return 1; + } + return 0; + } + + /** + * Starts the new downloaded Novel-Grabber.jar + */ + private static void startNovelGrabber() { + Process proc = null; + try { + proc = Runtime.getRuntime().exec("java -jar Novel-Grabber.jar"); + } catch (IOException e) { + e.printStackTrace(); + } + InputStream in = proc.getInputStream(); + InputStream err = proc.getErrorStream(); + } + + private static boolean isRedirected(Map> header) { + for (String hv : header.get(null)) { + if (hv.contains("301") || hv.contains("302")) return true; + } + return false; + } + + private static void downloadFileFromGitHub(String URL) throws Throwable { + String link = URL; + String fileName = "Novel-Grabber.jar"; + java.net.URL url = new URL(link); + HttpURLConnection http = (HttpURLConnection) url.openConnection(); + Map> header = http.getHeaderFields(); + while (isRedirected(header)) { + link = header.get("Location").get(0); + url = new URL(link); + http = (HttpURLConnection) url.openConnection(); + header = http.getHeaderFields(); + } + InputStream input = http.getInputStream(); + byte[] buffer = new byte[256000]; + int n; + try (OutputStream output = new FileOutputStream(new File(fileName))) { + while ((n = input.read(buffer)) != -1) { + output.write(buffer, 0, n); + } + } + } +}