├── src ├── main │ ├── dist │ │ ├── temp │ │ │ └── safetodelete │ │ ├── conf │ │ │ ├── jetty-users.dsc │ │ │ └── settings.conf │ │ ├── MangaLauncher.sh │ │ ├── scripts │ │ │ ├── README.md │ │ │ ├── mangaloader │ │ │ └── dlList │ │ ├── MangaLauncher.bat │ │ ├── log │ │ │ └── readme.txt │ │ ├── readme.html │ │ └── downloader.txt │ └── cs │ │ └── run.cs └── notused │ ├── Run.bat │ ├── readme │ ├── readme_en │ │ ├── README.txt │ │ └── pattern.txt │ ├── readme_de │ │ ├── README.txt │ │ └── pattern.txt │ ├── data.js │ └── readme.html │ ├── Server.bat │ ├── Run │ ├── Gui │ ├── Dialog.bat │ ├── Gui.bat │ └── html-resources │ └── style.css ├── LICENSE ├── settings.gradle ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── MangaLib ├── src │ ├── main │ │ ├── resources │ │ │ ├── jetty │ │ │ │ ├── favicon.ico │ │ │ │ ├── bg │ │ │ │ │ ├── nausicaa.jpg │ │ │ │ │ ├── sankarea.jpg │ │ │ │ │ ├── cits_robot.jpg │ │ │ │ │ ├── mh_kodama.jpg │ │ │ │ │ ├── naruto_ns.jpg │ │ │ │ │ ├── tkr_misaka.jpg │ │ │ │ │ ├── cits_sakura.jpg │ │ │ │ │ ├── naruto_narutos.jpg │ │ │ │ │ ├── onepiece_pirates.jpg │ │ │ │ │ ├── sakurasou_shiina.jpg │ │ │ │ │ └── onepiece_jollyroger.jpg │ │ │ │ ├── css │ │ │ │ │ └── style.css │ │ │ │ ├── l10n │ │ │ │ │ ├── en.json │ │ │ │ │ └── de.json │ │ │ │ └── index.html │ │ │ └── de │ │ │ │ └── herrlock │ │ │ │ ├── javafx │ │ │ │ ├── glumanda.gif │ │ │ │ ├── dialog-error.png │ │ │ │ ├── dialog-confirm.png │ │ │ │ ├── dialog-warning.png │ │ │ │ ├── dialog-information.png │ │ │ │ └── jmetro_light_overrides.css │ │ │ │ └── manga │ │ │ │ ├── index │ │ │ │ ├── DataTables.zip │ │ │ │ ├── index.html │ │ │ │ ├── manga2datatable.xsl │ │ │ │ └── manga2count.xsl │ │ │ │ └── viewpage │ │ │ │ └── style.css │ │ └── java │ │ │ └── de │ │ │ └── herrlock │ │ │ └── manga │ │ │ ├── util │ │ │ ├── management │ │ │ │ ├── PictureMapContainerMXBean.java │ │ │ │ ├── ChapterListContainerMXBean.java │ │ │ │ ├── DownloadQueueContainerMXBean.java │ │ │ │ └── MDownloaderMXBean.java │ │ │ ├── ProgressListener.java │ │ │ ├── Constants.java │ │ │ ├── configuration │ │ │ │ ├── IndexerConfiguration.java │ │ │ │ ├── JDConfiguration.java │ │ │ │ └── DownloadConfiguration.java │ │ │ └── Progressable.java │ │ │ ├── host │ │ │ ├── impl │ │ │ │ ├── FanFox.java │ │ │ │ ├── PureManga.java │ │ │ │ └── MangaTube.java │ │ │ ├── annotations │ │ │ │ ├── ChapterListDetails.java │ │ │ │ └── Details.java │ │ │ ├── exceptions │ │ │ │ ├── NoHosterFoundException.java │ │ │ │ └── HosterInstantiationException.java │ │ │ ├── HosterImpl.java │ │ │ └── Chapter.java │ │ │ ├── downloader │ │ │ ├── impl │ │ │ │ └── PlainDownloader.java │ │ │ ├── pmc │ │ │ │ ├── ImmutableEntryList.java │ │ │ │ └── EntryList.java │ │ │ ├── dqc │ │ │ │ └── Page.java │ │ │ ├── DownloadProcessor.java │ │ │ └── clc │ │ │ │ └── ChapterListContainer.java │ │ │ ├── exceptions │ │ │ ├── ResponseHandlerException.java │ │ │ ├── ResponseFailedException.java │ │ │ ├── MDException.java │ │ │ ├── MDRuntimeException.java │ │ │ └── InitializeException.java │ │ │ ├── index │ │ │ ├── entity │ │ │ │ ├── Index.java │ │ │ │ ├── HosterListEntry.java │ │ │ │ └── HosterList.java │ │ │ └── Indexer.java │ │ │ ├── jd │ │ │ ├── CrawljobEntry.java │ │ │ └── Crawljob.java │ │ │ ├── http │ │ │ ├── client │ │ │ │ ├── ResponseHandler.java │ │ │ │ └── ToDocumentOrRetryHandler.java │ │ │ └── server │ │ │ │ ├── handlers │ │ │ │ └── MangaBaseHandler.java │ │ │ │ └── log │ │ │ │ └── Log4j2Bridge.java │ │ │ └── viewpage │ │ │ └── ViewPageConstants.java │ └── test │ │ ├── resources │ │ ├── META-INF │ │ │ └── services │ │ │ │ └── de.herrlock.manga.host.HosterImpl │ │ └── log4j2-test.xml │ │ └── java │ │ └── de │ │ └── herrlock │ │ └── manga │ │ ├── LoadLog4j2Test.java │ │ ├── jd │ │ ├── TestCrawljobEntry.java │ │ └── TestCrawljob.java │ │ ├── viewpage │ │ ├── TestViewArchive.java │ │ ├── TestViewPageConstants.java │ │ └── TestViewPage.java │ │ ├── DummyServer.java │ │ ├── util │ │ ├── TestChapterPatternRegex.java │ │ ├── StaticMethods.java │ │ ├── TestUtils.java │ │ └── configuration │ │ │ └── TestConfiguration.java │ │ ├── http │ │ └── client │ │ │ └── TestJettyClient.java │ │ ├── host │ │ └── TestHosters.java │ │ └── downloader │ │ ├── dqc │ │ └── TestPage.java │ │ └── pmc │ │ └── TestEntryList.java └── build.gradle ├── README.md ├── .travis.yml ├── MangaCtrl ├── src │ ├── main │ │ ├── resources │ │ │ └── de │ │ │ │ └── herrlock │ │ │ │ └── manga │ │ │ │ ├── ui │ │ │ │ ├── img │ │ │ │ │ ├── asuma.png │ │ │ │ │ ├── server.png │ │ │ │ │ ├── error_f00.gif │ │ │ │ │ ├── transparent.gif │ │ │ │ │ ├── checkmark_0f0.gif │ │ │ │ │ └── checkmark_ff0.gif │ │ │ │ └── main │ │ │ │ │ ├── MDGui.properties │ │ │ │ │ ├── MDGui_de.properties │ │ │ │ │ ├── style.css │ │ │ │ │ └── MDGuiScene.xml │ │ │ │ ├── Ctrl.properties │ │ │ │ ├── Ctrl_de.properties │ │ │ │ └── CtrlScene.xml │ │ └── java │ │ │ └── de │ │ │ └── herrlock │ │ │ └── manga │ │ │ ├── host │ │ │ └── PrintAllHoster.java │ │ │ ├── http │ │ │ └── ServerMain.java │ │ │ ├── downloader │ │ │ ├── SettingsFileDownloader.java │ │ │ └── ConsoleDownloader.java │ │ │ └── viewpage │ │ │ └── ViewGeneratorMain.java │ └── test │ │ └── resources │ │ └── log4j2-test.xml └── build.gradle ├── MangaLauncher ├── src │ ├── main │ │ ├── java │ │ │ └── de │ │ │ │ └── herrlock │ │ │ │ ├── manga │ │ │ │ ├── util │ │ │ │ │ └── management │ │ │ │ │ │ └── CliOptionsMXBean.java │ │ │ │ └── cli │ │ │ │ │ ├── options │ │ │ │ │ ├── EmptyOptions.java │ │ │ │ │ ├── ServerOptions.java │ │ │ │ │ ├── SubOptions.java │ │ │ │ │ ├── LogOptions.java │ │ │ │ │ ├── ViewpageOptions.java │ │ │ │ │ ├── ConsoleOptions.java │ │ │ │ │ └── MainOptions.java │ │ │ │ │ ├── parser │ │ │ │ │ └── IgnoreUnknownParser.java │ │ │ │ │ ├── CliOptions.java │ │ │ │ │ └── OptionParser.java │ │ │ │ └── log4j2 │ │ │ │ ├── util │ │ │ │ └── Log4jConfiguration.java │ │ │ │ └── filter │ │ │ │ └── LevelFilter.java │ │ └── resources │ │ │ └── log4j2.xml │ └── test │ │ ├── java │ │ └── de │ │ │ └── herrlock │ │ │ └── manga │ │ │ ├── RunMain.java │ │ │ └── cli │ │ │ ├── options │ │ │ ├── TestLogOptions.java │ │ │ ├── TestMainOptions.java │ │ │ ├── TestEmptyOptions.java │ │ │ ├── TestServerOptions.java │ │ │ ├── TestConsoleOptions.java │ │ │ ├── TestViewpageOptions.java │ │ │ └── TestSubOptions.java │ │ │ └── parser │ │ │ └── TestIgnoreUnknownParser.java │ │ └── resources │ │ └── log4j2-test.xml └── build.gradle ├── .gitignore ├── TODO.txt ├── licenses └── mit-license └── gradlew.bat /src/main/dist/temp/safetodelete: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/main/dist/conf/jetty-users.dsc: -------------------------------------------------------------------------------- 1 | # user-configuration 2 | admin: admin 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2014-2016 Jan Rau 2 | 3 | http://choosealicense.com/licenses/no-license/ 4 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'Manga' 2 | 3 | include 'MangaLauncher', 'MangaLib', 'MangaCtrl' 4 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/herrlock/Manga/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /MangaLib/src/main/resources/jetty/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/herrlock/Manga/HEAD/MangaLib/src/main/resources/jetty/favicon.ico -------------------------------------------------------------------------------- /MangaLib/src/main/resources/jetty/bg/nausicaa.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/herrlock/Manga/HEAD/MangaLib/src/main/resources/jetty/bg/nausicaa.jpg -------------------------------------------------------------------------------- /MangaLib/src/main/resources/jetty/bg/sankarea.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/herrlock/Manga/HEAD/MangaLib/src/main/resources/jetty/bg/sankarea.jpg -------------------------------------------------------------------------------- /MangaLib/src/main/resources/jetty/bg/cits_robot.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/herrlock/Manga/HEAD/MangaLib/src/main/resources/jetty/bg/cits_robot.jpg -------------------------------------------------------------------------------- /MangaLib/src/main/resources/jetty/bg/mh_kodama.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/herrlock/Manga/HEAD/MangaLib/src/main/resources/jetty/bg/mh_kodama.jpg -------------------------------------------------------------------------------- /MangaLib/src/main/resources/jetty/bg/naruto_ns.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/herrlock/Manga/HEAD/MangaLib/src/main/resources/jetty/bg/naruto_ns.jpg -------------------------------------------------------------------------------- /MangaLib/src/main/resources/jetty/bg/tkr_misaka.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/herrlock/Manga/HEAD/MangaLib/src/main/resources/jetty/bg/tkr_misaka.jpg -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MangaDownloader 2 | 3 | [![Build Status](https://travis-ci.org/herrlock/Manga.svg?branch=master)](https://travis-ci.org/herrlock/Manga) 4 | -------------------------------------------------------------------------------- /MangaLib/src/main/resources/jetty/bg/cits_sakura.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/herrlock/Manga/HEAD/MangaLib/src/main/resources/jetty/bg/cits_sakura.jpg -------------------------------------------------------------------------------- /MangaLib/src/main/resources/jetty/bg/naruto_narutos.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/herrlock/Manga/HEAD/MangaLib/src/main/resources/jetty/bg/naruto_narutos.jpg -------------------------------------------------------------------------------- /MangaLib/src/main/resources/de/herrlock/javafx/glumanda.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/herrlock/Manga/HEAD/MangaLib/src/main/resources/de/herrlock/javafx/glumanda.gif -------------------------------------------------------------------------------- /MangaLib/src/main/resources/jetty/bg/onepiece_pirates.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/herrlock/Manga/HEAD/MangaLib/src/main/resources/jetty/bg/onepiece_pirates.jpg -------------------------------------------------------------------------------- /MangaLib/src/main/resources/jetty/bg/sakurasou_shiina.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/herrlock/Manga/HEAD/MangaLib/src/main/resources/jetty/bg/sakurasou_shiina.jpg -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | 2 | dist: trusty 3 | language: java 4 | 5 | jdk: 6 | - oraclejdk8 7 | - openjdk8 8 | 9 | before_install: 10 | - chmod +x gradlew 11 | 12 | -------------------------------------------------------------------------------- /MangaLib/src/main/resources/jetty/bg/onepiece_jollyroger.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/herrlock/Manga/HEAD/MangaLib/src/main/resources/jetty/bg/onepiece_jollyroger.jpg -------------------------------------------------------------------------------- /MangaCtrl/src/main/resources/de/herrlock/manga/ui/img/asuma.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/herrlock/Manga/HEAD/MangaCtrl/src/main/resources/de/herrlock/manga/ui/img/asuma.png -------------------------------------------------------------------------------- /MangaCtrl/src/main/resources/de/herrlock/manga/ui/img/server.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/herrlock/Manga/HEAD/MangaCtrl/src/main/resources/de/herrlock/manga/ui/img/server.png -------------------------------------------------------------------------------- /MangaLib/src/main/resources/de/herrlock/javafx/dialog-error.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/herrlock/Manga/HEAD/MangaLib/src/main/resources/de/herrlock/javafx/dialog-error.png -------------------------------------------------------------------------------- /MangaLib/src/main/resources/de/herrlock/javafx/dialog-confirm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/herrlock/Manga/HEAD/MangaLib/src/main/resources/de/herrlock/javafx/dialog-confirm.png -------------------------------------------------------------------------------- /MangaLib/src/main/resources/de/herrlock/javafx/dialog-warning.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/herrlock/Manga/HEAD/MangaLib/src/main/resources/de/herrlock/javafx/dialog-warning.png -------------------------------------------------------------------------------- /MangaLib/src/main/resources/de/herrlock/manga/index/DataTables.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/herrlock/Manga/HEAD/MangaLib/src/main/resources/de/herrlock/manga/index/DataTables.zip -------------------------------------------------------------------------------- /MangaCtrl/src/main/resources/de/herrlock/manga/ui/img/error_f00.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/herrlock/Manga/HEAD/MangaCtrl/src/main/resources/de/herrlock/manga/ui/img/error_f00.gif -------------------------------------------------------------------------------- /MangaCtrl/src/main/resources/de/herrlock/manga/ui/img/transparent.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/herrlock/Manga/HEAD/MangaCtrl/src/main/resources/de/herrlock/manga/ui/img/transparent.gif -------------------------------------------------------------------------------- /MangaLib/src/main/resources/de/herrlock/javafx/dialog-information.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/herrlock/Manga/HEAD/MangaLib/src/main/resources/de/herrlock/javafx/dialog-information.png -------------------------------------------------------------------------------- /MangaCtrl/src/main/resources/de/herrlock/manga/ui/img/checkmark_0f0.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/herrlock/Manga/HEAD/MangaCtrl/src/main/resources/de/herrlock/manga/ui/img/checkmark_0f0.gif -------------------------------------------------------------------------------- /MangaCtrl/src/main/resources/de/herrlock/manga/ui/img/checkmark_ff0.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/herrlock/Manga/HEAD/MangaCtrl/src/main/resources/de/herrlock/manga/ui/img/checkmark_ff0.gif -------------------------------------------------------------------------------- /src/notused/Run.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | echo. > log/err.log 3 | echo ------------------------ >> log/err.log 4 | echo %date%, %time% >> log/err.log 5 | start javaw -cp "lib/*" de.herrlock.manga.Ctrl 2>>log/err.log 6 | -------------------------------------------------------------------------------- /src/notused/readme/readme_en/README.txt: -------------------------------------------------------------------------------- 1 | 2 | 1) get the url of the manga (eg. http://mangafox.me/manga/log_horizon/) 3 | 2) run "Run.bat" 4 | 3) fill the fields in the GUI 5 | 4) start the desired task 6 | 7 | -------------------------------------------------------------------------------- /src/notused/Server.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | echo. > log/err.log 3 | echo ------------------------ >> log/err.log 4 | echo %date%, %time% >> log/err.log 5 | start javaw -cp "lib/*" de.herrlock.manga.http.StartWithDesktop 2>>log/err.log 6 | -------------------------------------------------------------------------------- /src/notused/readme/readme_de/README.txt: -------------------------------------------------------------------------------- 1 | 2 | 1) URL des Mangas holen (z.b. http://mangafox.me/manga/log_horizon/) 3 | 2) "Run.bat" ausführen 4 | 3) in der GUI die benötigten Felder ausfüllen 5 | 4) die gewünschte Aufgabe ausführen 6 | 7 | -------------------------------------------------------------------------------- /MangaLib/src/main/java/de/herrlock/manga/util/management/PictureMapContainerMXBean.java: -------------------------------------------------------------------------------- 1 | package de.herrlock.manga.util.management; 2 | 3 | /** 4 | * @author HerrLock 5 | */ 6 | public interface PictureMapContainerMXBean { 7 | // nothing currently 8 | } 9 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /MangaLib/src/main/java/de/herrlock/manga/util/management/ChapterListContainerMXBean.java: -------------------------------------------------------------------------------- 1 | package de.herrlock.manga.util.management; 2 | 3 | /** 4 | * @author HerrLock 5 | */ 6 | public interface ChapterListContainerMXBean { 7 | // nothing currently 8 | } 9 | -------------------------------------------------------------------------------- /MangaLib/src/test/resources/META-INF/services/de.herrlock.manga.host.HosterImpl: -------------------------------------------------------------------------------- 1 | de.herrlock.manga.host.impl.FanFox 2 | de.herrlock.manga.host.impl.MangaFox 3 | de.herrlock.manga.host.impl.MangaPanda 4 | de.herrlock.manga.host.impl.MangaTube 5 | de.herrlock.manga.host.impl.PureManga 6 | -------------------------------------------------------------------------------- /src/notused/Run: -------------------------------------------------------------------------------- 1 | echo > log/err.log 2 | echo ------------------------ >> log/err.log 3 | date >> log/err.log 4 | java -cp "lib/*" de.herrlock.manga.Ctrl 2>&1 | tee -a log/err.log 5 | if [ "${PIPESTATUS[0]}" -ne "0" ] || [ $(grep -cE '.*' log/err.log) -gt 3 ] ; then 6 | echo 7 | cat log/err.log 8 | fi -------------------------------------------------------------------------------- /src/notused/Gui: -------------------------------------------------------------------------------- 1 | echo > log/err.log 2 | echo ------------------------ >> log/err.log 3 | date >> log/err.log 4 | java -cp "lib/*" de.herrlock.manga.ui.main.MDGui 2>&1 | tee -a log/err.log 5 | if [ "${PIPESTATUS[0]}" -ne "0" ] || [ $(grep -cE '.*' log/err.log) -gt 3 ] ; then 6 | echo 7 | cat log/err.log 8 | fi -------------------------------------------------------------------------------- /MangaLauncher/src/main/java/de/herrlock/manga/util/management/CliOptionsMXBean.java: -------------------------------------------------------------------------------- 1 | package de.herrlock.manga.util.management; 2 | 3 | /** 4 | * @author HerrLock 5 | */ 6 | public interface CliOptionsMXBean { 7 | 8 | String getMainOption(); 9 | String[] getSubOptions(); 10 | String[] getLogOptions(); 11 | 12 | } 13 | -------------------------------------------------------------------------------- /src/main/dist/MangaLauncher.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -x 3 | 4 | # check for existence of at least one argument 5 | if [ "$1" ] 6 | then 7 | # start MangaLauncher with the given arguments 8 | java -jar MangaLauncher.jar "$@" 9 | else 10 | # show help since no arguments are given 11 | java -jar MangaLauncher.jar --help 12 | fi 13 | -------------------------------------------------------------------------------- /MangaLib/src/main/java/de/herrlock/manga/util/management/DownloadQueueContainerMXBean.java: -------------------------------------------------------------------------------- 1 | package de.herrlock.manga.util.management; 2 | 3 | /** 4 | * @author HerrLock 5 | */ 6 | public interface DownloadQueueContainerMXBean { 7 | 8 | /** 9 | * @return the size of the current queue 10 | */ 11 | int getSize(); 12 | 13 | } 14 | -------------------------------------------------------------------------------- /src/main/dist/scripts/README.md: -------------------------------------------------------------------------------- 1 | # Example scripts 2 | 3 | This folder contains example-scripts used for different purposes. 4 | Most scripts need to be run from the application's root-folder, so you should copy or move them. 5 | 6 | You might need to use `chmod +a 9 | 10 | 11 | You should be redirected to 12 | 13 | https://github.com/herrlock/Manga/wiki 14 | 15 | -------------------------------------------------------------------------------- /src/notused/Gui.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | echo. > log/err.log 3 | echo ------------------------ >> log/err.log 4 | echo %date%, %time% >> log/err.log 5 | java -cp "lib/*" de.herrlock.manga.ui.main.MDGui 2>>log/err.log 6 | if errorlevel 1 goto showerrlog 7 | 8 | for /f %%C in ('Find /V /C "" ^< log/err.log') do set Count=%%C 9 | if %Count% GTR 3 goto showerrlog 10 | 11 | goto end 12 | 13 | :showerrlog 14 | notepad log/err.log 15 | 16 | :end -------------------------------------------------------------------------------- /MangaLib/src/main/java/de/herrlock/manga/host/impl/FanFox.java: -------------------------------------------------------------------------------- 1 | package de.herrlock.manga.host.impl; 2 | 3 | import com.google.auto.service.AutoService; 4 | 5 | import de.herrlock.manga.host.HosterImpl; 6 | import de.herrlock.manga.host.annotations.Details; 7 | 8 | @AutoService( HosterImpl.class ) 9 | @Details( name = "Fanfox", baseUrl = "http://www.fanfox.net/" ) 10 | public final class FanFox extends MangaFox { 11 | // no own implementation 12 | } 13 | -------------------------------------------------------------------------------- /src/main/cs/run.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics; 2 | 3 | namespace MD 4 | { 5 | class Run 6 | { 7 | static void Main() 8 | { 9 | ProcessStartInfo startInfo = new ProcessStartInfo("cmd.exe", "/C java -jar MangaLauncher.jar"); 10 | startInfo.WindowStyle = ProcessWindowStyle.Hidden; 11 | Process process = new Process(); 12 | process.StartInfo = startInfo; 13 | process.Start(); 14 | } 15 | } 16 | } -------------------------------------------------------------------------------- /src/notused/readme/readme_en/pattern.txt: -------------------------------------------------------------------------------- 1 | a chapter-pattern has the purpose of enabling a partial download. 2 | it can serve with all possible combinations of chapters. 3 | a pattern is a list of chapternumbers or intervals of chapters, joined by semiolon 4 | 5 | bsp: 6 | 7 | 42 8 | chapter 42 9 | 10 | 42;45 11 | chapters 42 and 45 12 | 13 | 42-46 14 | chapters 42 to 46 (42, 43, 44, 45, 46) 15 | 16 | 42-46;50-52 17 | chapters 42 to 46 and 50 to 52 (42, 43, 44, 45, 46, 50, 51, 52) 18 | -------------------------------------------------------------------------------- /MangaLib/src/main/java/de/herrlock/manga/util/management/MDownloaderMXBean.java: -------------------------------------------------------------------------------- 1 | package de.herrlock.manga.util.management; 2 | 3 | /** 4 | * @author HerrLock 5 | */ 6 | public interface MDownloaderMXBean { 7 | 8 | /** 9 | * @return if the MDownloader was started 10 | */ 11 | boolean getStarted(); 12 | 13 | /** 14 | * @return the current progress 15 | */ 16 | int getProgress(); 17 | 18 | /** 19 | * @return the maximum progress 20 | */ 21 | int getMaxProgress(); 22 | } 23 | -------------------------------------------------------------------------------- /src/notused/readme/readme_de/pattern.txt: -------------------------------------------------------------------------------- 1 | ein chapter-pattern dient zum partiellen download eines mangas. 2 | damit können alle möglichen kombinationen der kapitel ausgewählt werden. 3 | ein pattern setzt sich aus einzelnen kapitelzahlen oder intervallen von kapiteln, mit semicolon getrennt, zusammen. 4 | 5 | bsp: 6 | 7 | 42 8 | kapitel 42 9 | 10 | 42;45 11 | kapitel 42 and 45 12 | 13 | 42-46 14 | kapitel 42 bis 46 (42, 43, 44, 45, 46) 15 | 16 | 42-46;50-52 17 | kapitel 42 bis 46 und 50 bis 52 (42, 43, 44, 45, 46, 50, 51, 52) 18 | -------------------------------------------------------------------------------- /src/main/dist/conf/settings.conf: -------------------------------------------------------------------------------- 1 | 2 | # Concurrent downloads 3 | # Default: 10 4 | #thread.count = 10 5 | 6 | # Useragent 7 | # Default: set by http-client 8 | #http.useragent = Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:62.0) Gecko/20100101 Firefox/62.0 9 | 10 | # Trust all certificates on SSL-connections 11 | # Default: false 12 | #https.trustAll = false 13 | 14 | # Proxy 15 | # Default: no proxy 16 | #http.proxy.host = localhost 17 | #http.proxy.port = 8888 18 | #http.proxy.realm = proxyrealm 19 | #http.proxy.user = myuser 20 | #http.proxy.password = secret 21 | -------------------------------------------------------------------------------- /MangaCtrl/src/main/resources/de/herrlock/manga/ui/main/MDGui.properties: -------------------------------------------------------------------------------- 1 | #Generated by ResourceBundle Editor (http://essiembre.github.io/eclipse-rbe/) 2 | 3 | bottom.buttons.download = start download 4 | bottom.buttons.exit = Exit 5 | bottom.buttons.html = create HTML 6 | 7 | center.label.pattern = Chapters 8 | center.label.proxyaddress = Proxy URL 9 | center.label.url = URL 10 | center.textfield.pattern = en_pattern 11 | center.textfield.proxyaddress = en_proxy 12 | center.textfield.url = en_url 13 | 14 | right.title = Availabile Hoster 15 | 16 | top.title = SomeTitle 17 | -------------------------------------------------------------------------------- /MangaCtrl/src/main/resources/de/herrlock/manga/ui/main/MDGui_de.properties: -------------------------------------------------------------------------------- 1 | #Generated by ResourceBundle Editor (http://essiembre.github.io/eclipse-rbe/) 2 | 3 | bottom.buttons.download = Download starten 4 | bottom.buttons.exit = Beenden 5 | bottom.buttons.html = HTML erzeugen 6 | 7 | center.label.pattern = Kapitel 8 | center.label.proxyaddress = Proxyadresse 9 | center.label.url = URL 10 | center.textfield.pattern = de_pattern 11 | center.textfield.proxyaddress = de_proxy 12 | center.textfield.url = de_url 13 | 14 | right.title = Verf\u00FCgbare Hoster 15 | 16 | top.title = SomeTitle_de 17 | -------------------------------------------------------------------------------- /MangaLauncher/src/test/java/de/herrlock/manga/RunMain.java: -------------------------------------------------------------------------------- 1 | package de.herrlock.manga; 2 | 3 | /** 4 | * A class to start Launcher.main without having to alter the IDE's run-configuration
5 | * Please do not commit changes to this file 6 | * 7 | * @author HerrLock 8 | */ 9 | public final class RunMain { 10 | public static void main( final String... args ) { 11 | // enter CLI-arguments as string-array here 12 | String[] arguments = // 13 | { 14 | "--help" 15 | }; 16 | Launcher.main( arguments ); 17 | } 18 | 19 | private RunMain() { 20 | // not used 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /MangaCtrl/build.gradle: -------------------------------------------------------------------------------- 1 | logger.info ' >> MangaCtrl' 2 | 3 | description = 'A library for all special implementations of the classes in MangaLib.' 4 | 5 | dependencies { 6 | implementation project(':MangaLib') 7 | } 8 | 9 | pmdMain.ignoreFailures = true 10 | pmdMain.doLast { 11 | assertPmdErrors pmdMain, [ 12 | [clazz: 'de.herrlock.manga.downloader.SettingsFileDownloader', method: 'run', rule: 'AvoidRethrowingException'], 13 | [clazz: 'de.herrlock.manga.downloader.SettingsFileDownloader', method: 'run', rule: 'AvoidCatchingGenericException'], 14 | [clazz: 'de.herrlock.manga.jd.JDExport', method: 'execute', rule: 'InefficientEmptyStringCheck'] 15 | ] 16 | } 17 | -------------------------------------------------------------------------------- /MangaLib/src/main/java/de/herrlock/manga/util/ProgressListener.java: -------------------------------------------------------------------------------- 1 | package de.herrlock.manga.util; 2 | 3 | /** 4 | * An interface for classes that can be informed when the progress of another object has changed. 5 | * 6 | * @author HerrLock 7 | */ 8 | public interface ProgressListener { 9 | /** 10 | * @param oldProgress 11 | * the previous progress 12 | * @param newProgress 13 | * the new progress 14 | * @param maxProgress 15 | * the highest achievable progress (eg. 100 when percentages are used) 16 | */ 17 | void progress( int oldProgress, int newProgress, int maxProgress ); 18 | } 19 | -------------------------------------------------------------------------------- /MangaLib/src/main/java/de/herrlock/manga/downloader/impl/PlainDownloader.java: -------------------------------------------------------------------------------- 1 | package de.herrlock.manga.downloader.impl; 2 | 3 | import de.herrlock.manga.downloader.MDownloader; 4 | import de.herrlock.manga.util.configuration.DownloadConfiguration; 5 | 6 | /** 7 | * A basic implementation of the {@link MDownloader} that simply calls {@link #downloadAll()}. 8 | * 9 | * @author HerrLock 10 | */ 11 | public class PlainDownloader extends MDownloader { 12 | 13 | public PlainDownloader( final DownloadConfiguration conf ) { 14 | super( conf ); 15 | } 16 | 17 | @Override 18 | protected void run() { 19 | downloadAll(); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /MangaLib/src/main/java/de/herrlock/manga/exceptions/ResponseHandlerException.java: -------------------------------------------------------------------------------- 1 | package de.herrlock.manga.exceptions; 2 | 3 | /** 4 | * @author Jan Rau 5 | * 6 | */ 7 | public class ResponseHandlerException extends RuntimeException { 8 | 9 | private static final long serialVersionUID = 1L; 10 | 11 | public ResponseHandlerException( final String message ) { 12 | super( message ); 13 | } 14 | 15 | public ResponseHandlerException( final Throwable cause ) { 16 | super( cause ); 17 | } 18 | 19 | public ResponseHandlerException( final String message, final Throwable cause ) { 20 | super( message, cause ); 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /MangaLib/src/main/resources/jetty/css/style.css: -------------------------------------------------------------------------------- 1 | /* background-image*/ 2 | html { 3 | background-color: #ccc; 4 | background-repeat: no-repeat; 5 | background-position: top center; 6 | background-size: cover; 7 | height: 100%; 8 | } 9 | 10 | body { 11 | background-color: transparent; 12 | } 13 | 14 | /* transparency for form */ 15 | #bars > .panel, 16 | #content > .panel { 17 | opacity : 0.8; 18 | } 19 | 20 | /* design for links at the bottom */ 21 | #reflinks { 22 | position: fixed; 23 | bottom: 0; 24 | right: 0; 25 | background-color: rgba(222, 222, 222, 0.8); 26 | border-radius: .5em 0 0 0; 27 | padding: .5em; 28 | font-size: small; 29 | text-align: end; 30 | } 31 | -------------------------------------------------------------------------------- /MangaLib/src/main/java/de/herrlock/manga/exceptions/ResponseFailedException.java: -------------------------------------------------------------------------------- 1 | package de.herrlock.manga.exceptions; 2 | 3 | /** 4 | * @author Jan Rau 5 | * 6 | */ 7 | public class ResponseFailedException extends ResponseHandlerException { 8 | 9 | private static final long serialVersionUID = 1L; 10 | 11 | public ResponseFailedException( final String message ) { 12 | super( message ); 13 | } 14 | 15 | public ResponseFailedException( final Throwable cause ) { 16 | super( cause ); 17 | } 18 | 19 | public ResponseFailedException( final String message, final Throwable cause ) { 20 | super( message, cause ); 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /MangaLib/src/main/java/de/herrlock/manga/host/annotations/ChapterListDetails.java: -------------------------------------------------------------------------------- 1 | package de.herrlock.manga.host.annotations; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | /** 9 | * @author HerrLock 10 | */ 11 | @Target( ElementType.TYPE ) 12 | @Retention( RetentionPolicy.RUNTIME ) 13 | public @interface ChapterListDetails { 14 | /** 15 | * indicates if the chapters are listed in descending order 16 | * 17 | * @return true if the list is reversed (highest chapter first). Defaults to false 18 | */ 19 | boolean reversed() default false; 20 | } 21 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | ## eclipse-files 3 | .classpath 4 | .project 5 | .settings/ 6 | bin/ 7 | 8 | ## gradle-files 9 | .gradle/ 10 | build/ 11 | /gradle.properties 12 | 13 | ## files for local testing 14 | # All projects 15 | /additionalHoster.txt 16 | /Manga*/additionalHoster.txt 17 | /download/ 18 | /Manga*/download/ 19 | /downloader.txt 20 | /Manga*/downloader.txt 21 | /folderwatch/ 22 | /Manga*/folderwatch/ 23 | /index/ 24 | /Manga*/index/ 25 | /jetty/ 26 | /Manga*/jetty/ 27 | /log/ 28 | /Manga*/log/ 29 | /temp/ 30 | /Manga*/temp/ 31 | # MangaCtrl 32 | 33 | # MangaLib 34 | MangaLib/src/main/resources/de/herrlock/manga/http/background.jpg 35 | MangaLib/src/main/resources/de/herrlock/manga/http/jquery.js 36 | MangaLib/testFolder -------------------------------------------------------------------------------- /MangaLauncher/src/main/java/de/herrlock/manga/cli/options/EmptyOptions.java: -------------------------------------------------------------------------------- 1 | package de.herrlock.manga.cli.options; 2 | 3 | import org.apache.commons.cli.Option; 4 | import org.apache.commons.cli.Options; 5 | 6 | /** 7 | * A set of {@linkplain Option}s 8 | * 9 | * @author HerrLock 10 | */ 11 | public final class EmptyOptions extends SubOptions { 12 | 13 | private final Options options; 14 | 15 | /** 16 | * Create new Options 17 | */ 18 | public EmptyOptions() { 19 | this.options = new Options(); 20 | } 21 | 22 | /** 23 | * @return the Options from the class 24 | */ 25 | @Override 26 | public Options getOptions() { 27 | return this.options; 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /src/main/dist/downloader.txt: -------------------------------------------------------------------------------- 1 | 2 | # required 3 | # the url from where to download 4 | # is in most times the url of that page, where all chapter are listed 5 | url= 6 | 7 | # optional 8 | # pattern of the chapters to download 9 | # if left empty all chapters are downloaded 10 | # see readme for description 11 | pattern= 12 | 13 | # dependant 14 | # to export the links to JDownloader (to use FolderWatch) add the path to the folderwatch-folder in your local jd-installation 15 | # example: jdfw=C:/Program Files/JDownloader2/folderwatch 16 | # important: use only forward slashes (/) 17 | jdfw= 18 | 19 | # optional 20 | # set this to use a proxy. Basic authentication is supported 21 | # Example: http://user:password@example.com:8000/ 22 | proxy= 23 | -------------------------------------------------------------------------------- /MangaLib/src/test/java/de/herrlock/manga/jd/TestCrawljobEntry.java: -------------------------------------------------------------------------------- 1 | package de.herrlock.manga.jd; 2 | 3 | import org.junit.Assert; 4 | import org.junit.Test; 5 | 6 | /** 7 | * @author HerrLock 8 | */ 9 | public class TestCrawljobEntry { 10 | 11 | /** 12 | * Test the method CrawljobEntry.export() 13 | */ 14 | @Test 15 | public void testExport() { 16 | CrawljobEntry crawljobEntry = new CrawljobEntry( "filename", "url" ); 17 | String export = crawljobEntry.export(); 18 | String[] split = export.split( System.lineSeparator() ); 19 | String[] expected = { 20 | "text=url", "filename=filename.jpg" 21 | }; 22 | Assert.assertArrayEquals( expected, split ); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /MangaLib/src/main/resources/jetty/l10n/en.json: -------------------------------------------------------------------------------- 1 | { 2 | "helloWorld" : "Hello World!", 3 | "formheader" : "Parameters", 4 | "progress" : "Progress", 5 | "lbl" : { 6 | "type" : "Type", 7 | "url" : "URL", 8 | "proxy" : "Proxy-URL", 9 | "pattern" : "Kapitel" 10 | }, 11 | "btn" : { 12 | "start" : "Start download", 13 | "clear" : "Clear fields", 14 | "stop" : "Stop Server" 15 | }, 16 | "closeNotice" : "Server stopped, please close this Tab.", 17 | "ref" : { 18 | "firefox" : { 19 | "pre" : "Tested with\u00a0", 20 | "post" : " " 21 | }, 22 | "bootstrap" : { 23 | "pre" : "Design with\u00a0", 24 | "post" : " " 25 | }, 26 | "konachan" : { 27 | "pre" : "Images from\u00a0", 28 | "post" : " " 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /MangaLauncher/build.gradle: -------------------------------------------------------------------------------- 1 | logger.info ' >> MangaLauncher' 2 | 3 | description = 'A project that contains the main-classes.' 4 | 5 | dependencies { 6 | implementation project(':MangaLib') 7 | implementation project(':MangaCtrl') 8 | 9 | implementation 'commons-cli:commons-cli:1.4' 10 | 11 | implementation 'org.apache.logging.log4j:log4j-core:2.11.2' 12 | } 13 | 14 | tasks.withType(JavaCompile) { 15 | options.compilerArgs << '-proc:none' 16 | } 17 | 18 | jar { 19 | manifest { 20 | attributes 'Main-Class' : 'de.herrlock.manga.Launcher', 21 | 'Class-Path' : configurations.runtimeClasspath 22 | .plus(file('MangaExt.jar')) 23 | .collect{ file -> "lib/${file.name}" } 24 | .sort{ it.toLowerCase() } 25 | .join(' ') 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /MangaLib/src/main/resources/jetty/l10n/de.json: -------------------------------------------------------------------------------- 1 | { 2 | "helloWorld": "Hallo Welt!", 3 | "formheader" : "Parameter", 4 | "progress" : "Fortschritt", 5 | "lbl" : { 6 | "type" : "Typ", 7 | "url" : "URL", 8 | "proxy" : "Proxy-URL", 9 | "pattern" : "Kapitel" 10 | }, 11 | "btn" : { 12 | "start" : "Starte Download", 13 | "clear" : "Felder leeren", 14 | "stop" : "Server stoppen" 15 | }, 16 | "closeNotice" : "Server gestoppt, bitte diesen Tab schließen.", 17 | "ref" : { 18 | "firefox" : { 19 | "pre" : "Getestet mit\u00a0", 20 | "post" : " " 21 | }, 22 | "bootstrap" : { 23 | "pre" : "Design mit\u00a0", 24 | "post" : " " 25 | }, 26 | "konachan" : { 27 | "pre" : "Bilder von\u00a0", 28 | "post" : " " 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /MangaLauncher/src/test/java/de/herrlock/manga/cli/options/TestLogOptions.java: -------------------------------------------------------------------------------- 1 | package de.herrlock.manga.cli.options; 2 | 3 | import org.apache.commons.cli.Options; 4 | import org.junit.Assert; 5 | import org.junit.Test; 6 | 7 | public final class TestLogOptions { 8 | 9 | @Test 10 | public void testOptionCount() { 11 | LogOptions mainOptions = new LogOptions(); 12 | Options options = mainOptions.getOptions(); 13 | Assert.assertEquals( 3, options.getOptions().size() ); 14 | } 15 | 16 | @Test 17 | public void testRequiredOptionCount() { 18 | LogOptions mainOptions = new LogOptions(); 19 | Options options = mainOptions.getOptions(); 20 | Assert.assertEquals( 0, options.getRequiredOptions().size() ); 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /MangaLauncher/src/test/java/de/herrlock/manga/cli/options/TestMainOptions.java: -------------------------------------------------------------------------------- 1 | package de.herrlock.manga.cli.options; 2 | 3 | import org.apache.commons.cli.Options; 4 | import org.junit.Assert; 5 | import org.junit.Test; 6 | 7 | public final class TestMainOptions { 8 | 9 | @Test 10 | public void testOptionCount() { 11 | MainOptions mainOptions = new MainOptions(); 12 | Options options = mainOptions.getOptions(); 13 | Assert.assertEquals( 6, options.getOptions().size() ); 14 | } 15 | 16 | @Test 17 | public void testRequiredOptionCount() { 18 | MainOptions mainOptions = new MainOptions(); 19 | Options options = mainOptions.getOptions(); 20 | Assert.assertEquals( 1, options.getRequiredOptions().size() ); 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /MangaLauncher/src/test/java/de/herrlock/manga/cli/options/TestEmptyOptions.java: -------------------------------------------------------------------------------- 1 | package de.herrlock.manga.cli.options; 2 | 3 | import org.apache.commons.cli.Options; 4 | import org.junit.Assert; 5 | import org.junit.Test; 6 | 7 | public final class TestEmptyOptions { 8 | 9 | @Test 10 | public void testOptionCount() { 11 | EmptyOptions mainOptions = new EmptyOptions(); 12 | Options options = mainOptions.getOptions(); 13 | Assert.assertEquals( 0, options.getOptions().size() ); 14 | } 15 | 16 | @Test 17 | public void testRequiredOptionCount() { 18 | EmptyOptions mainOptions = new EmptyOptions(); 19 | Options options = mainOptions.getOptions(); 20 | Assert.assertEquals( 0, options.getRequiredOptions().size() ); 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /MangaLauncher/src/test/java/de/herrlock/manga/cli/options/TestServerOptions.java: -------------------------------------------------------------------------------- 1 | package de.herrlock.manga.cli.options; 2 | 3 | import org.apache.commons.cli.Options; 4 | import org.junit.Assert; 5 | import org.junit.Test; 6 | 7 | public final class TestServerOptions { 8 | 9 | @Test 10 | public void testOptionCount() { 11 | ServerOptions mainOptions = new ServerOptions(); 12 | Options options = mainOptions.getOptions(); 13 | Assert.assertEquals( 1, options.getOptions().size() ); 14 | } 15 | 16 | @Test 17 | public void testRequiredOptionCount() { 18 | ServerOptions mainOptions = new ServerOptions(); 19 | Options options = mainOptions.getOptions(); 20 | Assert.assertEquals( 0, options.getRequiredOptions().size() ); 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /MangaLauncher/src/test/java/de/herrlock/manga/cli/options/TestConsoleOptions.java: -------------------------------------------------------------------------------- 1 | package de.herrlock.manga.cli.options; 2 | 3 | import org.apache.commons.cli.Options; 4 | import org.junit.Assert; 5 | import org.junit.Test; 6 | 7 | public final class TestConsoleOptions { 8 | 9 | @Test 10 | public void testOptionCount() { 11 | ConsoleOptions mainOptions = new ConsoleOptions(); 12 | Options options = mainOptions.getOptions(); 13 | Assert.assertEquals( 6, options.getOptions().size() ); 14 | } 15 | 16 | @Test 17 | public void testRequiredOptionCount() { 18 | ConsoleOptions mainOptions = new ConsoleOptions(); 19 | Options options = mainOptions.getOptions(); 20 | Assert.assertEquals( 0, options.getRequiredOptions().size() ); 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /src/notused/readme/data.js: -------------------------------------------------------------------------------- 1 | var properties = (function() { 2 | var data = { 3 | step1 : { 4 | de : "URL des Mangas holen (z.b. http://mangafox.me/manga/log_horizon/)", 5 | en : "get the url of the manga (eg. http://mangafox.me/manga/log_horizon/)" 6 | }, 7 | step2 : { 8 | de : "val2_de", 9 | en : "val2_en" 10 | }, 11 | step3 : { 12 | en : "val3_en" 13 | } 14 | }; 15 | console.dir([data]); 16 | var locale = (location.search.substring(1).split("&").find(s => s.match(/^lang=..$/)) || "").substring(5) || navigator.language.substring(0, 2); 17 | console.warn("locale", locale); 18 | var result = {}; 19 | Object.keys(data).forEach(function(value) { 20 | var obj = data[value]; 21 | result[value] = (obj[locale] || obj.en); 22 | }); 23 | console.dir(result); 24 | return result; 25 | }()); 26 | -------------------------------------------------------------------------------- /MangaLauncher/src/test/java/de/herrlock/manga/cli/options/TestViewpageOptions.java: -------------------------------------------------------------------------------- 1 | package de.herrlock.manga.cli.options; 2 | 3 | import org.apache.commons.cli.Options; 4 | import org.junit.Assert; 5 | import org.junit.Test; 6 | 7 | public final class TestViewpageOptions { 8 | 9 | @Test 10 | public void testOptionCount() { 11 | ViewpageOptions mainOptions = new ViewpageOptions(); 12 | Options options = mainOptions.getOptions(); 13 | Assert.assertEquals( 5, options.getOptions().size() ); 14 | } 15 | 16 | @Test 17 | public void testRequiredOptionCount() { 18 | ViewpageOptions mainOptions = new ViewpageOptions(); 19 | Options options = mainOptions.getOptions(); 20 | Assert.assertEquals( 1, options.getRequiredOptions().size() ); 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /MangaLib/src/main/java/de/herrlock/manga/host/exceptions/NoHosterFoundException.java: -------------------------------------------------------------------------------- 1 | package de.herrlock.manga.host.exceptions; 2 | 3 | import de.herrlock.manga.exceptions.MDException; 4 | 5 | /** 6 | * @author HerrLock 7 | */ 8 | public class NoHosterFoundException extends MDException { 9 | 10 | private static final long serialVersionUID = 1L; 11 | 12 | @Deprecated 13 | public NoHosterFoundException() { 14 | super(); 15 | } 16 | 17 | public NoHosterFoundException( final String message ) { 18 | super( message ); 19 | } 20 | 21 | public NoHosterFoundException( final Throwable cause ) { 22 | super( cause ); 23 | } 24 | 25 | public NoHosterFoundException( final String message, final Throwable cause ) { 26 | super( message, cause ); 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /src/main/dist/scripts/mangaloader: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | ##################################################### 3 | # This script can be placed on the PATH to # 4 | # execute the mangadownloader from the cli easily # 5 | ##################################################### 6 | 7 | # immediately exit on error 8 | set -e 9 | 10 | # the folder containing the application 11 | folder= 12 | # the name of the script to launch 13 | script="MangaLauncher.sh" 14 | 15 | # check if folder exists 16 | if [[ -d "$folder" ]]; then 17 | # cd into the folder 18 | cd $folder 19 | # check if the script exists and is executable 20 | if [[ -x "$script" ]]; then 21 | # launch script 22 | ./"$script" "$@" 23 | else 24 | echo "\"$folder/$script\" is not executable" 25 | fi 26 | else 27 | echo "Cannot find folder \"$folder\"" 28 | fi 29 | -------------------------------------------------------------------------------- /MangaLib/src/main/java/de/herrlock/manga/host/annotations/Details.java: -------------------------------------------------------------------------------- 1 | package de.herrlock.manga.host.annotations; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | import de.herrlock.manga.host.Hoster; 9 | 10 | /** 11 | * provides information about {@link Hoster}s 12 | * 13 | * @author HerrLock 14 | */ 15 | @Target( ElementType.TYPE ) 16 | @Retention( RetentionPolicy.RUNTIME ) 17 | public @interface Details { 18 | /** 19 | * the Hoster's name 20 | * 21 | * @return the hoster's name 22 | */ 23 | String name(); 24 | /** 25 | * the hoster's url, only the host-part 26 | * 27 | * @return the hoster's url 28 | */ 29 | String baseUrl(); 30 | } 31 | -------------------------------------------------------------------------------- /src/main/dist/scripts/dlList: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | ################################################################## 3 | # This script downloads all mangas listed in the file dlListData # 4 | ################################################################## 5 | 6 | # exit if the data-file does not exist 7 | if [ ! -e dlListData ] 8 | then 9 | echo dlListData does not exist - exiting 10 | exit 3 11 | fi 12 | 13 | # verbose 14 | set -x 15 | 16 | # read list 17 | list=$(cat dlListData) 18 | 19 | # print list, useful to assure the arguments are read correctly 20 | echo list: $list | tee log/shlog.txt 21 | 22 | # execute the downloader for every entry in the list 23 | for url in $list 24 | do 25 | echo | tee -a log/shlog.txt 26 | echo $url | tee -a log/shlog.txt 27 | java -jar MangaLauncher.jar \ 28 | --log debug \ 29 | --console \ 30 | --url $url \ 31 | | tee -a log/shlog.txt 32 | done 33 | -------------------------------------------------------------------------------- /MangaLib/src/main/java/de/herrlock/manga/host/exceptions/HosterInstantiationException.java: -------------------------------------------------------------------------------- 1 | package de.herrlock.manga.host.exceptions; 2 | 3 | import de.herrlock.manga.exceptions.MDException; 4 | 5 | /** 6 | * An Exception indicating, that a Hoster could not be created. 7 | * 8 | * @author HerrLock 9 | */ 10 | public final class HosterInstantiationException extends MDException { 11 | 12 | private static final long serialVersionUID = 1L; 13 | 14 | @Deprecated 15 | public HosterInstantiationException() { 16 | super(); 17 | } 18 | 19 | public HosterInstantiationException( final String message ) { 20 | super( message ); 21 | } 22 | 23 | public HosterInstantiationException( final Throwable cause ) { 24 | super( cause ); 25 | } 26 | 27 | public HosterInstantiationException( final String message, final Throwable cause ) { 28 | super( message, cause ); 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /MangaCtrl/src/main/resources/de/herrlock/manga/Ctrl.properties: -------------------------------------------------------------------------------- 1 | #Generated by ResourceBundle Editor (http://essiembre.github.io/eclipse-rbe/) 2 | 3 | button.text.addToJD = Add To JDownloader 4 | button.text.createHTML = Create reader 5 | button.text.showHosts = Show hoster 6 | button.text.startDDL = Download with Dialog 7 | button.text.startPDL = Download 8 | button.text.startServer = start Server 9 | button.tooltip.addToJD = Creates a .crawljob-file that can be imported into the JDownloader. 10 | button.tooltip.createHTML = Create HTML Pages for existing Chapters 11 | button.tooltip.showHosts = Show all availabile Hosts 12 | button.tooltip.startDDL = Start download after reporting the number of pictures. 13 | button.tooltip.startPDL = Start download without confirmation 14 | button.tooltip.startServer = starts a HTTP-server at port 1905 15 | 16 | scene.title = Please select action 17 | 18 | text.running = Running... please wait 19 | -------------------------------------------------------------------------------- /MangaLauncher/src/main/java/de/herrlock/manga/cli/options/ServerOptions.java: -------------------------------------------------------------------------------- 1 | package de.herrlock.manga.cli.options; 2 | 3 | import org.apache.commons.cli.Option; 4 | import org.apache.commons.cli.Options; 5 | 6 | /** 7 | * A set of {@linkplain Option}s 8 | * 9 | * @author HerrLock 10 | */ 11 | public final class ServerOptions extends SubOptions { 12 | 13 | private final Option launchBrowserOption = Option.builder() // 14 | .longOpt( "browser" ) // 15 | .desc( "Start the browser after starting the server" ) // 16 | .build(); 17 | 18 | private final Options options; 19 | 20 | /** 21 | * Create new Options 22 | */ 23 | public ServerOptions() { 24 | this.options = new Options().addOption( this.launchBrowserOption ); 25 | } 26 | 27 | /** 28 | * @return the Options from the class 29 | */ 30 | @Override 31 | public Options getOptions() { 32 | return this.options; 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /MangaLib/src/main/java/de/herrlock/manga/index/entity/Index.java: -------------------------------------------------------------------------------- 1 | package de.herrlock.manga.index.entity; 2 | 3 | import java.text.MessageFormat; 4 | import java.util.Collection; 5 | 6 | import javax.xml.bind.annotation.XmlAccessType; 7 | import javax.xml.bind.annotation.XmlAccessorType; 8 | import javax.xml.bind.annotation.XmlElement; 9 | import javax.xml.bind.annotation.XmlRootElement; 10 | 11 | /** 12 | * @author HerrLock 13 | */ 14 | @XmlRootElement 15 | @XmlAccessorType( XmlAccessType.NONE ) 16 | public final class Index { 17 | 18 | @XmlElement( name = "hoster" ) 19 | private Collection hosters; 20 | 21 | public Collection getHosters() { 22 | return this.hosters; 23 | } 24 | 25 | public void setHosters( final Collection hosters ) { 26 | this.hosters = hosters; 27 | } 28 | 29 | @Override 30 | public String toString() { 31 | return MessageFormat.format( "Index ({0})", this.hosters ); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/notused/readme/readme.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 26 | 37 | 38 | 39 |
40 |

Readme

41 |
    42 |
43 | 44 | -------------------------------------------------------------------------------- /TODO.txt: -------------------------------------------------------------------------------- 1 | 2 | 1.5: 3 | - add java-beans for easier tracking of running downloads 4 | - create DialogDownloader (swing/fx/?) 5 | - queue downloads => no parallel dls 6 | - json-configuration for console 7 | 8 | 1.6: 9 | - fx-gui 10 | - swing-gui 11 | 12 | 1.x: 13 | - use java.util.concurrent.* package for more complex execution with progress-callbacks 14 | - improve average filesize 15 | - make jd-export faster 16 | 17 | later: 18 | - take a look at launch4j 19 | - https://commons.apache.org/proper/commons-launcher/ 20 | 21 | --- 22 | 23 | 1.4: 24 | - build the web-based gui 25 | - get some images with a "valid" copyright 26 | - easy way to start and stop the server 27 | - release it finally 28 | 29 | 1.3: 30 | - fill manga.html after download 31 | - update manga.html with better js 32 | - optional: create html-file from downloaded pages 33 | 34 | 1.2: 35 | - add documentation (readme) 36 | - add javadoc 37 | 38 | 1.1: 39 | - add multithreading 40 | 41 | 1.0: 42 | - create working version from previous MD 43 | -------------------------------------------------------------------------------- /MangaCtrl/src/main/resources/de/herrlock/manga/Ctrl_de.properties: -------------------------------------------------------------------------------- 1 | #Generated by ResourceBundle Editor (http://essiembre.github.io/eclipse-rbe/) 2 | 3 | button.text.addToJD = Zu JDownloader 4 | button.text.createHTML = Reader erzeugen 5 | button.text.showHosts = Hoster anzeigen 6 | button.text.startDDL = Mit Dialog Herunterladen 7 | button.text.startPDL = Herunterladen 8 | button.text.startServer = Server starten 9 | button.tooltip.addToJD = Erzeugt eine .crawljob-Datei, die vom JDownloader gelesen werden kann. 10 | button.tooltip.createHTML = HTML-Seiten f\u00FCr bereits existierende Kapitel erzeugen 11 | button.tooltip.showHosts = Alle verf\u00FCgbaren Hoster anzeigen 12 | button.tooltip.startDDL = Den Download starten und die Anzahl der Bilder melden. 13 | button.tooltip.startPDL = Den Download starten und ohne Nachfrage Herunterladen 14 | button.tooltip.startServer = Startet einen HTTP-Server am Port 1905 15 | 16 | scene.title = Bitte Aktion w\u00E4hlen 17 | 18 | text.running = Ausf\u00FChrung... Bitte warten 19 | -------------------------------------------------------------------------------- /MangaCtrl/src/main/resources/de/herrlock/manga/ui/main/style.css: -------------------------------------------------------------------------------- 1 | 2 | .text { 3 | -fx-font-family: "Segoe UI", Helvetica, Arial, sans-serif; 4 | } 5 | 6 | .gridpane { 7 | -fx-hgap: 16; 8 | -fx-vgap: 8; 9 | } 10 | 11 | .text-field .isEmpty { 12 | -fx-text-box-border: red; 13 | -fx-focus-color: red; 14 | } 15 | 16 | .padding8 { 17 | -fx-padding: 8px; 18 | } 19 | 20 | .padding16 { 21 | -fx-padding: 16px; 22 | } 23 | 24 | .bp-top, .bp-right, .bp-center, .bp-bottom { 25 | -fx-background-color: #f0f0f0; 26 | } 27 | 28 | /* Copied from JMetro light-theme, was commented out in the jar*/ 29 | .tooltip { 30 | -fx-background-color: white; 31 | -fx-background-insets: 0; 32 | -fx-background-radius: 0 0 0 0; 33 | -fx-padding: 0.333333em 0.666667em 0.333333em 0.666667em; 34 | -fx-effect: dropshadow( one-pass-box , #808080 , 5, 0.0 , 0 , 0 ); 35 | -fx-font-family: "Segoe UI Semilight", "Segoe UI Light", "Segoe UI", Helvetica, Arial, sans-serif; 36 | -fx-text-fill: #949494; 37 | -fx-cursor: none !important; 38 | } 39 | 40 | .page-corner { 41 | -fx-padding: 4.5 4.5 4.5 4.5; 42 | -fx-background-color: transparent; 43 | -fx-shape: null; 44 | -fx-effect: null; 45 | } 46 | 47 | -------------------------------------------------------------------------------- /MangaLib/src/main/java/de/herrlock/manga/jd/CrawljobEntry.java: -------------------------------------------------------------------------------- 1 | package de.herrlock.manga.jd; 2 | 3 | import java.net.URL; 4 | import java.text.MessageFormat; 5 | 6 | /** 7 | * A class representing a single download (url => filename) 8 | * 9 | * @author HerrLock 10 | */ 11 | final class CrawljobEntry { 12 | private final String filename; 13 | private final String url; 14 | 15 | /** 16 | * creates a CrawljobEntry of the resource with the given filename at the given URL 17 | * 18 | * @param filename 19 | * the name to save the downloaded image with 20 | * @param url 21 | * the {@link URL} to download the image from 22 | */ 23 | public CrawljobEntry( final String filename, final String url ) { 24 | this.filename = filename; 25 | this.url = url; 26 | } 27 | 28 | /** 29 | * creates a String that represents the current CrawljobEntry 30 | * 31 | * @return string for the current CrawljobEntry-object 32 | */ 33 | public String export() { 34 | return MessageFormat.format( "text={0}{1}filename={2}.jpg", this.url, System.lineSeparator(), this.filename ); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /MangaLauncher/src/main/java/de/herrlock/manga/cli/options/SubOptions.java: -------------------------------------------------------------------------------- 1 | package de.herrlock.manga.cli.options; 2 | 3 | import org.apache.commons.cli.Option; 4 | import org.apache.commons.cli.Options; 5 | 6 | /** 7 | * A set of {@linkplain Option}s 8 | * 9 | * @author HerrLock 10 | */ 11 | public abstract class SubOptions { 12 | 13 | /** 14 | * @return the Options from the class 15 | */ 16 | public abstract Options getOptions(); 17 | 18 | public static SubOptions getSubOptions( final String name ) { 19 | if ( name == null ) { 20 | return new EmptyOptions(); 21 | } else if ( "console".equalsIgnoreCase( name ) ) { 22 | return new ConsoleOptions(); 23 | } else if ( "viewpage".equalsIgnoreCase( name ) ) { 24 | return new ViewpageOptions(); 25 | } else if ( "server".equalsIgnoreCase( name ) ) { 26 | return new ServerOptions(); 27 | } else if ( "help".equalsIgnoreCase( name ) ) { 28 | return new EmptyOptions(); 29 | } else if ( "version".equalsIgnoreCase( name ) ) { 30 | return new EmptyOptions(); 31 | } else { 32 | return new EmptyOptions(); 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /MangaLib/src/main/resources/de/herrlock/manga/index/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Mangaindex 4 | 5 | 9 | 10 | 11 | 35 | 36 | 37 |
38 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /MangaCtrl/src/test/resources/log4j2-test.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | %d{HH:mm:ss.SSS} 5 | %-5level 6 | %logger{1.}.%M 7 | ${_tim} [%t] ${_lev} ${_log} - %m%n 8 | ${_lev} ${_log} - %m%n 9 | >>> ${_log} - %m%n 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /MangaLib/src/main/java/de/herrlock/manga/host/HosterImpl.java: -------------------------------------------------------------------------------- 1 | package de.herrlock.manga.host; 2 | 3 | import java.io.IOException; 4 | import java.util.Arrays; 5 | import java.util.Collection; 6 | 7 | import de.herrlock.manga.host.annotations.Details; 8 | import de.herrlock.manga.index.entity.HosterListEntry; 9 | import de.herrlock.manga.util.configuration.DownloadConfiguration; 10 | import de.herrlock.manga.util.configuration.IndexerConfiguration; 11 | 12 | /** 13 | * @author HerrLock 14 | */ 15 | public abstract class HosterImpl { 16 | public abstract ChapterList getChapterList( DownloadConfiguration conf ) throws IOException; 17 | 18 | public Collection getAvailabile( @SuppressWarnings( "unused" ) final IndexerConfiguration conf ) { 19 | HosterListEntry hosterListEntry = new HosterListEntry(); 20 | hosterListEntry.setName( "<no entries>" ); 21 | hosterListEntry.setUrl( getDetails().baseUrl() ); 22 | return Arrays.asList( hosterListEntry ); 23 | } 24 | 25 | public Details getDetails() { 26 | Details details = getClass().getAnnotation( Details.class ); 27 | if ( details == null ) { 28 | throw new IllegalStateException( "No annotation @Details given. Consider adding it or override this method." ); 29 | } 30 | return details; 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /MangaLib/src/test/resources/log4j2-test.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | %d{HH:mm:ss.SSS} 5 | %-5level 6 | %logger{1.}.%M 7 | ${_tim} [%t] ${_lev} ${_log} - %m%n 8 | ${_lev} ${_log} - %m%n 9 | >>> ${_log} - %m%n 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /MangaLauncher/src/test/resources/log4j2-test.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | %d{HH:mm:ss.SSS} 5 | %-5level 6 | %logger{1.}.%M 7 | ${_tim} [%t] ${_lev} ${_log} - %m%n 8 | ${_lev} ${_log} - %m%n 9 | >>> ${_log} - %m%n 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /MangaLib/src/test/java/de/herrlock/manga/viewpage/TestViewArchive.java: -------------------------------------------------------------------------------- 1 | package de.herrlock.manga.viewpage; 2 | 3 | import org.junit.Assert; 4 | import org.junit.Test; 5 | 6 | public class TestViewArchive { 7 | 8 | @Test 9 | public void testPad1() { 10 | String string = ViewArchive.padWith0( "", 10 ); 11 | Assert.assertEquals( "0000000000", string ); 12 | } 13 | 14 | @Test 15 | public void testPad2() { 16 | String string = ViewArchive.padWith0( "Hello World", 10 ); 17 | Assert.assertEquals( "Hello World", string ); 18 | } 19 | 20 | @Test 21 | public void testFormatArchiveFilename1() { 22 | String filename = ViewArchive.toArchiveEntryFilename( null ); 23 | Assert.assertEquals( "", filename ); 24 | } 25 | 26 | @Test 27 | public void testFormatArchiveFilename2() { 28 | String filename = ViewArchive.toArchiveEntryFilename( "1.jpg" ); 29 | Assert.assertEquals( "001.jpg", filename ); 30 | } 31 | 32 | @Test 33 | public void testFormatArchiveFilename3() { 34 | String filename = ViewArchive.toArchiveEntryFilename( "03.jpg" ); 35 | Assert.assertEquals( "003.jpg", filename ); 36 | } 37 | 38 | @Test 39 | public void testFormatArchiveFilename4() { 40 | String filename = ViewArchive.toArchiveEntryFilename( "100.jpg" ); 41 | Assert.assertEquals( "100.jpg", filename ); 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /MangaLib/src/main/java/de/herrlock/manga/http/client/ResponseHandler.java: -------------------------------------------------------------------------------- 1 | package de.herrlock.manga.http.client; 2 | 3 | import java.io.IOException; 4 | import java.util.function.Function; 5 | 6 | import org.eclipse.jetty.client.api.ContentResponse; 7 | 8 | import de.herrlock.manga.exceptions.ResponseHandlerException; 9 | 10 | public abstract class ResponseHandler implements Function { 11 | 12 | protected abstract T handle( ContentResponse input ) throws IOException; 13 | 14 | @Override 15 | public final T apply( final ContentResponse input ) throws ResponseHandlerException { 16 | try { 17 | return handle( input ); 18 | } catch ( IOException ex ) { 19 | throw new ResponseHandlerException( ex ); 20 | } 21 | } 22 | 23 | public static ResponseHandler fromFunction( final Function delegate ) { 24 | return new DelegateResponseHandler<>( delegate ); 25 | } 26 | 27 | private static class DelegateResponseHandler extends ResponseHandler { 28 | private final Function delegate; 29 | 30 | public DelegateResponseHandler( final Function delegate ) { 31 | this.delegate = delegate; 32 | } 33 | 34 | @Override 35 | protected T handle( final ContentResponse input ) throws IOException { 36 | return delegate.apply( input ); 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /MangaLib/src/main/java/de/herrlock/manga/host/Chapter.java: -------------------------------------------------------------------------------- 1 | package de.herrlock.manga.host; 2 | 3 | import java.net.URL; 4 | import java.text.MessageFormat; 5 | 6 | /** 7 | * a class to store number and url of a single Chapter 8 | * 9 | * @author HerrLock 10 | */ 11 | public final class Chapter { 12 | private final String number; 13 | private final URL chapterUrl; 14 | 15 | /** 16 | * @param number 17 | * tha Chapter's number. can contain alphanumerical characters 18 | * @param url 19 | * the url of a page (generally the first) of the chapter 20 | */ 21 | Chapter( final String number, final URL url ) { 22 | this.number = number; 23 | this.chapterUrl = url; 24 | } 25 | 26 | /** 27 | * Getter for this Chapter's number 28 | * 29 | * @return the number of this Chapter. Might be non-numerical, so it is a String. 30 | */ 31 | public String getNumber() { 32 | return this.number; 33 | } 34 | 35 | /** 36 | * Getter for this Chapter's url 37 | * 38 | * @return the {@link URL} of this Chapter. Most times this is the URL of the first page, but the other pages should work as 39 | * well. 40 | */ 41 | public URL getChapterUrl() { 42 | return this.chapterUrl; 43 | } 44 | 45 | @Override 46 | public String toString() { 47 | return MessageFormat.format( "{0}: {1}", this.number, this.chapterUrl ); 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /MangaLib/src/main/java/de/herrlock/manga/downloader/pmc/ImmutableEntryList.java: -------------------------------------------------------------------------------- 1 | package de.herrlock.manga.downloader.pmc; 2 | 3 | import java.util.AbstractMap.SimpleImmutableEntry; 4 | import java.util.Collection; 5 | import java.util.Comparator; 6 | 7 | /** 8 | * @author HerrLock 9 | * 10 | * @param 11 | * the type of the key 12 | * @param 13 | * the type of the value 14 | */ 15 | public final class ImmutableEntryList extends EntryList { 16 | 17 | /** 18 | * @param c 19 | * the collection to copy the values from 20 | */ 21 | public ImmutableEntryList( final Collection> c ) { 22 | super( c ); 23 | } 24 | 25 | /** 26 | * @param e 27 | * the EntryList to copy the values from 28 | */ 29 | public ImmutableEntryList( final EntryList e ) { 30 | super( e ); 31 | } 32 | 33 | /** 34 | * {@link UnsupportedOperationException} 35 | */ 36 | @Override 37 | public void addEntry( final K key, final V value ) { 38 | throw new UnsupportedOperationException( "adding an entry to an immutable list is prohibited" ); 39 | } 40 | 41 | /** 42 | * {@link UnsupportedOperationException} 43 | */ 44 | @Override 45 | public void sort( final Comparator> c ) { 46 | throw new UnsupportedOperationException( "sorting an immutable list is prohibited" ); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /MangaLib/src/main/java/de/herrlock/manga/util/Constants.java: -------------------------------------------------------------------------------- 1 | package de.herrlock.manga.util; 2 | 3 | import java.util.Comparator; 4 | 5 | /** 6 | * A central class for miscellanous constant values 7 | * 8 | * @author HerrLock 9 | */ 10 | public final class Constants { 11 | /** 12 | * the position of the configuration-file to runtime 13 | */ 14 | public static final String SETTINGS_FILE = "./downloader.txt"; 15 | /** 16 | * the default location to save the downloads into 17 | */ 18 | public static final String TARGET_FOLDER = "./download"; 19 | 20 | /** 21 | * a {@link Comparator} to compare Strings based on their numeric value 22 | */ 23 | public static final Comparator STRING_NUMBER_COMPARATOR = Comparator.comparingDouble( Double::parseDouble ); 24 | 25 | /** 26 | * the average filesize in kB.
27 | * estimated from : 28 | *
29 | *
700 chapters of Naruto from Mangapanda
30 | *
156.6 kB
31 | *
799 chapters of OnePiece from Mangapanda
32 | *
183.7 kB
33 | *
700 + some coloured chapters of Naruto from Mangafox
34 | *
139.2 kB
35 | *
799 chapters of OnePiece from Mangafox
36 | *
230.6 kB
37 | *
38 | */ 39 | public static final int AVG_SIZE = 177; 40 | 41 | /** 42 | * unused constructor to avoid instantiation 43 | */ 44 | private Constants() { 45 | // not called 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /MangaLib/src/main/java/de/herrlock/manga/exceptions/MDException.java: -------------------------------------------------------------------------------- 1 | package de.herrlock.manga.exceptions; 2 | 3 | /** 4 | * A general custom checked Exception 5 | * 6 | * @author HerrLock 7 | */ 8 | public class MDException extends Exception { 9 | 10 | private static final long serialVersionUID = 1L; 11 | 12 | /** 13 | * A new MDException without detailed message or cause 14 | * 15 | * @deprecated should not be used since there will be no detail-message 16 | */ 17 | @Deprecated 18 | public MDException() { 19 | super(); 20 | } 21 | 22 | /** 23 | * A new MDException with a detailed message 24 | * 25 | * @param message 26 | * a detailmessage why this exception occurred 27 | */ 28 | public MDException( final String message ) { 29 | super( message ); 30 | } 31 | 32 | /** 33 | * A new MDException with a cause 34 | * 35 | * @param cause 36 | * the cause of this exception 37 | */ 38 | public MDException( final Throwable cause ) { 39 | super( cause ); 40 | } 41 | 42 | /** 43 | * A new MDException with a detailed message and cause 44 | * 45 | * @param message 46 | * a detailmessage why this exception occurred 47 | * @param cause 48 | * the cause of this exception 49 | */ 50 | public MDException( final String message, final Throwable cause ) { 51 | super( message, cause ); 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /MangaLib/src/main/java/de/herrlock/manga/downloader/dqc/Page.java: -------------------------------------------------------------------------------- 1 | package de.herrlock.manga.downloader.dqc; 2 | 3 | import java.io.File; 4 | import java.net.URL; 5 | 6 | final class Page { 7 | /** 8 | * the {@link URL} where to read this page from 9 | */ 10 | private final URL pageUrl; 11 | /** 12 | * the {@link File} where this page will be saved 13 | */ 14 | private final File targetFile; 15 | 16 | /** 17 | * creates a new page 18 | * 19 | * @param pageUrl 20 | * the {@link URL} where to read from 21 | * @param chapterFolder 22 | * the folder where the page will be stored 23 | * @param pageNumber 24 | * the number of the page, sets the filename (with optional prepended '0') 25 | */ 26 | public Page( final URL pageUrl, final File chapterFolder, final int pageNumber ) { 27 | this.pageUrl = pageUrl; 28 | String _nr = ( pageNumber > 9 ? "" : "0" ) + pageNumber; 29 | this.targetFile = new File( chapterFolder, _nr + ".jpg" ); 30 | } 31 | 32 | /** 33 | * getter for this page's {@link URL} 34 | * 35 | * @return the {@link URL} of this page 36 | */ 37 | public URL getUrl() { 38 | return this.pageUrl; 39 | } 40 | 41 | /** 42 | * getter for this page's save-location 43 | * 44 | * @return the {@link File} where to store this page 45 | */ 46 | public File getTargetFile() { 47 | return this.targetFile; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /MangaLib/src/main/java/de/herrlock/manga/util/configuration/IndexerConfiguration.java: -------------------------------------------------------------------------------- 1 | package de.herrlock.manga.util.configuration; 2 | 3 | import java.net.URL; 4 | import java.text.MessageFormat; 5 | import java.util.Properties; 6 | 7 | /** 8 | * A {@link Configuration} containing settings needed for http-connections 9 | * 10 | * @author HerrLock 11 | */ 12 | public class IndexerConfiguration extends DownloadConfiguration { 13 | 14 | /** 15 | * Creates an {@link IndexerConfiguration} from the given {@link Properties} 16 | * 17 | * @param p 18 | * the {@link Properties} where to get the values from 19 | * @return a new {@link DownloadConfiguration} 20 | */ 21 | public static IndexerConfiguration create( final Properties p ) { 22 | URL url = _createUrlNotRequired( p ); 23 | int timeout = _createTimeout( p ); 24 | return new IndexerConfiguration( url, timeout ); 25 | } 26 | 27 | /** 28 | * constructor for an {@link IndexerConfiguration} 29 | * 30 | * @param url 31 | * an {@link URL} to the manga's base-page. 32 | * @param timeout 33 | * the timeout for the http-requests. The dafult-value is used if negative. 34 | */ 35 | public IndexerConfiguration( final URL url, final int timeout ) { 36 | super( true, false, url, null, timeout ); 37 | } 38 | 39 | @Override 40 | public String toString() { 41 | return MessageFormat.format( "URL: {0}, Timeout: {1}", getUrl(), getTimeout() ); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /MangaLib/src/test/java/de/herrlock/manga/jd/TestCrawljob.java: -------------------------------------------------------------------------------- 1 | package de.herrlock.manga.jd; 2 | 3 | import java.io.File; 4 | import java.io.IOException; 5 | 6 | import org.junit.Assert; 7 | import org.junit.Test; 8 | 9 | /** 10 | * @author HerrLock 11 | */ 12 | public class TestCrawljob { 13 | 14 | @Test 15 | public void test1() throws IOException { 16 | Crawljob crawljob = new Crawljob( new File( "" ), "42" ); 17 | crawljob.addCrawljobEntry( "filename", "url" ); 18 | String ls = System.lineSeparator(); 19 | StringBuilder sb = new StringBuilder()// 20 | .append( ls )// 21 | .append( "->NEW ENTRY<-" )// 22 | .append( ls )// 23 | .append( "text=url" )// 24 | .append( ls )// 25 | .append( "filename=filename.jpg" )// 26 | .append( ls )// 27 | .append( "downloadFolder=" )// 28 | .append( new File( "." ).getCanonicalPath() )// 29 | .append( ls )// 30 | .append( "packageName=42" )// 31 | .append( ls )// 32 | .append( "addOfflineLink=true" )// 33 | .append( ls )// 34 | .append( ( char ) 0 ); 35 | String expected = sb.toString(); 36 | String export = crawljob.export(); 37 | Assert.assertEquals( expected, export ); 38 | } 39 | 40 | @Test 41 | public void testGetFilename() { 42 | Crawljob crawljob = new Crawljob( new File( "" ), "42" ); 43 | Assert.assertEquals( "42.crawljob", crawljob.getFilename() ); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /MangaLib/src/main/java/de/herrlock/manga/exceptions/MDRuntimeException.java: -------------------------------------------------------------------------------- 1 | package de.herrlock.manga.exceptions; 2 | 3 | /** 4 | * A general custom RuntimeException 5 | * 6 | * @author HerrLock 7 | */ 8 | public class MDRuntimeException extends RuntimeException { 9 | 10 | private static final long serialVersionUID = 1L; 11 | 12 | /** 13 | * A new MDRuntimeException without detailed message or cause 14 | * 15 | * @deprecated should not be used since there will be no detail-message 16 | */ 17 | @Deprecated 18 | public MDRuntimeException() { 19 | super(); 20 | } 21 | 22 | /** 23 | * A new MDRuntimeException with a detailed message 24 | * 25 | * @param message 26 | * a detailmessage why this exception occurred 27 | */ 28 | public MDRuntimeException( final String message ) { 29 | super( message ); 30 | } 31 | 32 | /** 33 | * A new MDRuntimeException with a cause 34 | * 35 | * @param cause 36 | * the cause of this exception 37 | */ 38 | public MDRuntimeException( final Throwable cause ) { 39 | super( cause ); 40 | } 41 | 42 | /** 43 | * A new MDRuntimeException with a detailed message and cause 44 | * 45 | * @param message 46 | * a detailmessage why this exception occurred 47 | * @param cause 48 | * the cause of this exception 49 | */ 50 | public MDRuntimeException( final String message, final Throwable cause ) { 51 | super( message, cause ); 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /MangaLib/src/main/java/de/herrlock/manga/index/entity/HosterListEntry.java: -------------------------------------------------------------------------------- 1 | package de.herrlock.manga.index.entity; 2 | 3 | import java.text.MessageFormat; 4 | import java.util.Comparator; 5 | import java.util.Locale; 6 | 7 | import javax.xml.bind.annotation.XmlAccessType; 8 | import javax.xml.bind.annotation.XmlAccessorType; 9 | import javax.xml.bind.annotation.XmlAttribute; 10 | 11 | /** 12 | * @author HerrLock 13 | */ 14 | @XmlAccessorType( XmlAccessType.NONE ) 15 | public final class HosterListEntry { 16 | 17 | @XmlAttribute( name = "name" ) 18 | private String name; 19 | @XmlAttribute( name = "url" ) 20 | private String url; 21 | 22 | public String getName() { 23 | return this.name; 24 | } 25 | 26 | public void setName( final String name ) { 27 | this.name = name; 28 | } 29 | 30 | public String getUrl() { 31 | return this.url; 32 | } 33 | 34 | public void setUrl( final String url ) { 35 | this.url = url; 36 | } 37 | 38 | @Override 39 | public String toString() { 40 | return MessageFormat.format( "HosterListEntry ({0}, {1})", this.name, this.url ); 41 | } 42 | 43 | public static final Comparator NAME_COMPARATOR = new Comparator() { 44 | @Override 45 | public int compare( final HosterListEntry entry1, final HosterListEntry entry2 ) { 46 | String name1 = entry1.getName().toUpperCase( Locale.GERMANY ); 47 | String name2 = entry2.getName().toUpperCase( Locale.GERMANY ); 48 | return name1.compareTo( name2 ); 49 | } 50 | }; 51 | 52 | } 53 | -------------------------------------------------------------------------------- /MangaLauncher/src/main/java/de/herrlock/manga/cli/options/LogOptions.java: -------------------------------------------------------------------------------- 1 | package de.herrlock.manga.cli.options; 2 | 3 | import org.apache.commons.cli.Option; 4 | import org.apache.commons.cli.OptionGroup; 5 | import org.apache.commons.cli.Options; 6 | 7 | /** 8 | * A set of {@linkplain Option}s 9 | * 10 | * @author HerrLock 11 | */ 12 | public final class LogOptions { 13 | 14 | private final Option logLevelOption = Option.builder( "l" ) // 15 | .longOpt( "log" ) // 16 | .hasArg() // 17 | .argName( "level" ) // 18 | .desc( "Loglevel to use. Allowed values: OFF, FATAL, ERROR, WARN, INFO, DEBUG, TRACE, ALL" ) // 19 | .build(); 20 | private final Option quietOption = Option.builder( "q" ) // 21 | .longOpt( "quiet" ) // 22 | .desc( "Set the log-level to WARN" ) // 23 | .build(); 24 | private final Option verboseOption = Option.builder( "v" ) // 25 | .longOpt( "verbose" ) // 26 | .desc( "Set the log-level to DEBUG" ) // 27 | .build(); 28 | 29 | private final OptionGroup logOptionGroup = new OptionGroup() // 30 | .addOption( this.logLevelOption ) // 31 | .addOption( this.quietOption ) // 32 | .addOption( this.verboseOption ) // 33 | ; 34 | 35 | private final Options options; 36 | 37 | /** 38 | * Create new Options 39 | */ 40 | public LogOptions() { 41 | this.options = new Options().addOptionGroup( this.logOptionGroup ); 42 | } 43 | 44 | /** 45 | * @return the Options from the class 46 | */ 47 | public Options getOptions() { 48 | return this.options; 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /MangaLauncher/src/test/java/de/herrlock/manga/cli/parser/TestIgnoreUnknownParser.java: -------------------------------------------------------------------------------- 1 | package de.herrlock.manga.cli.parser; 2 | 3 | import org.apache.commons.cli.CommandLine; 4 | import org.apache.commons.cli.CommandLineParser; 5 | import org.apache.commons.cli.Options; 6 | import org.apache.commons.cli.ParseException; 7 | import org.junit.Assert; 8 | import org.junit.Test; 9 | 10 | /** 11 | * @author HerrLock 12 | */ 13 | public class TestIgnoreUnknownParser { 14 | 15 | private final CommandLineParser parser = new IgnoreUnknownParser(); 16 | 17 | @Test 18 | public void test1() throws ParseException { 19 | Options options = new Options().addOption( "o", "opt", false, "desc" ); 20 | String[] args = { 21 | "--opt" 22 | }; 23 | CommandLine commandLine = this.parser.parse( options, args ); 24 | Assert.assertEquals( 1, commandLine.getOptions().length ); 25 | } 26 | 27 | @Test 28 | public void test2() throws ParseException { 29 | Options options = new Options().addOption( "o", "opt", false, "desc" ); 30 | String[] args = { 31 | "--opt", "--unknown" 32 | }; 33 | CommandLine commandLine = this.parser.parse( options, args ); 34 | Assert.assertEquals( 1, commandLine.getOptions().length ); 35 | } 36 | 37 | @Test 38 | public void test3() throws ParseException { 39 | Options options = new Options(); 40 | String[] args = { 41 | "--opt" 42 | }; 43 | CommandLine commandLine = this.parser.parse( options, args ); 44 | Assert.assertEquals( 0, commandLine.getOptions().length ); 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /MangaCtrl/src/main/java/de/herrlock/manga/host/PrintAllHoster.java: -------------------------------------------------------------------------------- 1 | package de.herrlock.manga.host; 2 | 3 | import java.io.PrintStream; 4 | import java.text.MessageFormat; 5 | import java.util.ArrayDeque; 6 | import java.util.Collection; 7 | 8 | import org.apache.logging.log4j.LogManager; 9 | import org.apache.logging.log4j.Logger; 10 | 11 | /** 12 | * @author HerrLock 13 | */ 14 | public final class PrintAllHoster { 15 | 16 | private static final Logger logger = LogManager.getLogger(); 17 | 18 | public static void printHoster( final PrintStream out ) { 19 | Collection values = Hosters.sortedValues(); 20 | out.println( "availabile hoster" ); 21 | for ( Hoster h : values ) { 22 | out.println( getHosterString( h ) ); 23 | } 24 | } 25 | 26 | public static void printHoster() { 27 | Collection values = Hosters.sortedValues(); 28 | logger.info( "availabile hoster" ); 29 | for ( Hoster h : values ) { 30 | logger.info( getHosterString( h ) ); 31 | } 32 | } 33 | 34 | public static Collection getHosterDescs() { 35 | Collection values = Hosters.sortedValues(); 36 | Collection result = new ArrayDeque<>( values.size() ); 37 | for ( Hoster h : values ) { 38 | result.add( getHosterString( h ) ); 39 | } 40 | return result; 41 | } 42 | 43 | private static String getHosterString( final Hoster hoster ) { 44 | return MessageFormat.format( "{0}:\t{1}", hoster.getName(), hoster.getBaseUrl() ); 45 | } 46 | 47 | private PrintAllHoster() { 48 | // nothing to do 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /MangaLauncher/src/main/resources/log4j2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | %m%n 5 | %d{HH:mm:ss.SSS} [%t] %-5p %c{1.}.%M - %m%n 6 | %d{yyyy-MM-dd} - ${patternLayout} 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /MangaLauncher/src/main/java/de/herrlock/manga/cli/parser/IgnoreUnknownParser.java: -------------------------------------------------------------------------------- 1 | package de.herrlock.manga.cli.parser; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Arrays; 5 | import java.util.List; 6 | import java.util.Properties; 7 | 8 | import org.apache.commons.cli.CommandLine; 9 | import org.apache.commons.cli.DefaultParser; 10 | import org.apache.commons.cli.Options; 11 | import org.apache.commons.cli.ParseException; 12 | import org.apache.commons.cli.UnrecognizedOptionException; 13 | 14 | /** 15 | * @author HerrLock 16 | */ 17 | public class IgnoreUnknownParser extends DefaultParser { 18 | 19 | @Override 20 | public CommandLine parse( final Options options, final String[] arguments, final Properties properties, 21 | final boolean stopAtNonOption ) throws ParseException { 22 | List argumentList = new ArrayList<>( Arrays.asList( arguments ) ); 23 | CommandLine parse = null; 24 | while ( parse == null && !argumentList.isEmpty() ) { 25 | /* parse == null and argumentList not empty */ 26 | try { 27 | String[] argumentListArray = argumentList.toArray( new String[0] ); 28 | parse = super.parse( options, argumentListArray, properties, false ); 29 | } catch ( UnrecognizedOptionException ex ) { 30 | argumentList.remove( ex.getOption() ); 31 | } 32 | } 33 | /* parse != null or argumentList is empty */ 34 | if ( parse == null ) { 35 | /* argumentList is empty */ 36 | parse = super.parse( options, new String[0], properties, false ); 37 | } 38 | return parse; 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /MangaLib/src/main/java/de/herrlock/manga/exceptions/InitializeException.java: -------------------------------------------------------------------------------- 1 | package de.herrlock.manga.exceptions; 2 | 3 | /** 4 | * an exception that indicates that sth. happened while initializing the download, so the application can stay opened. 5 | * 6 | * @author HerrLock 7 | */ 8 | public final class InitializeException extends RuntimeException { 9 | 10 | private static final long serialVersionUID = 1L; 11 | 12 | /** 13 | * A new InitializeException without detailed message or cause 14 | * 15 | * @deprecated should not be used since there will be no detail-message 16 | */ 17 | @Deprecated 18 | public InitializeException() { 19 | super(); 20 | } 21 | 22 | /** 23 | * A new InitializeException with a detailed message 24 | * 25 | * @param message 26 | * a detailmessage why this exception occurred 27 | */ 28 | public InitializeException( final String message ) { 29 | super( message ); 30 | } 31 | 32 | /** 33 | * A new InitializeException with a cause 34 | * 35 | * @param cause 36 | * the cause of this exception 37 | */ 38 | public InitializeException( final Throwable cause ) { 39 | super( cause ); 40 | } 41 | 42 | /** 43 | * A new InitializeException with a detailed message and cause 44 | * 45 | * @param message 46 | * a detailmessage why this exception occurred 47 | * @param cause 48 | * the cause of this exception 49 | */ 50 | public InitializeException( final String message, final Throwable cause ) { 51 | super( message, cause ); 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /MangaLauncher/src/test/java/de/herrlock/manga/cli/options/TestSubOptions.java: -------------------------------------------------------------------------------- 1 | package de.herrlock.manga.cli.options; 2 | 3 | import java.util.Arrays; 4 | import java.util.Collection; 5 | 6 | import org.junit.Assert; 7 | import org.junit.Test; 8 | import org.junit.runner.RunWith; 9 | import org.junit.runners.Parameterized; 10 | import org.junit.runners.Parameterized.Parameter; 11 | import org.junit.runners.Parameterized.Parameters; 12 | 13 | @RunWith( Parameterized.class ) 14 | public final class TestSubOptions { 15 | 16 | @Parameter( 0 ) 17 | public String subOptionName; 18 | @Parameter( 1 ) 19 | public Class expectedClass; 20 | 21 | @Test 22 | public void testOptionCount() { 23 | SubOptions subOptions = SubOptions.getSubOptions( this.subOptionName ); 24 | Assert.assertTrue( this.expectedClass.isAssignableFrom( subOptions.getClass() ) ); 25 | } 26 | 27 | @Parameters( name = "{0}: {1}" ) 28 | public static Collection createParams() { 29 | return Arrays.asList( new Object[][] { 30 | { 31 | null, EmptyOptions.class 32 | }, { 33 | "console", ConsoleOptions.class 34 | }, { 35 | "dialog", EmptyOptions.class 36 | }, { 37 | "gui", EmptyOptions.class 38 | }, { 39 | "viewpage", ViewpageOptions.class 40 | }, { 41 | "server", ServerOptions.class 42 | }, { 43 | "help", EmptyOptions.class 44 | }, { 45 | "version", EmptyOptions.class 46 | }, { 47 | "unknown", EmptyOptions.class 48 | } 49 | } ); 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /MangaCtrl/src/main/java/de/herrlock/manga/http/ServerMain.java: -------------------------------------------------------------------------------- 1 | package de.herrlock.manga.http; 2 | 3 | import java.awt.Desktop; 4 | import java.io.IOException; 5 | import java.net.URI; 6 | import java.net.URISyntaxException; 7 | 8 | import org.apache.logging.log4j.LogManager; 9 | import org.apache.logging.log4j.Logger; 10 | 11 | import de.herrlock.manga.exceptions.MDException; 12 | import de.herrlock.manga.http.server.JettyServer; 13 | 14 | /** 15 | * @author HerrLock 16 | */ 17 | public final class ServerMain { 18 | private static final Logger logger = LogManager.getLogger(); 19 | 20 | private final JettyServer server; 21 | 22 | public static void execute() throws IOException, URISyntaxException, MDException { 23 | logger.traceEntry(); 24 | execute( false ); 25 | } 26 | 27 | public static void execute( final boolean withDesktop ) throws IOException, URISyntaxException, MDException { 28 | logger.traceEntry( "withDesktop: {}", withDesktop ); 29 | ServerMain srvMain = new ServerMain(); 30 | srvMain.start(); 31 | if ( withDesktop && Desktop.isDesktopSupported() ) { 32 | Desktop.getDesktop().browse( new URI( "http://localhost:1905" ) ); 33 | } 34 | srvMain.listenForStop(); 35 | srvMain.stop(); 36 | } 37 | 38 | public ServerMain() { 39 | logger.traceEntry(); 40 | this.server = new JettyServer(); 41 | } 42 | 43 | public void start() throws MDException { 44 | logger.traceEntry(); 45 | this.server.start(); 46 | } 47 | 48 | public void listenForStop() { 49 | logger.traceEntry(); 50 | this.server.listenForStop(); 51 | } 52 | 53 | public void stop() throws MDException { 54 | logger.traceEntry(); 55 | this.server.stop(); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /MangaCtrl/src/main/java/de/herrlock/manga/downloader/SettingsFileDownloader.java: -------------------------------------------------------------------------------- 1 | package de.herrlock.manga.downloader; 2 | 3 | import java.io.IOException; 4 | import java.io.InputStream; 5 | import java.nio.file.Files; 6 | import java.nio.file.Paths; 7 | import java.util.Properties; 8 | 9 | import org.apache.logging.log4j.LogManager; 10 | import org.apache.logging.log4j.Logger; 11 | 12 | import de.herrlock.manga.exceptions.MDRuntimeException; 13 | import de.herrlock.manga.util.Constants; 14 | import de.herrlock.manga.util.configuration.DownloadConfiguration; 15 | 16 | /** 17 | * Simply starts the download without any confirmation, 18 | * 19 | * @author HerrLock 20 | */ 21 | public final class SettingsFileDownloader extends MDownloader { 22 | private static final Logger logger = LogManager.getLogger(); 23 | 24 | public static void execute() { 25 | logger.traceEntry(); 26 | Properties p = new Properties(); 27 | // load properties 28 | try ( InputStream fIn = Files.newInputStream( Paths.get( Constants.SETTINGS_FILE ) ) ) { 29 | p.load( fIn ); 30 | } catch ( IOException ex ) { 31 | throw new MDRuntimeException( ex ); 32 | } 33 | // properties loaded successful 34 | DownloadConfiguration conf = DownloadConfiguration.create( p ); 35 | SettingsFileDownloader dlImpl = new SettingsFileDownloader( conf ); 36 | DownloadProcessor.getInstance().addDownload( dlImpl ); 37 | } 38 | 39 | public SettingsFileDownloader( final DownloadConfiguration conf ) { 40 | super( conf ); 41 | } 42 | 43 | @Override 44 | protected void run() { 45 | logger.traceEntry(); 46 | try { 47 | downloadAll(); 48 | } catch ( Exception ex ) { 49 | throw ex; 50 | } 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /MangaLib/src/main/java/de/herrlock/manga/index/entity/HosterList.java: -------------------------------------------------------------------------------- 1 | package de.herrlock.manga.index.entity; 2 | 3 | import java.text.MessageFormat; 4 | import java.util.Collection; 5 | import java.util.Comparator; 6 | import java.util.Locale; 7 | 8 | import javax.xml.bind.annotation.XmlAccessType; 9 | import javax.xml.bind.annotation.XmlAccessorType; 10 | import javax.xml.bind.annotation.XmlAttribute; 11 | import javax.xml.bind.annotation.XmlElement; 12 | 13 | /** 14 | * @author HerrLock 15 | */ 16 | @XmlAccessorType( XmlAccessType.NONE ) 17 | public final class HosterList { 18 | 19 | @XmlAttribute( name = "name" ) 20 | private String hosterName; 21 | @XmlElement( name = "manga" ) 22 | private Collection mangas; 23 | 24 | public String getHosterName() { 25 | return this.hosterName; 26 | } 27 | 28 | public void setHosterName( final String hosterName ) { 29 | this.hosterName = hosterName; 30 | } 31 | 32 | public Collection getMangas() { 33 | return this.mangas; 34 | } 35 | 36 | public void setMangas( final Collection mangas ) { 37 | this.mangas = mangas; 38 | } 39 | 40 | @Override 41 | public String toString() { 42 | return MessageFormat.format( "HosterList @{0} ({1})", this.hosterName, this.mangas == null ? null : this.mangas.size() ); 43 | } 44 | 45 | public static final Comparator HOSTER_NAME_COMPARATOR = new Comparator() { 46 | @Override 47 | public int compare( final HosterList list1, final HosterList list2 ) { 48 | String name1 = list1.getHosterName().toUpperCase( Locale.GERMANY ); 49 | String name2 = list2.getHosterName().toUpperCase( Locale.GERMANY ); 50 | return name1.compareTo( name2 ); 51 | } 52 | }; 53 | 54 | } 55 | -------------------------------------------------------------------------------- /MangaLib/src/test/java/de/herrlock/manga/DummyServer.java: -------------------------------------------------------------------------------- 1 | package de.herrlock.manga; 2 | 3 | import java.io.IOException; 4 | import java.util.concurrent.atomic.AtomicInteger; 5 | 6 | import javax.servlet.ServletException; 7 | import javax.servlet.http.HttpServletRequest; 8 | import javax.servlet.http.HttpServletResponse; 9 | 10 | import org.eclipse.jetty.server.Request; 11 | import org.eclipse.jetty.server.Server; 12 | import org.eclipse.jetty.server.handler.AbstractHandler; 13 | 14 | /** 15 | * @author HerrLock 16 | */ 17 | public class DummyServer { 18 | private final Server server; 19 | private final DummyDefaultHandler handler; 20 | 21 | public DummyServer( final int port ) { 22 | this.server = new Server( port ); 23 | this.handler = new DummyDefaultHandler(); 24 | this.server.setHandler( this.handler ); 25 | } 26 | 27 | public int timesHandlerCalled() { 28 | return this.handler.timesCalled(); 29 | } 30 | 31 | public final void start() throws Exception { 32 | this.server.start(); 33 | } 34 | 35 | public final void stop() throws Exception { 36 | this.server.stop(); 37 | } 38 | 39 | private static final class DummyDefaultHandler extends AbstractHandler { 40 | private final AtomicInteger called = new AtomicInteger(); 41 | 42 | @Override 43 | public void handle( final String target, final Request baseRequest, final HttpServletRequest request, 44 | final HttpServletResponse response ) throws IOException, ServletException { 45 | this.called.incrementAndGet(); 46 | response.setStatus( HttpServletResponse.SC_OK ); 47 | response.getWriter().write( "OK\r\n" ); 48 | baseRequest.setHandled( true ); 49 | } 50 | 51 | public int timesCalled() { 52 | return this.called.get(); 53 | } 54 | 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/notused/html-resources/style.css: -------------------------------------------------------------------------------- 1 | html { 2 | background-color: #ccc; 3 | background-repeat: no-repeat; 4 | background-position: top center; 5 | background-size: 100%; 6 | font-family: sans-serif; 7 | } 8 | 9 | body { 10 | padding: 1rem; 11 | } 12 | 13 | #content, 14 | #closeNotice { 15 | float: left; 16 | margin: 1em; 17 | padding: 1em; 18 | width: 35em; 19 | background-color: lightgray; 20 | border-radius: 15px; 21 | opacity: 0.8; 22 | } 23 | 24 | #auswahl, 25 | #eingabe { 26 | margin: .5em; 27 | } 28 | 29 | #eingabe label, 30 | #eingabe input { 31 | margin: 2px; 32 | display: inline-block; 33 | } 34 | 35 | #eingabe > ul { 36 | list-style-type: none; 37 | list-style-position: outside; 38 | margin: 0px; 39 | padding: 0px; 40 | } 41 | 42 | #eingabe label { 43 | width: 7em; 44 | padding: .5em 0em; 45 | } 46 | 47 | #eingabe input { 48 | padding: .5em; 49 | width: 100%; 50 | max-width: 25em; 51 | } 52 | 53 | #buttons { 54 | margin: 4px; 55 | padding: 4px; 56 | } 57 | 58 | #buttons > button { 59 | padding: 4px 8px; 60 | } 61 | 62 | #bars { 63 | float: left; 64 | margin: 1em; 65 | display: inline-block; 66 | background-color: lightgray; 67 | opacity: 0.9; 68 | border-radius: .5em; 69 | } 70 | 71 | #bars > h2 { 72 | text-align: center; 73 | } 74 | 75 | #bars > fieldset { 76 | margin: .5em; 77 | } 78 | 79 | #bars > fieldset > legend { 80 | color: #666; 81 | font-size: x-small; 82 | } 83 | 84 | #bars progress { 85 | font-size: large; 86 | width: 100%; 87 | } 88 | 89 | .dummy { 90 | visibility: hidden; 91 | height: 0em; 92 | overflow-y: hidden; 93 | } 94 | 95 | #reflinks { 96 | position: fixed; 97 | bottom: .5rem; 98 | right: .5rem; 99 | padding: .2rem; 100 | border-radius: .5em; 101 | font-size: x-small; 102 | background-color: lightgray; 103 | opacity: 0.8; 104 | } 105 | -------------------------------------------------------------------------------- /MangaLib/src/test/java/de/herrlock/manga/util/TestChapterPatternRegex.java: -------------------------------------------------------------------------------- 1 | package de.herrlock.manga.util; 2 | 3 | import static org.junit.Assert.assertEquals; 4 | 5 | import java.util.Arrays; 6 | import java.util.Collection; 7 | 8 | import org.junit.Test; 9 | import org.junit.runner.RunWith; 10 | import org.junit.runners.Parameterized; 11 | import org.junit.runners.Parameterized.Parameters; 12 | 13 | /** 14 | * Tests the ChapterPattern's matcher-regex 15 | * 16 | * @author HerrLock 17 | */ 18 | @RunWith( Parameterized.class ) 19 | public class TestChapterPatternRegex { 20 | private final String toCheck; 21 | private final boolean expected; 22 | 23 | /** 24 | * @param toCheck 25 | * the value to check 26 | * @param expected 27 | * if the value to check is expected to be valid 28 | */ 29 | public TestChapterPatternRegex( final String toCheck, final boolean expected ) { 30 | this.toCheck = toCheck; 31 | this.expected = expected; 32 | } 33 | 34 | /** 35 | * tests a single entry 36 | */ 37 | @Test 38 | public void testCase() { 39 | assertEquals( this.expected, ChapterPattern.REGEX.matcher( this.toCheck ).matches() ); 40 | } 41 | 42 | /** 43 | * Creates the entries to test 44 | * 45 | * @return the paramters 46 | */ 47 | @Parameters( name = "{0} => {1}" ) 48 | public static Collection generateParams() { 49 | Object[][] params = { 50 | { 51 | "10", true 52 | }, { 53 | "10-12", true 54 | }, { 55 | "10;11", true 56 | }, { 57 | "10;11-13", true 58 | }, { 59 | "10;", false 60 | }, { 61 | "10;;11", false 62 | } 63 | }; 64 | return Arrays.asList( params ); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /MangaLib/src/main/java/de/herrlock/manga/http/server/handlers/MangaBaseHandler.java: -------------------------------------------------------------------------------- 1 | package de.herrlock.manga.http.server.handlers; 2 | 3 | import java.io.IOException; 4 | 5 | import javax.servlet.ServletException; 6 | import javax.servlet.http.HttpServletRequest; 7 | import javax.servlet.http.HttpServletResponse; 8 | 9 | import org.apache.logging.log4j.LogManager; 10 | import org.apache.logging.log4j.Logger; 11 | import org.eclipse.jetty.server.Handler; 12 | import org.eclipse.jetty.server.Request; 13 | import org.eclipse.jetty.server.handler.HandlerList; 14 | 15 | public class MangaBaseHandler extends HandlerList { 16 | private static final Logger logger = LogManager.getLogger(); 17 | 18 | public static final String PREFIX_PATH = "/j/"; 19 | 20 | private final Handler imageHandler = new ReturnImageHandler(); 21 | private final Handler downloadHandler = new DownloadHandler(); 22 | private final Handler listHandler = new GetListHandler(); 23 | 24 | @Override 25 | public void handle( final String target, final Request baseRequest, final HttpServletRequest request, 26 | final HttpServletResponse response ) throws IOException, ServletException { 27 | logger.traceEntry( "{}", target ); 28 | 29 | if ( target != null && target.startsWith( PREFIX_PATH ) ) { 30 | String subPath = target.substring( PREFIX_PATH.length() ); 31 | if ( subPath.equals( ReturnImageHandler.PREFIX_PATH ) ) { 32 | this.imageHandler.handle( subPath, baseRequest, request, response ); 33 | } else if ( subPath.startsWith( DownloadHandler.PREFIX_PATH ) ) { 34 | this.downloadHandler.handle( subPath, baseRequest, request, response ); 35 | } else if ( subPath.startsWith( GetListHandler.PREFIX_PATH ) ) { 36 | this.listHandler.handle( subPath, baseRequest, request, response ); 37 | } 38 | } 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /MangaLib/src/test/java/de/herrlock/manga/http/client/TestJettyClient.java: -------------------------------------------------------------------------------- 1 | package de.herrlock.manga.http.client; 2 | 3 | import static org.junit.Assert.assertEquals; 4 | 5 | import java.net.MalformedURLException; 6 | import java.net.URI; 7 | import java.net.URL; 8 | import java.util.Properties; 9 | 10 | import org.eclipse.jetty.client.api.Request; 11 | import org.junit.Test; 12 | 13 | import de.herrlock.manga.DummyServer; 14 | import de.herrlock.manga.util.configuration.Configuration; 15 | import de.herrlock.manga.util.configuration.DownloadConfiguration; 16 | 17 | public class TestJettyClient { 18 | 19 | @Test 20 | public void testCreateHttpGet() throws MalformedURLException { 21 | URL url = new URL( "http", "localhost", 1337, "/" ); 22 | Properties p = new Properties(); 23 | p.setProperty( Configuration.URL, url.toExternalForm() ); 24 | DownloadConfiguration conf = DownloadConfiguration.create( p ); 25 | Request request = JettyClient.createHttpGet( url, conf ); 26 | URI uri = request.getURI(); 27 | assertEquals( "http://localhost:1337/", uri.toString() ); 28 | } 29 | 30 | @Test 31 | public void testExecuteHttpGet() throws Exception { 32 | DummyServer server = new DummyServer( 1337 ); 33 | 34 | URL url = new URL( "http", "localhost", 1337, "/" ); 35 | Properties p = new Properties(); 36 | p.setProperty( Configuration.URL, url.toExternalForm() ); 37 | DownloadConfiguration conf = DownloadConfiguration.create( p ); 38 | ResponseHandler responseHandler = ResponseHandler.fromFunction( input -> input.getContentAsString() ); 39 | 40 | server.start(); 41 | String response = JettyClient.getDataAndExecuteResponseHandler( url, conf, responseHandler ); 42 | server.stop(); 43 | 44 | assertEquals( 1, server.timesHandlerCalled() ); 45 | assertEquals( "OK\r\n", response ); 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /MangaLauncher/src/main/java/de/herrlock/log4j2/util/Log4jConfiguration.java: -------------------------------------------------------------------------------- 1 | package de.herrlock.log4j2.util; 2 | 3 | import java.util.List; 4 | 5 | import org.apache.logging.log4j.Level; 6 | import org.apache.logging.log4j.LogManager; 7 | import org.apache.logging.log4j.Logger; 8 | import org.apache.logging.log4j.core.Filter; 9 | import org.apache.logging.log4j.core.LoggerContext; 10 | import org.apache.logging.log4j.core.config.AppenderRef; 11 | 12 | import de.herrlock.log4j2.filter.LevelFilter; 13 | 14 | public final class Log4jConfiguration { 15 | private static final Logger logger = LogManager.getLogger(); 16 | 17 | public static void changeLevelFilterLevel( final String optionValue ) { 18 | Level level = Level.toLevel( optionValue, Level.INFO ); 19 | changeLevelFilterLevel( level ); 20 | } 21 | 22 | public static void changeLevelFilterLevel( final Level level ) { 23 | LoggerContext context = ( LoggerContext ) LogManager.getContext( false ); 24 | List appenderRefs = context.getConfiguration().getRootLogger().getAppenderRefs(); 25 | for ( AppenderRef appenderRef : appenderRefs ) { 26 | if ( "ConsoleLogger".equals( appenderRef.getRef() ) ) { 27 | Filter rootFilter = appenderRef.getFilter(); 28 | if ( rootFilter instanceof LevelFilter ) { 29 | LevelFilter levelFilter = ( LevelFilter ) rootFilter; 30 | levelFilter.setLevel( level ); 31 | context.updateLoggers(); 32 | logger.debug( "set log-level to {}", level ); 33 | } else { 34 | logger.debug( "cannot find LevelFilter" ); 35 | } 36 | } else { 37 | logger.debug( "Not ConsoleLogger: {}", appenderRef ); 38 | } 39 | } 40 | } 41 | 42 | private Log4jConfiguration() { 43 | // prevent instantiation 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /MangaLib/src/main/java/de/herrlock/manga/http/client/ToDocumentOrRetryHandler.java: -------------------------------------------------------------------------------- 1 | package de.herrlock.manga.http.client; 2 | 3 | import java.io.IOException; 4 | import java.net.URL; 5 | 6 | import org.eclipse.jetty.client.api.ContentResponse; 7 | import org.jsoup.Jsoup; 8 | import org.jsoup.nodes.Document; 9 | 10 | import de.herrlock.manga.exceptions.ResponseHandlerException; 11 | import de.herrlock.manga.util.configuration.DownloadConfiguration; 12 | 13 | /** 14 | * converts an {@link ContentResponse} to a Jsoup-{@link Document} or retries the HTTP-request 15 | */ 16 | public final class ToDocumentOrRetryHandler extends ResponseHandler { 17 | 18 | private final URL url; 19 | private final DownloadConfiguration conf; 20 | 21 | public ToDocumentOrRetryHandler( final URL url, final DownloadConfiguration conf ) { 22 | this.url = url; 23 | this.conf = conf; 24 | } 25 | 26 | @Override 27 | public Document handle( final ContentResponse response ) { 28 | if ( response == null ) { 29 | throw new IllegalArgumentException( "ContentResponse is null" ); 30 | } 31 | int statusCode = response.getStatus(); 32 | switch ( statusCode ) { 33 | case 200: 34 | return Jsoup.parse( response.getContentAsString() ); 35 | case 503: 36 | try { 37 | Thread.sleep( 1000 ); 38 | } catch ( InterruptedException ex ) { 39 | throw new ResponseHandlerException( ex ); 40 | } 41 | try { 42 | return JettyClient.getDataAndExecuteResponseHandler( this.url, this.conf, this ); 43 | } catch ( IOException ex ) { 44 | throw new ResponseHandlerException( ex ); 45 | } 46 | default: 47 | throw new ResponseHandlerException( "Received non-expected StatusCode: " + statusCode ); 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /licenses/mit-license: -------------------------------------------------------------------------------- 1 | 2 | 3 | jsoup License 4 | 5 | The jsoup code-base (include source and compiled packages) are distributed under the open source MIT license as described below. 6 | 7 | The MIT License 8 | 9 | Copyright © 2009 - 2013 Jonathan Hedley (jonathan@hedley.net) 10 | 11 | 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: 12 | 13 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 14 | 15 | 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. 16 | 17 | http://jsoup.org/license 18 | 19 | ----------------------------------------------- 20 | 21 | jQuery license 22 | 23 | jQuery Foundation projects are released under the terms of the license specified in the project's repository or if not specified, under the MIT license. 24 | 25 | The MIT License is simple and easy to understand and it places almost no restrictions on what you can do with a jQuery Foundation project. 26 | 27 | You are free to use any jQuery Foundation project in any other project (even commercial projects) as long as the copyright header is left intact. 28 | 29 | (c) jQuery Foundation 30 | 31 | https://jquery.org/license/ 32 | 33 | ----------------------------------------------- 34 | -------------------------------------------------------------------------------- /MangaLib/src/test/java/de/herrlock/manga/host/TestHosters.java: -------------------------------------------------------------------------------- 1 | package de.herrlock.manga.host; 2 | 3 | import java.io.IOException; 4 | import java.net.URL; 5 | 6 | import org.junit.Assert; 7 | import org.junit.Test; 8 | 9 | public class TestHosters { 10 | @Test 11 | public void testGetHostByURL1() throws IOException { 12 | URL url = new URL( "http://mangapanda.com" ); 13 | Hoster hoster = Hosters.tryGetHostByURL( url ); 14 | Assert.assertEquals( "Mangapanda", hoster.getName() ); 15 | } 16 | 17 | @Test 18 | public void testGetHostByURL2() throws IOException { 19 | URL url = new URL( "http://mangafox.me" ); 20 | Hoster hoster = Hosters.tryGetHostByURL( url ); 21 | Assert.assertEquals( "Mangafox", hoster.getName() ); 22 | } 23 | 24 | @Test 25 | public void testEquals() throws IOException { 26 | Hoster hoster1 = Hosters.tryGetHostByURL( new URL( "http://mangapanda.com" ) ); 27 | Hoster hoster2 = Hosters.tryGetHostByURL( new URL( "http://mangapanda.com" ) ); 28 | boolean equals = hoster1.equals( hoster2 ); 29 | Assert.assertTrue( equals ); 30 | } 31 | 32 | @Test 33 | public void testNotEquals() throws IOException { 34 | Hoster hoster1 = Hosters.tryGetHostByURL( new URL( "http://mangapanda.com" ) ); 35 | Assert.assertNotNull( hoster1 ); 36 | } 37 | 38 | @Test 39 | public void testNotEquals2() throws IOException { 40 | Hoster hoster1 = Hosters.tryGetHostByURL( new URL( "http://mangapanda.com" ) ); 41 | Object hoster2 = new Object(); 42 | boolean equals = hoster1.equals( hoster2 ); 43 | Assert.assertFalse( equals ); 44 | } 45 | 46 | @Test 47 | public void testNotEquals3() throws IOException { 48 | Hoster hoster1 = Hosters.tryGetHostByURL( new URL( "http://mangapanda.com" ) ); 49 | Hoster hoster2 = Hosters.tryGetHostByURL( new URL( "http://mangafox.me" ) ); 50 | boolean equals = hoster1.equals( hoster2 ); 51 | Assert.assertFalse( equals ); 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /MangaLib/src/test/java/de/herrlock/manga/util/StaticMethods.java: -------------------------------------------------------------------------------- 1 | package de.herrlock.manga.util; 2 | 3 | import java.lang.reflect.Constructor; 4 | import java.lang.reflect.Modifier; 5 | 6 | import org.junit.Assert; 7 | 8 | /** 9 | * Contains utility-methods for the tests 10 | * 11 | * @author HerrLock 12 | */ 13 | public final class StaticMethods { 14 | 15 | /** 16 | * Calls the private (no-args) constructor of a class. 17 | * 18 | * @param clazz 19 | * the clazz to retrieve the constructor from 20 | * @return the just created instance of the class 21 | * @throws ReflectiveOperationException 22 | * from {@link Class#getDeclaredConstructor(Class...)} and {@link #callPrivateConstructor(Constructor)} 23 | */ 24 | public static T callPrivateConstructor( final Class clazz ) throws InstantiationException, IllegalAccessException, 25 | IllegalArgumentException, NoSuchMethodException, SecurityException, ReflectiveOperationException { 26 | return callPrivateConstructor( clazz.getDeclaredConstructor() ); 27 | } 28 | 29 | /** 30 | * Calls the private constructor of a class. 31 | * 32 | * @param constructor 33 | * the constructor to use 34 | * @return the just created instance of the class 35 | * @throws ReflectiveOperationException 36 | * from {@link Constructor#setAccessible(boolean)} and {@link Constructor#newInstance(Object...)} 37 | */ 38 | public static T callPrivateConstructor( final Constructor constructor ) 39 | throws InstantiationException, IllegalAccessException, IllegalArgumentException, ReflectiveOperationException { 40 | Assert.assertNotNull( "Passed constructor must be non-null", constructor ); 41 | Assert.assertTrue( "Constructor is not private", Modifier.isPrivate( constructor.getModifiers() ) ); 42 | constructor.setAccessible( true ); 43 | return constructor.newInstance(); 44 | } 45 | 46 | private StaticMethods() { 47 | // not used 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /MangaLib/build.gradle: -------------------------------------------------------------------------------- 1 | logger.info ' >> MangaLib' 2 | 3 | description = 'The central library for this application containing all general implementations of the downloader.' 4 | 5 | dependencies { 6 | // utilities 7 | api 'com.google.guava:guava:27.1-jre' 8 | api 'org.glassfish:javax.json:1.1.4' 9 | 10 | // logging 11 | api 'org.apache.logging.log4j:log4j-api:2.11.2' 12 | runtimeOnly 'org.apache.logging.log4j:log4j-slf4j-impl:2.11.2' 13 | 14 | // IO 15 | implementation 'org.jsoup:jsoup:1.11.3' 16 | implementation 'org.eclipse.jetty:jetty-client:9.4.17.v20190418' 17 | 18 | // embed jetty 19 | implementation 'org.eclipse.jetty:jetty-server:9.4.17.v20190418' 20 | implementation 'org.eclipse.jetty:jetty-security:9.4.17.v20190418' 21 | 22 | // compressing and archiving files 23 | implementation 'org.apache.commons:commons-compress:1.18' 24 | 25 | // ServiceLoader-annotations 26 | compileOnly 'com.google.auto.service:auto-service:1.0-rc5' 27 | annotationProcessor 'com.google.auto.service:auto-service:1.0-rc5' 28 | 29 | } 30 | 31 | pmdMain.ignoreFailures = true 32 | /* 33 | TODO: fix PMD-warnings 34 | pmdMain.doLast { 35 | assertPmdErrors pmdMain, [ 36 | [clazz:'de.herrlock.manga.http.jetty.JettyServer', method: 'start', rule:'AvoidCatchingGenericException'], 37 | [clazz:'de.herrlock.manga.http.jetty.JettyServer', method: 'stop', rule:'AvoidCatchingGenericException'], 38 | [clazz:'de.herrlock.manga.jd.Crawljob', method: 'export', rule:'InsufficientStringBufferDeclaration'], 39 | [clazz:'de.herrlock.manga.util.', method: '', rule:'GodClass'], 40 | [clazz:'de.herrlock.manga.util.Utils', method: '', rule:'AvoidCatchingGenericException'] 41 | ] 42 | } 43 | */ 44 | pmdTest.ignoreFailures = true 45 | /* 46 | pmdTest.doLast { 47 | assertPmdErrors pmdTest, [ 48 | [clazz:'de.herrlock.manga.DummyServer', method: 'start', rule:'SignatureDeclareThrowsException'], 49 | [clazz:'de.herrlock.manga.DummyServer', method: 'stop', rule:'SignatureDeclareThrowsException'], 50 | [clazz:'de.herrlock.manga.util.TestUtils', method: 'testExecuteHttpGet', rule:'SignatureDeclareThrowsException'] 51 | ] 52 | } 53 | */ 54 | -------------------------------------------------------------------------------- /MangaLib/src/main/resources/de/herrlock/manga/index/manga2datatable.xsl: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 |
HosterName
42 | 45 |
46 | 47 |
48 | -------------------------------------------------------------------------------- /MangaCtrl/src/main/resources/de/herrlock/manga/CtrlScene.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 27 | 33 | 39 | 45 | 51 | 52 |
53 | 54 | 55 | 56 |
57 | -------------------------------------------------------------------------------- /MangaLib/src/main/resources/de/herrlock/manga/viewpage/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | background-color: #000; 3 | margin: 0em; 4 | padding: 1em; 5 | } 6 | 7 | h1 { 8 | color: #f00; 9 | font-weight: normal; 10 | text-decoration: underline; 11 | } 12 | 13 | h2 { 14 | color: #f00; 15 | font-weight: normal; 16 | } 17 | 18 | img.fullwidth { 19 | width: 200px; 20 | } 21 | 22 | img.normalwidth { 23 | width: 150px; 24 | } 25 | 26 | @media (min-width: 400px) { 27 | img.fullwidth { 28 | width: 340px; 29 | } 30 | img.normalwidth { 31 | width: 260px; 32 | } 33 | } 34 | 35 | @media (min-width: 600px) { 36 | img.fullwidth { 37 | width: 540px; 38 | } 39 | img.normalwidth { 40 | width: 500px; 41 | } 42 | } 43 | 44 | @media (min-width: 784px) { 45 | img.fullwidth { 46 | width: 730px; 47 | } 48 | img.normalwidth { 49 | width: 640px; 50 | } 51 | } 52 | 53 | @media (min-width: 1300px) { 54 | img.fullwidth { 55 | width: 1100px; 56 | } 57 | img.normalwidth { 58 | width: 800px; 59 | } 60 | } 61 | 62 | hr.separator { 63 | color: #f00; 64 | background-color: #f00; 65 | height: 5px; 66 | border: none; 67 | border-radius: 2px; 68 | } 69 | 70 | a { 71 | text-decoration: none; 72 | } 73 | 74 | a.whitelink:link { 75 | color: white; 76 | } 77 | 78 | a.whitelink:visited { 79 | color: white; 80 | } 81 | 82 | a.whitelink:hover { 83 | color: black; 84 | background-color: white; 85 | } 86 | 87 | a.hidelink:link { 88 | color: grey; 89 | } 90 | 91 | a.hidelink:visited { 92 | color: grey; 93 | } 94 | 95 | a.hidelink:hover { 96 | color: white; 97 | background-color: black; 98 | border: 1px red solid; 99 | } 100 | 101 | #bandindex { 102 | text-align: right; 103 | } 104 | 105 | #bandindex a { 106 | color: white; 107 | } 108 | 109 | #leftdiv { 110 | float: left; 111 | } 112 | 113 | ul.leftList { 114 | list-style-type: none; 115 | padding-left: 8px; 116 | margin: 0px; 117 | } 118 | 119 | #rightdiv { 120 | margin-left: 1em; 121 | float: left; 122 | } 123 | 124 | div.center { 125 | text-align: center; 126 | } -------------------------------------------------------------------------------- /MangaLib/src/main/java/de/herrlock/manga/downloader/DownloadProcessor.java: -------------------------------------------------------------------------------- 1 | package de.herrlock.manga.downloader; 2 | 3 | import java.util.concurrent.BlockingQueue; 4 | import java.util.concurrent.LinkedBlockingQueue; 5 | 6 | import de.herrlock.manga.http.client.JettyClient; 7 | 8 | /** 9 | * @author HerrLock 10 | */ 11 | public class DownloadProcessor { 12 | 13 | private static DownloadProcessor _INSTANCE = new DownloadProcessor(); 14 | private DownloadExecutor executor; 15 | private final Object executorMon = new Object(); 16 | 17 | private final BlockingQueue queue = new LinkedBlockingQueue<>(); 18 | 19 | public static DownloadProcessor getInstance() { 20 | return _INSTANCE; 21 | } 22 | 23 | public void addDownload( final MDownloader mdownloader ) { 24 | this.queue.add( mdownloader ); 25 | synchronized ( this.executorMon ) { 26 | if ( this.executor == null ) { 27 | this.executor = new DownloadExecutor(); 28 | this.executor.start(); 29 | } 30 | } 31 | } 32 | 33 | public class DownloadExecutor extends Thread { 34 | 35 | public DownloadExecutor() { 36 | setName( "DownloadExecutor" ); 37 | } 38 | 39 | @Override 40 | public void run() { 41 | try { 42 | JettyClient.startHttpClient(); 43 | process(); 44 | JettyClient.stopHttpClient(); 45 | } catch ( InterruptedException ex ) { 46 | // logger.error("DownloadExecutor interrupted", ex); 47 | } 48 | } 49 | 50 | private void process() throws InterruptedException { 51 | boolean exit = false; 52 | do { 53 | MDownloader mdownloader = DownloadProcessor.this.queue.take(); 54 | mdownloader.run(); 55 | synchronized ( DownloadProcessor.this.executorMon ) { 56 | if ( DownloadProcessor.this.queue.isEmpty() ) { 57 | DownloadProcessor.this.executor = null; 58 | exit = true; 59 | } 60 | } 61 | } while ( !exit ); 62 | 63 | } 64 | } 65 | 66 | } 67 | -------------------------------------------------------------------------------- /MangaLib/src/main/resources/de/herrlock/manga/index/manga2count.xsl: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 33 | 34 | 35 | 36 |
37 |
Header
38 | 39 |
40 |
41 |
Content
42 | 43 |
44 |
45 |
Footer
46 | 47 |
48 |
49 | 50 | 51 |

52 |
53 | 54 | 55 | 56 |
57 | 58 | : 59 | 60 |
61 |
62 |
63 | 64 | 65 |

Droggelbecher

66 |
67 | 68 |
69 | -------------------------------------------------------------------------------- /MangaLauncher/src/main/java/de/herrlock/manga/cli/options/ViewpageOptions.java: -------------------------------------------------------------------------------- 1 | package de.herrlock.manga.cli.options; 2 | 3 | import java.io.File; 4 | 5 | import org.apache.commons.cli.Option; 6 | import org.apache.commons.cli.OptionGroup; 7 | import org.apache.commons.cli.Options; 8 | 9 | /** 10 | * A set of {@linkplain Option}s 11 | * 12 | * @author HerrLock 13 | */ 14 | public final class ViewpageOptions extends SubOptions { 15 | 16 | private final Option folderOption = Option.builder() // 17 | .longOpt( "folder" ) // 18 | .hasArg() // 19 | .type( File.class ) // 20 | .desc( "The folder to create the files in" ) // 21 | .build(); 22 | private final Option htmlOption = Option.builder() // 23 | .longOpt( "html" ) // 24 | .desc( "Create html-resources" ) // 25 | .build(); 26 | private final Option archiveOption = Option.builder() // 27 | .longOpt( "archive" ) // 28 | .hasArg() // 29 | .argName( "format" ) // 30 | .desc( "Create a comicbook-archive in the given format [CBZ, CBT]" ) // 31 | .build(); 32 | private final Option cleanOption = Option.builder( "c" ) // 33 | .longOpt( "clean" ) // 34 | .desc( "Whether to remove the downloaded chapters after archiving them" ) // 35 | .build(); 36 | private final Option clearOption = Option.builder() // 37 | .longOpt( "clear" ) // 38 | .desc( "Same as \"clean\"" ) // 39 | .build(); 40 | 41 | private final OptionGroup typeGroup = new OptionGroup() // 42 | .addOption( this.htmlOption ) // 43 | .addOption( this.archiveOption ) // 44 | ; 45 | 46 | private final Options options; 47 | 48 | /** 49 | * Create new Options 50 | */ 51 | public ViewpageOptions() { 52 | this.typeGroup.setRequired( true ); 53 | this.options = new Options() // 54 | .addOptionGroup( this.typeGroup ) // 55 | .addOption( this.folderOption ) // 56 | .addOption( this.cleanOption ) // 57 | .addOption( this.clearOption ) // 58 | ; 59 | } 60 | 61 | /** 62 | * @return the Options from the class 63 | */ 64 | @Override 65 | public Options getOptions() { 66 | return this.options; 67 | } 68 | 69 | } 70 | -------------------------------------------------------------------------------- /MangaLib/src/test/java/de/herrlock/manga/downloader/dqc/TestPage.java: -------------------------------------------------------------------------------- 1 | package de.herrlock.manga.downloader.dqc; 2 | 3 | import java.io.File; 4 | import java.net.MalformedURLException; 5 | import java.net.URL; 6 | import java.util.ArrayList; 7 | import java.util.Collection; 8 | import java.util.List; 9 | 10 | import org.junit.Assert; 11 | import org.junit.Test; 12 | import org.junit.runner.RunWith; 13 | import org.junit.runners.Parameterized; 14 | import org.junit.runners.Parameterized.Parameters; 15 | 16 | /** 17 | * Test the class Page 18 | * 19 | * @author HerrLock 20 | */ 21 | @RunWith( Parameterized.class ) 22 | public class TestPage { 23 | 24 | private static final File testfile = new File( "./test" ); 25 | private final String expString; 26 | private final URL pageUrl; 27 | private final Page page; 28 | 29 | /** 30 | * @return the parameters to use for the tests 31 | * @throws MalformedURLException 32 | */ 33 | @Parameters( name = "{0}" ) 34 | public static Collection getParams() throws MalformedURLException { 35 | List result = new ArrayList<>(); 36 | for ( int i = 0; i < 20; i++ ) { 37 | Object[] o = { 38 | i, ( i < 10 ? "0" : "" ) + i, new URL( "http", "www.example.com", "/" + i ) 39 | }; 40 | result.add( o ); 41 | } 42 | return result; 43 | } 44 | 45 | /** 46 | * @param pageNumber 47 | * the page's number 48 | * @param expString 49 | * the expected filename 50 | */ 51 | public TestPage( final int pageNumber, final String expString, final URL pageUrl ) { 52 | this.expString = expString; 53 | this.pageUrl = pageUrl; 54 | this.page = new Page( pageUrl, testfile, pageNumber ); 55 | } 56 | 57 | /** 58 | * test if the generated file equals the expected value 59 | */ 60 | @Test 61 | public void testFiles() { 62 | File exp = new File( testfile, this.expString + ".jpg" ); 63 | Assert.assertEquals( this.page.getTargetFile(), exp ); 64 | } 65 | 66 | /** 67 | * Tests the method {@link Page#getUrl()} 68 | */ 69 | @Test 70 | public void testGetUrl() { 71 | Assert.assertEquals( this.pageUrl, this.page.getUrl() ); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /MangaCtrl/src/main/java/de/herrlock/manga/downloader/ConsoleDownloader.java: -------------------------------------------------------------------------------- 1 | package de.herrlock.manga.downloader; 2 | 3 | import java.io.InputStream; 4 | import java.io.PrintStream; 5 | import java.util.NoSuchElementException; 6 | import java.util.Scanner; 7 | 8 | import org.apache.logging.log4j.LogManager; 9 | import org.apache.logging.log4j.Logger; 10 | 11 | import de.herrlock.manga.util.configuration.DownloadConfiguration; 12 | 13 | /** 14 | * Starts the Download after printing informations about the number of Pictures to download to STDOUT and receiving a confirmation 15 | * the proceed by STDIN. Reads the settings from the central settings-file. 16 | * 17 | * @author HerrLock 18 | */ 19 | public final class ConsoleDownloader extends MDownloader { 20 | private static final Logger logger = LogManager.getLogger(); 21 | 22 | private final Scanner sc; 23 | private final PrintStream out; 24 | private final boolean interactive; 25 | 26 | public ConsoleDownloader( final DownloadConfiguration conf, final boolean interactive, final InputStream in, 27 | final PrintStream out ) { 28 | super( conf ); 29 | this.sc = new Scanner( in, "UTF-8" ); 30 | this.out = out; 31 | this.interactive = interactive; 32 | } 33 | 34 | public ConsoleDownloader( final DownloadConfiguration conf, final boolean interactive ) { 35 | this( conf, interactive, System.in, System.out ); 36 | } 37 | 38 | @Override 39 | public void run() { 40 | logger.traceEntry(); 41 | if ( !this.interactive || goon() ) { 42 | logger.trace( "start download" ); 43 | downloadAll(); 44 | } 45 | logger.traceExit(); 46 | } 47 | 48 | private boolean goon() { 49 | int noOfPictures = getPMCSize(); 50 | if ( noOfPictures > 0 ) { 51 | this.out.println( noOfPictures + " page" + ( noOfPictures > 1 ? "s" : "" ) + " availabile" ); 52 | this.out.println( "go on? y|n" ); 53 | try { 54 | char c = this.sc.next( ".+" ).charAt( 0 ); 55 | return c == 'y' || c == 'Y'; 56 | } catch ( NoSuchElementException ex ) { 57 | return false; 58 | } 59 | } 60 | this.out.println( "no pages availabile; exiting" ); 61 | return false; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /MangaLib/src/main/java/de/herrlock/manga/util/Progressable.java: -------------------------------------------------------------------------------- 1 | package de.herrlock.manga.util; 2 | 3 | /** 4 | * An interface for a class that contains a progress. The form as Interface is used to make sure the using class can still extend 5 | * another class. Typically this Interface is implemented following: 6 | * 7 | *
 8 |  * 
 9 |     public class Foo implements Progressable {
10 |         private int progress;
11 |         private int maxProgress;
12 |         private Collection<ProgressListener> listeners = new HashSet<>(); // your favourite Collection
13 |     
14 |         @Override
15 |         public void setProgress( int progress ) {
16 |             this.progress = progress;
17 |         }
18 |         @Override
19 |         public int getProgress() {
20 |             return this.progress;
21 |         }
22 |         @Override
23 |         public void setMaxProgress( int maxProgress ) {
24 |             this.maxProgress = maxProgress;
25 |         }
26 |         @Override
27 |         public int getMaxProgress() {
28 |             return this.maxProgress;
29 |         }
30 |         @Override
31 |         public void addProgressListener( ProgressListener listener ) {
32 |             this.listeners.add( listener );
33 |         }
34 |         @Override
35 |         public void removeProgressListener( ProgressListener listener ) {
36 |             this.listeners.remove( listener );
37 |         }
38 |     }
39 |  * 
40 |  * 
41 | * 42 | * @author HerrLock 43 | */ 44 | public interface Progressable { 45 | /** 46 | * @param progress 47 | * the new progress 48 | */ 49 | void setProgress( int progress ); 50 | /** 51 | * @return the current progress 52 | */ 53 | int getProgress(); 54 | 55 | /** 56 | * @param maxProgress 57 | * the new maximal progress 58 | */ 59 | void setMaxProgress( int maxProgress ); 60 | /** 61 | * @return the maximal progress 62 | */ 63 | int getMaxProgress(); 64 | 65 | /** 66 | * @param listener 67 | * the listener to add 68 | */ 69 | void addProgressListener( ProgressListener listener ); 70 | /** 71 | * @param listener 72 | * the listener to remove 73 | */ 74 | void removeProgressListener( ProgressListener listener ); 75 | } 76 | -------------------------------------------------------------------------------- /MangaLauncher/src/main/java/de/herrlock/manga/cli/options/ConsoleOptions.java: -------------------------------------------------------------------------------- 1 | package de.herrlock.manga.cli.options; 2 | 3 | import org.apache.commons.cli.Option; 4 | import org.apache.commons.cli.Options; 5 | 6 | /** 7 | * A set of {@linkplain Option}s 8 | * 9 | * @author HerrLock 10 | */ 11 | public final class ConsoleOptions extends SubOptions { 12 | 13 | private final Option urlOption = Option.builder( "u" ) // 14 | .longOpt( "url" ) // 15 | .hasArg() // 16 | .argName( "url" ) // 17 | .desc( "The URL to download from" ) // 18 | .build(); 19 | private final Option patternOption = Option.builder( "p" ) // 20 | .longOpt( "pattern" ) // 21 | .hasArg() // 22 | .argName( "pattern" ) // 23 | .desc( "The pattern to use" ) // 24 | .build(); 25 | private final Option timeoutOption = Option.builder( "t" ) // 26 | .longOpt( "timeout" ) // 27 | .hasArg() // 28 | .argName( "timeout" ) // 29 | .desc( "The timeout for HTTP-requests in seconds" ) // 30 | .build(); 31 | private final Option interactiveOption = Option.builder( "i" ) // 32 | .longOpt( "interactive" ) // 33 | .desc( "Interactive mode: request confirmation etc. from STDIN" ) // 34 | .build(); 35 | 36 | private final Option showHosterOption = Option.builder() // 37 | .longOpt( "hoster" ) // 38 | .desc( "List all availabile Hoster" ) // 39 | .build(); 40 | private final Option createListOption = Option.builder() // 41 | .longOpt( "list" ) // 42 | .desc( "Create a list of all availabile mangas" ) // 43 | .build(); 44 | 45 | private final Options options; 46 | 47 | /** 48 | * Create new Options 49 | */ 50 | public ConsoleOptions() { 51 | this.options = new Options() // 52 | .addOption( this.urlOption ) // 53 | .addOption( this.patternOption ) // 54 | .addOption( this.timeoutOption ) // 55 | .addOption( this.interactiveOption ) // 56 | .addOption( this.showHosterOption ) // 57 | .addOption( this.createListOption ) // 58 | ; 59 | } 60 | 61 | /** 62 | * @return the Options from the class 63 | */ 64 | @Override 65 | public Options getOptions() { 66 | return this.options; 67 | } 68 | 69 | } 70 | -------------------------------------------------------------------------------- /MangaLib/src/main/java/de/herrlock/manga/util/configuration/JDConfiguration.java: -------------------------------------------------------------------------------- 1 | package de.herrlock.manga.util.configuration; 2 | 3 | import java.io.File; 4 | import java.net.URL; 5 | import java.util.Objects; 6 | import java.util.Properties; 7 | 8 | import de.herrlock.manga.util.ChapterPattern; 9 | 10 | /** 11 | * A {@link Configuration} containing settings needed for a download via the JDowloader-plugin "folderwatch" 12 | * 13 | * @author HerrLock 14 | */ 15 | public class JDConfiguration extends DownloadConfiguration { 16 | private final File folderwatch; 17 | 18 | public static JDConfiguration create( final Properties p ) { 19 | boolean headless = _getIsHeadless( p ); 20 | URL url = _createUrl( p ); 21 | ChapterPattern pattern = _createPattern( p ); 22 | int timeout = _createTimeout( p ); 23 | File folderwatch = _createFolderwatch( p ); 24 | return new JDConfiguration( headless, url, pattern, timeout, folderwatch ); 25 | } 26 | 27 | /** 28 | * constructor for a {@link JDConfiguration} 29 | * 30 | * @param headless 31 | * if the downloader runs in cli-mode (true) or with a type of gui (false) 32 | * @param url 33 | * an {@link URL} to the manga's base-page. 34 | * @param pattern 35 | * the {@link ChapterPattern} to use. Or null to use the default {@link ChapterPattern} to download all. 36 | * @param timeout 37 | * the timeout for the http-requests. The dafult-value is used if negative. 38 | * @param folderwatch 39 | * the {@link File} pointing to the folderwatch-folder from the local JDownloader-installation 40 | */ 41 | public JDConfiguration( final boolean headless, final URL url, final ChapterPattern pattern, final int timeout, 42 | final File folderwatch ) { 43 | super( headless, url, pattern, timeout ); 44 | this.folderwatch = Objects.requireNonNull( folderwatch, "The folderwatch-folder must not be null" ); 45 | } 46 | 47 | /** 48 | * Getter for the folderwatch-folder 49 | * 50 | * @return the {@link File} that points to the folderwatch-folder from the local JJDownloader-installation from this 51 | * {@link JDConfiguration} 52 | */ 53 | public final File getFolderwatch() { 54 | return this.folderwatch; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /MangaLauncher/src/main/java/de/herrlock/manga/cli/CliOptions.java: -------------------------------------------------------------------------------- 1 | package de.herrlock.manga.cli; 2 | 3 | import java.util.ArrayDeque; 4 | import java.util.Arrays; 5 | import java.util.Queue; 6 | import java.util.Set; 7 | 8 | import org.apache.commons.cli.CommandLine; 9 | import org.apache.commons.cli.Option; 10 | 11 | import com.google.common.collect.FluentIterable; 12 | import com.google.common.collect.ImmutableSet; 13 | 14 | import de.herrlock.manga.cli.OptionParser.CommandLineContainer; 15 | import de.herrlock.manga.util.management.CliOptionsMXBean; 16 | 17 | /** 18 | * @author HerrLock 19 | */ 20 | public class CliOptions implements CliOptionsMXBean { 21 | 22 | private final String mainOption; 23 | private final String[] subOptions; 24 | private final String[] logOptions; 25 | 26 | private final Set mainOptions = ImmutableSet.of( "help", "version", "console", "dialog", "gui", "viewpage", 27 | "server" ); 28 | 29 | public CliOptions( final CommandLineContainer cmdContainer ) { 30 | this.mainOption = findMainOption( cmdContainer.getMainCmd() ); 31 | 32 | this.subOptions = findSubOptions( cmdContainer.getSubCmd() ); 33 | this.logOptions = findSubOptions( cmdContainer.getLogCmd() ); 34 | } 35 | 36 | private String findMainOption( final CommandLine commandline ) { 37 | return FluentIterable.from( this.mainOptions ).firstMatch( new OptionParser.InCommandline( commandline ) ).orNull(); 38 | } 39 | 40 | private String[] findSubOptions( final CommandLine commandline ) { 41 | Option[] options = commandline.getOptions(); 42 | Queue optionQueue = new ArrayDeque<>( options.length ); 43 | for ( Option option : options ) { 44 | if ( !this.mainOptions.contains( option.getLongOpt() ) ) { 45 | String optionWithValue = option.getLongOpt() + ( option.hasArg() ? "=" + option.getValue() : "" ); 46 | optionQueue.add( optionWithValue ); 47 | } 48 | } 49 | return optionQueue.toArray( new String[0] ); 50 | } 51 | 52 | @Override 53 | public String getMainOption() { 54 | return this.mainOption; 55 | } 56 | 57 | @Override 58 | public String[] getSubOptions() { 59 | return Arrays.copyOf( this.subOptions, this.subOptions.length ); 60 | } 61 | 62 | @Override 63 | public String[] getLogOptions() { 64 | return Arrays.copyOf( this.logOptions, this.logOptions.length ); 65 | } 66 | 67 | } 68 | -------------------------------------------------------------------------------- /MangaLib/src/main/java/de/herrlock/manga/http/server/log/Log4j2Bridge.java: -------------------------------------------------------------------------------- 1 | package de.herrlock.manga.http.server.log; 2 | 3 | import org.apache.logging.log4j.Level; 4 | import org.apache.logging.log4j.LogManager; 5 | import org.eclipse.jetty.util.log.AbstractLogger; 6 | import org.eclipse.jetty.util.log.Logger; 7 | 8 | /** 9 | * @author Herrlock 10 | */ 11 | public class Log4j2Bridge extends AbstractLogger { 12 | 13 | private final org.apache.logging.log4j.Logger logger; 14 | private final String name; 15 | 16 | public Log4j2Bridge( final Class clazz ) { 17 | this( clazz.getName() ); 18 | } 19 | 20 | public Log4j2Bridge( final String name ) { 21 | this.logger = LogManager.getLogger( name ); 22 | this.name = name; 23 | } 24 | 25 | @Override 26 | protected Logger newLogger( final String fullname ) { 27 | return new Log4j2Bridge( fullname ); 28 | } 29 | 30 | @Override 31 | public String getName() { 32 | return this.name; 33 | } 34 | 35 | @Override 36 | public void warn( final String msg, final Object... args ) { 37 | this.logger.warn( msg, args ); 38 | } 39 | 40 | @Override 41 | public void warn( final Throwable thrown ) { 42 | this.logger.catching( Level.WARN, thrown ); 43 | } 44 | 45 | @Override 46 | public void warn( final String msg, final Throwable thrown ) { 47 | this.logger.warn( msg, thrown ); 48 | } 49 | 50 | @Override 51 | public void info( final String msg, final Object... args ) { 52 | this.logger.info( msg, args ); 53 | } 54 | 55 | @Override 56 | public void info( final Throwable thrown ) { 57 | this.logger.catching( Level.INFO, thrown ); 58 | } 59 | 60 | @Override 61 | public void info( final String msg, final Throwable thrown ) { 62 | this.logger.info( msg, thrown ); 63 | } 64 | 65 | @Override 66 | public boolean isDebugEnabled() { 67 | return false; 68 | // return this.logger.isDebugEnabled(); 69 | } 70 | 71 | @Override 72 | public void setDebugEnabled( final boolean enabled ) { 73 | // TODO 74 | } 75 | 76 | @Override 77 | public void debug( final String msg, final Object... args ) { 78 | this.logger.debug( msg, args ); 79 | } 80 | 81 | @Override 82 | public void debug( final Throwable thrown ) { 83 | this.logger.catching( Level.DEBUG, thrown ); 84 | } 85 | 86 | @Override 87 | public void debug( final String msg, final Throwable thrown ) { 88 | this.logger.debug( msg, thrown ); 89 | } 90 | 91 | @Override 92 | public void ignore( final Throwable ignored ) { 93 | this.logger.catching( Level.TRACE, ignored ); 94 | } 95 | 96 | } 97 | -------------------------------------------------------------------------------- /MangaLauncher/src/main/java/de/herrlock/manga/cli/options/MainOptions.java: -------------------------------------------------------------------------------- 1 | package de.herrlock.manga.cli.options; 2 | 3 | import java.util.Properties; 4 | 5 | import org.apache.commons.cli.Option; 6 | import org.apache.commons.cli.OptionGroup; 7 | import org.apache.commons.cli.Options; 8 | 9 | /** 10 | * A set of {@linkplain Option}s 11 | * 12 | * @author HerrLock 13 | */ 14 | public final class MainOptions { 15 | 16 | private final Option consoleTypeOption = Option.builder() // 17 | .longOpt( "console" ) // 18 | .desc( "start the console-downloader" ) // 19 | .build(); 20 | private final Option dialogTypeOption = Option.builder() // 21 | .longOpt( "dialog" ) // 22 | .desc( "start the dialog-downloader" ) // 23 | .build(); 24 | private final Option viewpageTypeOption = Option.builder() // 25 | .longOpt( "viewpage" ) // 26 | .desc( "create files to view the downloaded manga" ) // 27 | .build(); 28 | private final Option serverTypeOption = Option.builder() // 29 | .longOpt( "server" ) // 30 | .desc( "start the server to listen to http-requests" ) // 31 | .build(); 32 | private final Option helpOption = Option.builder( "h" ) // 33 | .longOpt( "help" ) // 34 | .hasArg( true ) // 35 | .optionalArg( true ) // 36 | .argName( "context" ) // 37 | .desc( "show the help and exit" ) // 38 | .build(); 39 | private final Option versionOption = Option.builder() // 40 | .longOpt( "version" ) // 41 | .desc( "show the version and exit" ) // 42 | .build(); 43 | 44 | private final OptionGroup typeOptionGroup = new OptionGroup() // 45 | .addOption( this.consoleTypeOption ) // 46 | .addOption( this.dialogTypeOption ) // 47 | .addOption( this.viewpageTypeOption ) // 48 | .addOption( this.serverTypeOption ) // 49 | .addOption( this.helpOption ) // 50 | .addOption( this.versionOption ) // 51 | ; 52 | 53 | private final Options options; 54 | 55 | private final Properties defaultValues = new Properties(); 56 | 57 | /** 58 | * Create new Options 59 | */ 60 | public MainOptions() { 61 | this.typeOptionGroup.setRequired( true ); 62 | this.options = new Options().addOptionGroup( this.typeOptionGroup ); 63 | this.defaultValues.setProperty( "help", "true" ); 64 | } 65 | 66 | /** 67 | * @return the Options from the class 68 | */ 69 | public Options getOptions() { 70 | return this.options; 71 | } 72 | 73 | /** 74 | * @return the Properties containing default-values to add 75 | */ 76 | public Properties getDefaultValues() { 77 | return this.defaultValues; 78 | } 79 | 80 | } 81 | -------------------------------------------------------------------------------- /MangaLib/src/test/java/de/herrlock/manga/viewpage/TestViewPageConstants.java: -------------------------------------------------------------------------------- 1 | package de.herrlock.manga.viewpage; 2 | 3 | import static org.junit.Assert.assertFalse; 4 | import static org.junit.Assert.assertTrue; 5 | 6 | import java.io.File; 7 | import java.util.AbstractMap.SimpleEntry; 8 | import java.util.Map.Entry; 9 | 10 | import org.junit.Assert; 11 | import org.junit.Test; 12 | 13 | import de.herrlock.manga.util.StaticMethods; 14 | 15 | public class TestViewPageConstants { 16 | 17 | @Test 18 | public void testFormatManganame1() { 19 | String manganame = ViewPageConstants.formatManganame( "naruto" ); 20 | Assert.assertEquals( "naruto", manganame ); 21 | } 22 | 23 | @Test 24 | public void testFormatManganame2() { 25 | String manganame = ViewPageConstants.formatManganame( "naruto_" ); 26 | Assert.assertEquals( "naruto", manganame ); 27 | } 28 | 29 | @Test 30 | public void testFormatManganame3() { 31 | String manganame = ViewPageConstants.formatManganame( "naruto_1337" ); 32 | Assert.assertEquals( "naruto", manganame ); 33 | } 34 | 35 | @Test 36 | public void testFormatManganame4() { 37 | String manganame = ViewPageConstants.formatManganame( "naruto_1337_asd" ); 38 | Assert.assertEquals( "naruto 1337 asd", manganame ); 39 | } 40 | 41 | @Test 42 | public void testFileFilter1() { 43 | assertTrue( new ViewPageConstants.FileIsDirectoryFilter().accept( new File( "." ) ) ); 44 | } 45 | 46 | @Test 47 | public void testFileFilter2() { 48 | assertFalse( new ViewPageConstants.FileIsDirectoryFilter().accept( new File( "./build.gradle" ) ) ); 49 | } 50 | 51 | @Test 52 | public void testFileFilter3() { 53 | assertFalse( new ViewPageConstants.FileIsDirectoryFilter().accept( new File( "./doesnot.exist" ) ) ); 54 | } 55 | 56 | @Test 57 | public void testNumericComparator1() { 58 | assertTrue( ViewPageConstants.NUMERIC_FILENAME_COMPARATOR.compare( new File( "2" ), new File( "10" ) ) < 0 ); 59 | } 60 | 61 | @Test 62 | public void testNumericComparator2() { 63 | assertTrue( ViewPageConstants.NUMERIC_FILENAME_COMPARATOR.compare( new File( "2.5" ), new File( "10" ) ) < 0 ); 64 | } 65 | 66 | @Test 67 | public void testIntegerEntryComparator1() { 68 | Entry entry1 = new SimpleEntry<>( 2, "first entry" ); 69 | Entry entry2 = new SimpleEntry<>( 10, "second entry" ); 70 | assertTrue( ViewPageConstants.INTEGER_ENTRY_COMPARATOR.compare( entry1, entry2 ) < 0 ); 71 | } 72 | 73 | @Test 74 | public void testConstructor() throws ReflectiveOperationException { 75 | StaticMethods.callPrivateConstructor( ViewPageConstants.class ); 76 | } 77 | 78 | } 79 | -------------------------------------------------------------------------------- /MangaLib/src/main/java/de/herrlock/manga/jd/Crawljob.java: -------------------------------------------------------------------------------- 1 | package de.herrlock.manga.jd; 2 | 3 | import java.io.File; 4 | import java.util.ArrayList; 5 | import java.util.Collections; 6 | import java.util.List; 7 | 8 | /** 9 | * A class representing a single Crawljob-file that contains a whole Chapter 10 | * 11 | * @author HerrLock 12 | */ 13 | public final class Crawljob { 14 | 15 | private final File folder; 16 | private final String packagenumber; 17 | private final List entries = Collections.synchronizedList( new ArrayList() ); 18 | 19 | /** 20 | * creates a crawljob-file to fill with entries 21 | * 22 | * @param folder 23 | * the folder where to download the images to (relative path, eg. "./manganame_timestamp/01") 24 | * @param packagenumber 25 | * name of the JDownloader-package 26 | */ 27 | public Crawljob( final File folder, final String packagenumber ) { 28 | this.folder = folder; 29 | this.packagenumber = packagenumber; 30 | } 31 | 32 | /** 33 | * adds a resource to this Crawljob 34 | * 35 | * @param filename 36 | * the target name for the resource 37 | * @param url 38 | * the resource's URL 39 | */ 40 | public void addCrawljobEntry( final String filename, final String url ) { 41 | synchronized ( this.entries ) { 42 | this.entries.add( new CrawljobEntry( filename, url ) ); 43 | } 44 | } 45 | 46 | /** 47 | * returns the filename that the current Crawljob should be written to 48 | * 49 | * @return the preferred filename for the current Crawljob 50 | */ 51 | public String getFilename() { 52 | return this.packagenumber + ".crawljob"; 53 | } 54 | 55 | /** 56 | * creates a String that represents the current Crawljob 57 | * 58 | * @return string for the current Crawljob-object 59 | */ 60 | public String export() { 61 | String ls = System.lineSeparator(); 62 | StringBuilder sb = new StringBuilder(); 63 | for ( CrawljobEntry c : this.entries ) { 64 | sb.append( ls )// 65 | .append( "->NEW ENTRY<-" )// 66 | .append( ls )// 67 | .append( c.export() )// 68 | .append( ls )// 69 | .append( "downloadFolder=" )// 70 | .append( this.folder.getAbsolutePath() )// 71 | .append( ls )// 72 | .append( "packageName=" )// 73 | .append( this.packagenumber )// 74 | .append( ls )// 75 | .append( "addOfflineLink=true" )// 76 | .append( ls )// 77 | .append( ( char ) 0 ); 78 | } 79 | return sb.toString(); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /MangaLib/src/main/java/de/herrlock/manga/host/impl/PureManga.java: -------------------------------------------------------------------------------- 1 | package de.herrlock.manga.host.impl; 2 | 3 | import java.io.IOException; 4 | import java.net.URL; 5 | 6 | import org.jsoup.nodes.Document; 7 | import org.jsoup.nodes.Element; 8 | import org.jsoup.select.Elements; 9 | 10 | import com.google.auto.service.AutoService; 11 | 12 | import de.herrlock.manga.downloader.pmc.EntryList; 13 | import de.herrlock.manga.host.ChapterList; 14 | import de.herrlock.manga.host.HosterImpl; 15 | import de.herrlock.manga.host.annotations.ChapterListDetails; 16 | import de.herrlock.manga.host.annotations.Details; 17 | import de.herrlock.manga.util.configuration.DownloadConfiguration; 18 | 19 | @AutoService( HosterImpl.class ) 20 | @Details( name = "PureManga", baseUrl = "http://www.pure-manga.org/" ) 21 | public final class PureManga extends HosterImpl { 22 | 23 | @Override 24 | public ChapterList getChapterList( final DownloadConfiguration conf ) throws IOException { 25 | return new MangaTubeChapterList( conf ); 26 | } 27 | 28 | } 29 | 30 | @ChapterListDetails( reversed = true ) 31 | final class PureMangaChapterList extends ChapterList { 32 | private final String name; 33 | 34 | public PureMangaChapterList( final DownloadConfiguration conf ) throws IOException { 35 | super( conf ); 36 | Document document = getDocument( conf.getUrl() ); 37 | 38 | this.name = document.select( "#content h2.titlebg" ).first().text(); 39 | 40 | Elements tr = document.getElementsByClass( "element" ); 41 | for ( Element e : tr ) { 42 | Element link = e.select( "div>a" ).first(); 43 | 44 | String[] chapterNrAndName = link.text().split( ":" ); 45 | String number = chapterNrAndName[0].split( " " )[1]; 46 | 47 | URL chapterUrl = new URL( conf.getUrl(), link.attr( "href" ) ); 48 | 49 | super.addChapter( number, chapterUrl ); 50 | } 51 | } 52 | 53 | @Override 54 | public String getMangaName() { 55 | return this.name; 56 | } 57 | 58 | @Override 59 | public URL imgLink( final URL url ) throws IOException { 60 | String src = getDocument( url ).select( "#page > .inner > a > img" ).first().attr( "src" ); 61 | return new URL( url, src ); 62 | } 63 | 64 | @Override 65 | protected EntryList _getAllPageURLs( final URL url ) throws IOException { 66 | EntryList result = new EntryList<>(); 67 | Elements li = getDocument( url ).select( ".dropdown_right > ul > li" ); 68 | for ( Element e : li ) { 69 | Element link = e.getElementsByTag( "a" ).first(); 70 | int number = Integer.parseInt( link.text().substring( 6 ) ); 71 | URL absUrl = new URL( url, link.attr( "href" ) ); 72 | result.addEntry( number, absUrl ); 73 | } 74 | return result; 75 | } 76 | 77 | } 78 | -------------------------------------------------------------------------------- /MangaLib/src/main/java/de/herrlock/manga/host/impl/MangaTube.java: -------------------------------------------------------------------------------- 1 | package de.herrlock.manga.host.impl; 2 | 3 | import java.io.IOException; 4 | import java.net.URL; 5 | 6 | import org.jsoup.nodes.Document; 7 | import org.jsoup.nodes.Element; 8 | import org.jsoup.select.Elements; 9 | 10 | import com.google.auto.service.AutoService; 11 | 12 | import de.herrlock.manga.downloader.pmc.EntryList; 13 | import de.herrlock.manga.host.ChapterList; 14 | import de.herrlock.manga.host.HosterImpl; 15 | import de.herrlock.manga.host.annotations.ChapterListDetails; 16 | import de.herrlock.manga.host.annotations.Details; 17 | import de.herrlock.manga.util.configuration.DownloadConfiguration; 18 | 19 | @AutoService( HosterImpl.class ) 20 | @Details( name = "Manga-Tube", baseUrl = "http://www.manga-tube.com/" ) 21 | public final class MangaTube extends HosterImpl { 22 | 23 | @Override 24 | public ChapterList getChapterList( final DownloadConfiguration conf ) throws IOException { 25 | return new MangaTubeChapterList( conf ); 26 | } 27 | 28 | } 29 | 30 | @ChapterListDetails( reversed = true ) 31 | final class MangaTubeChapterList extends ChapterList { 32 | private final String name; 33 | 34 | public MangaTubeChapterList( final DownloadConfiguration conf ) throws IOException { 35 | super( conf ); 36 | Document document = getDocument( conf.getUrl() ); 37 | 38 | this.name = document.select( "h1.title" ).first().text(); 39 | 40 | Elements elements = document.select( "div.group > div.element" ); 41 | for ( Element e : elements ) { 42 | Element titleDiv = e.select( "div.title" ).first(); 43 | Element link = titleDiv.getElementsByTag( "a" ).first(); 44 | 45 | String[] nameAndNumber = link.text().split( " " ); 46 | String number = nameAndNumber[nameAndNumber.length - 1]; 47 | 48 | URL chapterUrl = new URL( conf.getUrl(), link.attr( "href" ) ); 49 | 50 | super.addChapter( number, chapterUrl ); 51 | } 52 | } 53 | 54 | @Override 55 | public String getMangaName() { 56 | return this.name; 57 | } 58 | 59 | @Override 60 | public URL imgLink( final URL url ) throws IOException { 61 | String src = getDocument( url ).select( "#page img" ).first().attr( "src" ); 62 | return new URL( url, src ); 63 | } 64 | 65 | @Override 66 | protected EntryList _getAllPageURLs( final URL url ) throws IOException { 67 | EntryList result = new EntryList<>(); 68 | Elements pages = getDocument( url ).select( "div.topbar_right > div > ul.dropdown > li > a" ); 69 | for ( Element e : pages ) { 70 | Integer key = Integer.valueOf( e.text().split( " " )[1] ); 71 | URL value = new URL( url, e.attr( "href" ) ); 72 | result.addEntry( key, value ); 73 | } 74 | return result; 75 | } 76 | 77 | } 78 | -------------------------------------------------------------------------------- /MangaLib/src/test/java/de/herrlock/manga/viewpage/TestViewPage.java: -------------------------------------------------------------------------------- 1 | package de.herrlock.manga.viewpage; 2 | 3 | import java.io.File; 4 | import java.io.IOException; 5 | import java.nio.file.FileVisitResult; 6 | import java.nio.file.Files; 7 | import java.nio.file.Path; 8 | import java.nio.file.Paths; 9 | import java.nio.file.SimpleFileVisitor; 10 | import java.nio.file.attribute.BasicFileAttributes; 11 | import java.util.Arrays; 12 | import java.util.Collection; 13 | 14 | import org.junit.After; 15 | import org.junit.Before; 16 | import org.junit.Test; 17 | import org.junit.runner.RunWith; 18 | import org.junit.runners.Parameterized; 19 | import org.junit.runners.Parameterized.Parameters; 20 | 21 | @RunWith( Parameterized.class ) 22 | public class TestViewPage { 23 | 24 | private static final Path testfolder = Paths.get( ".", "testFolder" ); 25 | private final int numberOfChapters; 26 | private final Path baseFolder; 27 | 28 | @Parameters( name = "{0}: {1}" ) 29 | public static Collection createParams() { 30 | return Arrays.asList( new Object[][] { 31 | { 32 | 42, "testDefault" 33 | }, { 34 | 200, "testLarge" 35 | }, { 36 | 0, "testEmpty" 37 | } 38 | } ); 39 | } 40 | 41 | public TestViewPage( final int numberOfChapters, final String baseFolder ) { 42 | this.numberOfChapters = numberOfChapters; 43 | this.baseFolder = testfolder.resolve( baseFolder ); 44 | } 45 | 46 | @Before 47 | public void setUp() throws IOException { 48 | Files.createDirectories( this.baseFolder ); 49 | for ( int i = 1; i <= this.numberOfChapters; i++ ) { 50 | Path newFolder = this.baseFolder.resolve( Integer.toString( i ) ); 51 | if ( Files.notExists( newFolder ) ) { 52 | Files.createDirectories( newFolder ); 53 | } 54 | Path newFile = newFolder.resolve( "tmp" ); 55 | if ( Files.notExists( newFile ) ) { 56 | Files.createFile( newFile ); 57 | } 58 | } 59 | } 60 | 61 | @After 62 | public void deleteFolders() throws IOException { 63 | Files.walkFileTree( this.baseFolder, new DeletingFileVisitor() ); 64 | } 65 | 66 | @Test 67 | public void runViewPage() { 68 | File file = this.baseFolder.toFile(); 69 | ViewPage.execute( file ); 70 | } 71 | 72 | private static final class DeletingFileVisitor extends SimpleFileVisitor { 73 | @Override 74 | public FileVisitResult visitFile( final Path file, final BasicFileAttributes attrs ) throws IOException { 75 | Files.delete( file ); 76 | return FileVisitResult.CONTINUE; 77 | } 78 | @Override 79 | public FileVisitResult postVisitDirectory( final Path dir, final IOException exc ) throws IOException { 80 | Files.delete( dir ); 81 | return FileVisitResult.CONTINUE; 82 | } 83 | } 84 | 85 | } 86 | -------------------------------------------------------------------------------- /MangaCtrl/src/main/java/de/herrlock/manga/viewpage/ViewGeneratorMain.java: -------------------------------------------------------------------------------- 1 | package de.herrlock.manga.viewpage; 2 | 3 | import java.io.File; 4 | import java.io.FileNotFoundException; 5 | import java.io.IOException; 6 | 7 | import javax.swing.JFileChooser; 8 | 9 | import org.apache.logging.log4j.LogManager; 10 | import org.apache.logging.log4j.Logger; 11 | 12 | /** 13 | * @author HerrLock 14 | */ 15 | public final class ViewGeneratorMain { 16 | private static final Logger logger = LogManager.getLogger(); 17 | 18 | private static File getFolder() throws IOException { 19 | // TODO 20 | JFileChooser fc = new JFileChooser( "." ); 21 | fc.setFileSelectionMode( JFileChooser.DIRECTORIES_ONLY ); 22 | int returnVal = fc.showOpenDialog( null ); 23 | logger.info( "returnVal: {}", returnVal ); 24 | logger.info( "selected: {}", fc.getSelectedFile() ); 25 | 26 | if ( returnVal == JFileChooser.APPROVE_OPTION ) { 27 | return fc.getSelectedFile(); 28 | } else if ( returnVal == JFileChooser.CANCEL_OPTION ) { 29 | throw new IOException( "Aborted" ); 30 | } else if ( returnVal == JFileChooser.ERROR_OPTION ) { 31 | throw new IOException( "Error" ); 32 | } else { 33 | throw new IllegalArgumentException(); 34 | } 35 | } 36 | 37 | private static File queryFolder() throws IOException { 38 | File file = getFolder(); 39 | if ( !file.exists() ) { 40 | throw new FileNotFoundException( "The folder \"" + file.getAbsolutePath() + "\" does not exist" ); 41 | } 42 | if ( !file.isDirectory() ) { 43 | throw new IOException( "\"" + file.getAbsolutePath() + "\" must be a folder" ); 44 | } 45 | return file; 46 | } 47 | 48 | /** 49 | * @param folder 50 | * the mangafolder to create a viewer for (has the format {@code _}) 51 | */ 52 | public static void executeViewHtml( final File folder ) { 53 | try { 54 | File folderToUse = folder == null ? queryFolder() : folder; 55 | ViewPage.execute( folderToUse ); 56 | } catch ( IOException ex ) { 57 | logger.error( ex ); 58 | } 59 | } 60 | 61 | /** 62 | * @param folder 63 | * The mangafolder to create a viewer for (has the format {@code _}) 64 | * @param format 65 | * The format of the archive to create 66 | * @param clean 67 | * Whether to remove the images after archiving them 68 | */ 69 | public static void executeViewArchive( final File folder, final String format, final boolean clean ) { 70 | try { 71 | File folderToUse = folder == null ? queryFolder() : folder; 72 | ViewArchive.execute( folderToUse, format, clean ); 73 | } catch ( IOException ex ) { 74 | logger.error( ex ); 75 | } 76 | } 77 | 78 | private ViewGeneratorMain() { 79 | // nothing to do 80 | } 81 | 82 | } 83 | -------------------------------------------------------------------------------- /MangaLib/src/test/java/de/herrlock/manga/util/TestUtils.java: -------------------------------------------------------------------------------- 1 | package de.herrlock.manga.util; 2 | 3 | import static org.junit.Assert.assertTrue; 4 | import static org.junit.Assert.fail; 5 | 6 | import java.util.Arrays; 7 | import java.util.Collection; 8 | import java.util.List; 9 | import java.util.concurrent.Callable; 10 | import java.util.concurrent.ExecutionException; 11 | import java.util.concurrent.Future; 12 | 13 | import org.junit.Test; 14 | 15 | import de.herrlock.manga.exceptions.MDRuntimeException; 16 | 17 | public class TestUtils { 18 | 19 | @Test 20 | public void testCallCallables() throws InterruptedException, ExecutionException { 21 | BoolCallable callable1 = new BoolCallable(); 22 | BoolCallable callable2 = new BoolCallable(); 23 | Collection> callables = Arrays.asList( callable1, callable2 ); 24 | List> futures = Utils.callCallables( callables ); 25 | for ( Future future : futures ) { 26 | assertTrue( future.get() ); 27 | } 28 | } 29 | 30 | @Test( expected = MDRuntimeException.class ) 31 | public void testCallCallablesInterrupted() { 32 | Callable runningCallable = new SleepingRunnable( -1 ); 33 | Callable interruptCallable = new InterruptingRunnable( Thread.currentThread() ); 34 | Collection> callables = Arrays.asList( runningCallable, interruptCallable ); 35 | Utils.callCallables( callables ); 36 | fail( "should not get here" ); 37 | } 38 | 39 | private static final class BoolCallable implements Callable { 40 | @Override 41 | public Boolean call() { 42 | return Boolean.TRUE; 43 | } 44 | } 45 | 46 | /** 47 | * A Runnable and Callable that sleeps for n seconds 48 | */ 49 | private static final class SleepingRunnable implements Runnable, Callable { 50 | private final int time; 51 | 52 | public SleepingRunnable( final int time ) { 53 | this.time = time < 0 ? 10_000 : time; 54 | } 55 | 56 | @Override 57 | public void run() { 58 | try { 59 | Thread.sleep( this.time ); 60 | } catch ( InterruptedException ex ) { 61 | throw new MDRuntimeException( ex ); 62 | } 63 | } 64 | 65 | @Override 66 | public Void call() { 67 | this.run(); 68 | return null; 69 | } 70 | } 71 | 72 | /** 73 | * A Runnable that interrupts a given Thread 74 | */ 75 | private static final class InterruptingRunnable implements Runnable, Callable { 76 | private final Thread toInterrupt; 77 | 78 | public InterruptingRunnable( final Thread toInterrupt ) { 79 | this.toInterrupt = toInterrupt; 80 | } 81 | 82 | @Override 83 | public void run() { 84 | this.toInterrupt.interrupt(); 85 | } 86 | 87 | @Override 88 | public Void call() { 89 | this.run(); 90 | return null; 91 | } 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem http://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%" == "" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%" == "" set DIRNAME=. 29 | set APP_BASE_NAME=%~n0 30 | set APP_HOME=%DIRNAME% 31 | 32 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 33 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 34 | 35 | @rem Find java.exe 36 | if defined JAVA_HOME goto findJavaFromJavaHome 37 | 38 | set JAVA_EXE=java.exe 39 | %JAVA_EXE% -version >NUL 2>&1 40 | if "%ERRORLEVEL%" == "0" goto init 41 | 42 | echo. 43 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 44 | echo. 45 | echo Please set the JAVA_HOME variable in your environment to match the 46 | echo location of your Java installation. 47 | 48 | goto fail 49 | 50 | :findJavaFromJavaHome 51 | set JAVA_HOME=%JAVA_HOME:"=% 52 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 53 | 54 | if exist "%JAVA_EXE%" goto init 55 | 56 | echo. 57 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 58 | echo. 59 | echo Please set the JAVA_HOME variable in your environment to match the 60 | echo location of your Java installation. 61 | 62 | goto fail 63 | 64 | :init 65 | @rem Get command-line arguments, handling Windows variants 66 | 67 | if not "%OS%" == "Windows_NT" goto win9xME_args 68 | 69 | :win9xME_args 70 | @rem Slurp the command line arguments. 71 | set CMD_LINE_ARGS= 72 | set _SKIP=2 73 | 74 | :win9xME_args_slurp 75 | if "x%~1" == "x" goto execute 76 | 77 | set CMD_LINE_ARGS=%* 78 | 79 | :execute 80 | @rem Setup the command line 81 | 82 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 83 | 84 | @rem Execute Gradle 85 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 86 | 87 | :end 88 | @rem End local scope for the variables with windows NT shell 89 | if "%ERRORLEVEL%"=="0" goto mainEnd 90 | 91 | :fail 92 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 93 | rem the _cmd.exe /c_ return code! 94 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 95 | exit /b 1 96 | 97 | :mainEnd 98 | if "%OS%"=="Windows_NT" endlocal 99 | 100 | :omega 101 | -------------------------------------------------------------------------------- /MangaLib/src/test/java/de/herrlock/manga/downloader/pmc/TestEntryList.java: -------------------------------------------------------------------------------- 1 | package de.herrlock.manga.downloader.pmc; 2 | 3 | import java.util.AbstractMap.SimpleImmutableEntry; 4 | import java.util.Arrays; 5 | import java.util.Iterator; 6 | import java.util.List; 7 | 8 | import org.junit.Assert; 9 | import org.junit.Test; 10 | 11 | import de.herrlock.manga.util.Constants; 12 | 13 | public class TestEntryList { 14 | 15 | @Test 16 | public void testSize1() { 17 | EntryList list = new EntryList<>(); 18 | list.addEntry( "key", "value" ); 19 | Assert.assertEquals( 1, list.size() ); 20 | } 21 | 22 | @Test 23 | public void testSize2() { 24 | EntryList list = new EntryList<>( 3 ); 25 | list.addEntry( "key", "value" ); 26 | Assert.assertEquals( 1, list.size() ); 27 | } 28 | 29 | @Test 30 | public void testSize3() { 31 | EntryList list1 = new EntryList<>(); 32 | list1.addEntry( "key1", "value1" ); 33 | EntryList list = new EntryList<>( list1 ); 34 | list.addEntry( "key", "value" ); 35 | Assert.assertEquals( 2, list.size() ); 36 | } 37 | 38 | @Test 39 | public void testSort() { 40 | EntryList list = new EntryList<>(); 41 | list.addEntry( "2", "value2" ); 42 | list.addEntry( "1", "value1" ); 43 | // check elements 44 | Iterator> iterator1 = list.iterator(); 45 | Assert.assertEquals( "value2", iterator1.next().getValue() ); 46 | Assert.assertEquals( "value1", iterator1.next().getValue() ); 47 | // sort 48 | list.sort( EntryList.getStringComparator( Constants.STRING_NUMBER_COMPARATOR ) ); 49 | // check new order 50 | Iterator> iterator2 = list.iterator(); 51 | Assert.assertEquals( "value1", iterator2.next().getValue() ); 52 | Assert.assertEquals( "value2", iterator2.next().getValue() ); 53 | } 54 | 55 | @Test 56 | public void testImmutableEntryList1() { 57 | EntryList list1 = new EntryList<>(); 58 | list1.addEntry( "key1", "value1" ); 59 | EntryList list = new ImmutableEntryList<>( list1 ); 60 | Assert.assertEquals( 1, list.size() ); 61 | } 62 | 63 | @Test 64 | public void testImmutableEntryList2() { 65 | SimpleImmutableEntry entry = new SimpleImmutableEntry<>( "key", "value" ); 66 | List> collection = Arrays.asList( entry ); 67 | EntryList list = new ImmutableEntryList<>( collection ); 68 | Assert.assertEquals( 1, list.size() ); 69 | } 70 | 71 | @Test( expected = UnsupportedOperationException.class ) 72 | public void testImmutableEntryListAddEntry() { 73 | EntryList oldList = new EntryList<>(); 74 | EntryList list = new ImmutableEntryList<>( oldList ); 75 | list.addEntry( "key1", "value1" ); 76 | Assert.fail( "previous method should have thrown an exception" ); 77 | } 78 | 79 | @Test( expected = UnsupportedOperationException.class ) 80 | public void testImmutableEntryListSort() { 81 | EntryList oldList = new EntryList<>(); 82 | EntryList list = new ImmutableEntryList<>( oldList ); 83 | list.sort( null ); 84 | Assert.fail( "previous method should have thrown an exception" ); 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /MangaLib/src/main/java/de/herrlock/manga/index/Indexer.java: -------------------------------------------------------------------------------- 1 | package de.herrlock.manga.index; 2 | 3 | import java.util.Collection; 4 | import java.util.TreeSet; 5 | 6 | import javax.json.Json; 7 | import javax.json.JsonArray; 8 | import javax.json.JsonArrayBuilder; 9 | 10 | import org.apache.logging.log4j.LogManager; 11 | import org.apache.logging.log4j.Logger; 12 | 13 | import com.google.common.collect.ImmutableSet; 14 | 15 | import de.herrlock.manga.host.Hoster; 16 | import de.herrlock.manga.host.Hosters; 17 | import de.herrlock.manga.index.entity.HosterList; 18 | import de.herrlock.manga.index.entity.HosterListEntry; 19 | import de.herrlock.manga.index.entity.Index; 20 | import de.herrlock.manga.util.configuration.IndexerConfiguration; 21 | 22 | /** 23 | * @author HerrLock 24 | */ 25 | public final class Indexer { 26 | private static final Logger logger = LogManager.getLogger(); 27 | 28 | public static JsonArray createJsonIndex( final IndexerConfiguration conf ) { 29 | Index index = createIndex( conf ); 30 | JsonArrayBuilder arrayBuilder = Json.createArrayBuilder(); 31 | for ( HosterList hosterList : index.getHosters() ) { 32 | for ( HosterListEntry hosterListEntry : hosterList.getMangas() ) { 33 | arrayBuilder.add( Json.createObjectBuilder() // 34 | .add( "hosterName", hosterList.getHosterName() ) // 35 | .add( "name", hosterListEntry.getName() ) // 36 | .add( "url", hosterListEntry.getUrl() ) ); 37 | } 38 | } 39 | return arrayBuilder.build(); 40 | } 41 | 42 | public static Index createIndex( final IndexerConfiguration conf ) { 43 | logger.traceEntry( "({})", conf ); 44 | Iterable values; 45 | if ( conf.getUrl() == null ) { 46 | values = Hosters.values(); 47 | } else { 48 | values = ImmutableSet.of( Hosters.tryGetHostByURL( conf.getUrl() ) ); 49 | } 50 | Collection hosterEntries = new TreeSet<>( HosterList.HOSTER_NAME_COMPARATOR ); 51 | for ( Hoster hoster : values ) { 52 | HosterList indexFor = createIndexFor( hoster, conf ); 53 | hosterEntries.add( indexFor ); 54 | } 55 | Index index = new Index(); 56 | index.setHosters( hosterEntries ); 57 | return index; 58 | } 59 | 60 | private static HosterList createIndexFor( final Hoster hoster, final IndexerConfiguration conf ) { 61 | logger.traceEntry( "({})", hoster ); 62 | Collection elements = hoster.getAvailabile( conf ); 63 | Collection mangas = new TreeSet<>( HosterListEntry.NAME_COMPARATOR ); 64 | mangas.addAll( elements ); 65 | // select random elements from the list 66 | // final int AMOUNT = 10; 67 | // final java.util.Random random = new java.util.Random( 68 | // Long.parseLong( new java.text.SimpleDateFormat( "yyMMdd" ).format( new java.util.Date() ) ) ); 69 | // for ( int i = 0; i < Math.min( elements.size(), AMOUNT ); i++ ) { 70 | // int rnd = random.nextInt( elements.size() ); 71 | // HosterListEntry entry = com.google.common.collect.Iterables.get( elements, rnd ); 72 | // mangas.add( entry ); 73 | // } 74 | 75 | HosterList hosterList = new HosterList(); 76 | hosterList.setHosterName( hoster.getName() ); 77 | hosterList.setMangas( mangas ); 78 | return hosterList; 79 | } 80 | 81 | private Indexer() { 82 | // avoid instantiation 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /MangaCtrl/src/main/resources/de/herrlock/manga/ui/main/MDGuiScene.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 |
33 | 34 | 38 | 39 | 1 40 | 0 41 | 42 | 49 | 50 | 51 | 52 | 53 | 1 54 | 1 55 | 56 | 63 | 64 | 65 | 66 | 67 | 1 68 | 2 69 | 70 | 77 | 78 | 79 | 80 | 81 | 1 82 | 3 83 | 84 | 85 |
86 | 87 | 88 | 89 | 0.0 90 | 0.0 91 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 87 | 88 | 89 | 90 |

91 |
92 |

93 | 113 | 114 | 115 | 116 | -------------------------------------------------------------------------------- /MangaLib/src/main/java/de/herrlock/manga/downloader/pmc/EntryList.java: -------------------------------------------------------------------------------- 1 | package de.herrlock.manga.downloader.pmc; 2 | 3 | import java.util.AbstractMap.SimpleImmutableEntry; 4 | import java.util.ArrayList; 5 | import java.util.Collection; 6 | import java.util.Collections; 7 | import java.util.Comparator; 8 | import java.util.Iterator; 9 | import java.util.List; 10 | 11 | /** 12 | * An Iterable of {@link SimpleImmutableEntry}. The entries are stored in a {@link List} 13 | * 14 | * @param 15 | * the type of the key 16 | * @param 17 | * the type of the value 18 | * 19 | * @author HerrLock 20 | */ 21 | public class EntryList implements Iterable> { 22 | private final List> entries; 23 | 24 | /** 25 | * Creates a new empty EntryList 26 | * 27 | * @see ArrayList#ArrayList() 28 | */ 29 | public EntryList() { 30 | this.entries = new ArrayList<>(); 31 | } 32 | 33 | /** 34 | * Creates a new EntryList with the given default capacity 35 | * 36 | * @param initialCapacity 37 | * The initially size of the list 38 | * 39 | * @see ArrayList#ArrayList(int) 40 | */ 41 | public EntryList( final int initialCapacity ) { 42 | this.entries = new ArrayList<>( initialCapacity ); 43 | } 44 | 45 | /** 46 | * Creates a new EntryList as a copy of the given Collection of Entries 47 | * 48 | * @param c 49 | * the collection to copy the elements from 50 | * 51 | * @see ArrayList#ArrayList(Collection) 52 | */ 53 | public EntryList( final Collection> c ) { 54 | this.entries = new ArrayList<>( c ); 55 | } 56 | 57 | /** 58 | * Creates a new EntryList as a copy of the given EntryList 59 | * 60 | * @param entryList 61 | * the entryList to copy the elements from 62 | * 63 | * @see ArrayList#ArrayList(Collection) 64 | */ 65 | public EntryList( final EntryList entryList ) { 66 | this( entryList.entries ); 67 | } 68 | 69 | /** 70 | * Adds a single Entry to the list 71 | * 72 | * @param key 73 | * the key of the new entry 74 | * @param value 75 | * the value of the new entry 76 | */ 77 | public void addEntry( final K key, final V value ) { 78 | this.entries.add( new SimpleImmutableEntry<>( key, value ) ); 79 | } 80 | 81 | /** 82 | * 83 | * @return the current number of elements 84 | */ 85 | public int size() { 86 | return this.entries.size(); 87 | } 88 | 89 | /** 90 | * Sorts the entries with the given {@link Comparator} 91 | * 92 | * @param c 93 | * the {@link Comparator} to use 94 | */ 95 | public void sort( final Comparator> c ) { 96 | Collections.sort( this.entries, c ); 97 | } 98 | 99 | /** 100 | * 101 | */ 102 | @Override 103 | public Iterator> iterator() { 104 | return this.entries.iterator(); 105 | } 106 | 107 | /** 108 | * Returns a new {@link Comparator} that uses {@link Comparator#compare(Object, Object)} of the given Comparator to compare 109 | * the keys of the entries 110 | * 111 | * @param comparator 112 | * the base-comparator 113 | * @return a new comparator 114 | */ 115 | public static Comparator> getStringComparator( final Comparator comparator ) { 116 | return new Comparator>() { 117 | @Override 118 | public int compare( final SimpleImmutableEntry o1, final SimpleImmutableEntry o2 ) { 119 | return comparator.compare( o1.getKey(), o2.getKey() ); 120 | } 121 | }; 122 | } 123 | 124 | } 125 | -------------------------------------------------------------------------------- /MangaLib/src/main/java/de/herrlock/manga/viewpage/ViewPageConstants.java: -------------------------------------------------------------------------------- 1 | package de.herrlock.manga.viewpage; 2 | 3 | import java.io.File; 4 | import java.io.FileFilter; 5 | import java.io.IOException; 6 | import java.nio.file.DirectoryStream.Filter; 7 | import java.nio.file.Files; 8 | import java.nio.file.Path; 9 | import java.util.Comparator; 10 | import java.util.Map; 11 | import java.util.Map.Entry; 12 | 13 | import com.google.common.annotations.VisibleForTesting; 14 | 15 | final class ViewPageConstants { 16 | 17 | @VisibleForTesting 18 | static String formatManganame( final String foldername ) { 19 | String mangarawname = foldername; 20 | if ( foldername.matches( ".+_\\d+" ) ) { 21 | int lastUnderscore = foldername.lastIndexOf( '_' ); 22 | if ( lastUnderscore > -1 ) { 23 | mangarawname = foldername.substring( 0, lastUnderscore ); 24 | } 25 | } 26 | return mangarawname.replace( '_', ' ' ).trim(); 27 | } 28 | 29 | /** 30 | * compares two {@code Entry}-objects by their keys 31 | */ 32 | public static final Comparator> INTEGER_ENTRY_COMPARATOR = new Comparator>() { 33 | @Override 34 | public int compare( final Entry o1, final Entry o2 ) { 35 | return o1.getKey().compareTo( o2.getKey() ); 36 | } 37 | }; 38 | 39 | /** 40 | * Compares two {@link File}s by their name. Uses {@link NumericStringComparator} for the actual comparison. 41 | */ 42 | public static final Comparator NUMERIC_FILENAME_COMPARATOR = new Comparator() { 43 | @Override 44 | public int compare( final File o1, final File o2 ) { 45 | String name1 = o1.getName(); 46 | String name2 = o2.getName(); 47 | return NUMERIC_STRING_COMPARATOR.compare( name1, name2 ); 48 | } 49 | }; 50 | 51 | /** 52 | * Compares two {@link Path}s by their filename. Uses {@link NumericStringComparator} for the actual comparison. 53 | */ 54 | public static final Comparator NUMERIC_PATHNAME_COMPARATOR = new Comparator() { 55 | @Override 56 | public int compare( final Path o1, final Path o2 ) { 57 | String name1 = String.valueOf( o1.getFileName() ); 58 | String name2 = String.valueOf( o2.getFileName() ); 59 | return NUMERIC_STRING_COMPARATOR.compare( name1, name2 ); 60 | } 61 | }; 62 | 63 | /** 64 | * Compares two {@link String}s numerically.
65 | * Tries to use {@linkplain Integer#parseInt(String)} on both Strings and returns {@linkplain Integer#compare(int, int)}. If 66 | * that fails it tries {@linkplain Double#parseDouble(String)} and returns {@linkplain Double#compare(double, double)} 67 | */ 68 | public static final Comparator NUMERIC_STRING_COMPARATOR = new Comparator() { 69 | @Override 70 | public int compare( final String name1, final String name2 ) { 71 | try { 72 | int i1 = Integer.parseInt( name1 ); 73 | int i2 = Integer.parseInt( name2 ); 74 | return Integer.compare( i1, i2 ); 75 | } catch ( final NumberFormatException ex ) { 76 | double d1 = Double.parseDouble( name1 ); 77 | double d2 = Double.parseDouble( name2 ); 78 | return Double.compare( d1, d2 ); 79 | } 80 | } 81 | }; 82 | 83 | public static final class FileIsDirectoryFilter implements FileFilter { 84 | @Override 85 | public boolean accept( final File pathname ) { 86 | return pathname.isDirectory(); 87 | } 88 | } 89 | 90 | public static class PathIsDirectoryFilter implements Filter { 91 | @Override 92 | public boolean accept( final Path entry ) throws IOException { 93 | return Files.isDirectory( entry ); 94 | } 95 | } 96 | 97 | private ViewPageConstants() { 98 | // not used 99 | } 100 | 101 | } 102 | -------------------------------------------------------------------------------- /MangaLib/src/main/java/de/herrlock/manga/util/configuration/DownloadConfiguration.java: -------------------------------------------------------------------------------- 1 | package de.herrlock.manga.util.configuration; 2 | 3 | import java.net.URL; 4 | import java.text.MessageFormat; 5 | import java.util.Objects; 6 | import java.util.Properties; 7 | 8 | import de.herrlock.manga.util.ChapterPattern; 9 | 10 | /** 11 | * A {@link Configuration} containing settings needed for http-connections 12 | * 13 | * @author HerrLock 14 | */ 15 | public class DownloadConfiguration extends Configuration { 16 | private final URL url; 17 | private final ChapterPattern pattern; 18 | private final int timeout; 19 | 20 | /** 21 | * Creates a {@link DownloadConfiguration} from the given {@link Properties} 22 | * 23 | * @param p 24 | * the {@link Properties} where to get the values from 25 | * @return a new {@link DownloadConfiguration} 26 | */ 27 | public static DownloadConfiguration create( final Properties p ) { 28 | boolean isHeadless = _getIsHeadless( p ); 29 | URL url = _createUrl( p ); 30 | ChapterPattern pattern = _createPattern( p ); 31 | int timeout = _createTimeout( p ); 32 | return new DownloadConfiguration( isHeadless, url, pattern, timeout ); 33 | } 34 | 35 | /** 36 | * Constructor for a {@link DownloadConfiguration}. If the given URL is {@code null} an exception is thrown. 37 | * 38 | * @param isHeadless 39 | * if the downloader runs in cli-mode (true) or with a type of gui (false) 40 | * @param url 41 | * an {@link URL} to the manga's base-page. 42 | * @param pattern 43 | * the {@link ChapterPattern} to use. Or null to use the default {@link ChapterPattern} to download all. 44 | * @param timeout 45 | * the timeout for the http-requests. The dafult-value is used if negative. 46 | */ 47 | public DownloadConfiguration( final boolean isHeadless, final URL url, final ChapterPattern pattern, final int timeout ) { 48 | this( isHeadless, true, url, pattern, timeout ); 49 | } 50 | 51 | /** 52 | * Constructor for a {@link DownloadConfiguration} 53 | * 54 | * @param isHeadless 55 | * if the downloader runs in cli-mode (true) or with a type of gui (false) 56 | * @param requireURL 57 | * indicates if a URL is required. An exception is thrown, if this parameter is true and the parameter url is 58 | * {@code null}. 59 | * @param url 60 | * an {@link URL} to the manga's base-page. 61 | * @param pattern 62 | * the {@link ChapterPattern} to use. Or null to use the default {@link ChapterPattern} to download all. 63 | * @param timeout 64 | * the timeout for the http-requests. The dafult-value is used if negative. 65 | */ 66 | protected DownloadConfiguration( final boolean isHeadless, final boolean requireURL, final URL url, 67 | final ChapterPattern pattern, final int timeout ) { 68 | super( isHeadless ); 69 | this.url = requireURL ? Objects.requireNonNull( url, "A URL is required." ) : url; 70 | this.pattern = pattern == null ? new ChapterPattern( "" ) : pattern; 71 | this.timeout = timeout >= 0 ? timeout : TIMEOUT_DEFAULT; 72 | } 73 | 74 | /** 75 | * Getter for the URL 76 | * 77 | * @return the {@link URL} from this {@link DownloadConfiguration} 78 | */ 79 | public final URL getUrl() { 80 | return this.url; 81 | } 82 | 83 | /** 84 | * Getter for the used pattern 85 | * 86 | * @return the {@link ChapterPattern} from this {@link DownloadConfiguration} 87 | */ 88 | public final ChapterPattern getPattern() { 89 | return this.pattern; 90 | } 91 | 92 | /** 93 | * Getter for the timeout 94 | * 95 | * @return the timeout from this {@link DownloadConfiguration} 96 | */ 97 | public int getTimeout() { 98 | return this.timeout; 99 | } 100 | 101 | @Override 102 | public String toString() { 103 | return MessageFormat.format( "URL: {0}, Pattern: {1}, Timeout: {2}", this.url, this.pattern, this.timeout ); 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /MangaLauncher/src/main/java/de/herrlock/log4j2/filter/LevelFilter.java: -------------------------------------------------------------------------------- 1 | package de.herrlock.log4j2.filter; 2 | 3 | import java.text.MessageFormat; 4 | import java.util.Objects; 5 | 6 | import org.apache.logging.log4j.Level; 7 | import org.apache.logging.log4j.Marker; 8 | import org.apache.logging.log4j.core.LogEvent; 9 | import org.apache.logging.log4j.core.Logger; 10 | import org.apache.logging.log4j.core.config.plugins.Plugin; 11 | import org.apache.logging.log4j.core.config.plugins.PluginAttribute; 12 | import org.apache.logging.log4j.core.config.plugins.PluginFactory; 13 | import org.apache.logging.log4j.core.filter.AbstractFilter; 14 | import org.apache.logging.log4j.message.Message; 15 | 16 | /** 17 | * A simple Log4j2-Filter that filters with an additional log-level. Taken and modified for personal requirements from 18 | * https://logging.apache.org/log4j/2.0/manual/extending.html#Filters 19 | */ 20 | @Plugin( name = "LevelFilter", category = "Core", elementType = "filter", printObject = true ) 21 | public final class LevelFilter extends AbstractFilter { 22 | private Level filterLevel; 23 | 24 | private LevelFilter( final Level level, final Result onMatch, final Result onMismatch ) { 25 | super( onMatch, onMismatch ); 26 | this.filterLevel = Objects.requireNonNull( level ); 27 | } 28 | 29 | /** 30 | * Simply calls {@link #filter(Level)} with the passed {@link Level}. 31 | */ 32 | @Override 33 | public Result filter( final Logger logger, final Level level, final Marker marker, final String msg, 34 | final Object... params ) { 35 | return filter( level ); 36 | } 37 | 38 | /** 39 | * Simply calls {@link #filter(Level)} with the passed {@link Level}. 40 | */ 41 | @Override 42 | public Result filter( final Logger logger, final Level level, final Marker marker, final Object msg, final Throwable t ) { 43 | return filter( level ); 44 | } 45 | 46 | /** 47 | * Simply calls {@link #filter(Level)} with the passed {@link Level}. 48 | */ 49 | @Override 50 | public Result filter( final Logger logger, final Level level, final Marker marker, final Message msg, final Throwable t ) { 51 | return filter( level ); 52 | } 53 | 54 | /** 55 | * Simply calls {@link #filter(Level)} with the level from the passed {@link LogEvent}. 56 | */ 57 | @Override 58 | public Result filter( final LogEvent event ) { 59 | return filter( event.getLevel() ); 60 | } 61 | 62 | /** 63 | * Compares the given Level with the level currently set in this filter. If the given level is more specific than this level 64 | * {@code onMatch} is returned. Otherwise {@code onMismatch} is returned. 65 | * 66 | * @param level 67 | * The level to filter on. 68 | * @return The Result of filtering. 69 | */ 70 | public Result filter( final Level level ) { 71 | return level.isMoreSpecificThan( this.filterLevel ) ? this.onMatch : this.onMismatch; 72 | } 73 | 74 | /** 75 | * Setter for the {@link Level} of this filter. 76 | * 77 | * @param level 78 | * the new {@linkplain Level} 79 | */ 80 | public void setLevel( final Level level ) { 81 | this.filterLevel = level; 82 | } 83 | 84 | @Override 85 | public String toString() { 86 | return MessageFormat.format( "LevelFilter: {0}", this.filterLevel ); 87 | } 88 | 89 | /** 90 | * Create a ThresholdFilter. 91 | * 92 | * @param level 93 | * The log Level to filter with. 94 | * @param onMatch 95 | * The action to return on a match. 96 | * @param onMismatch 97 | * The action to return on a mismatch. 98 | * @return The created ThresholdFilter. 99 | */ 100 | @PluginFactory 101 | public static LevelFilter createFilter( @PluginAttribute( value = "level", defaultString = "ERROR" ) final Level level, 102 | @PluginAttribute( value = "onMatch", defaultString = "NEUTRAL" ) final Result onMatch, 103 | @PluginAttribute( value = "onMismatch", defaultString = "DENY" ) final Result onMismatch ) { 104 | return new LevelFilter( level, onMatch, onMismatch ); 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /MangaLauncher/src/main/java/de/herrlock/manga/cli/OptionParser.java: -------------------------------------------------------------------------------- 1 | package de.herrlock.manga.cli; 2 | 3 | import java.util.Arrays; 4 | import java.util.Properties; 5 | 6 | import org.apache.commons.cli.CommandLine; 7 | import org.apache.commons.cli.Options; 8 | import org.apache.commons.cli.ParseException; 9 | 10 | import com.google.common.base.Predicate; 11 | import com.google.common.collect.FluentIterable; 12 | 13 | import de.herrlock.manga.cli.options.LogOptions; 14 | import de.herrlock.manga.cli.options.MainOptions; 15 | import de.herrlock.manga.cli.options.SubOptions; 16 | import de.herrlock.manga.cli.parser.IgnoreUnknownParser; 17 | 18 | /** 19 | * @author HerrLock 20 | */ 21 | public final class OptionParser { 22 | 23 | public static CommandLineContainer parseOptions( final String... args ) throws ParseException { 24 | CommandLineContainer cmdContainer = new CommandLineContainer(); 25 | 26 | // main-options 27 | CommandLine mainOptions = getMainOptions( args ); 28 | cmdContainer.setMainCmd( mainOptions ); 29 | 30 | // sub-options 31 | CommandLine subOptions = getSubOptions( mainOptions, args ); 32 | cmdContainer.setSubCmd( subOptions ); 33 | 34 | // log-options 35 | CommandLine logOptions = getLogOptions( args ); 36 | cmdContainer.setLogCmd( logOptions ); 37 | 38 | return cmdContainer; 39 | } 40 | 41 | private static CommandLine getMainOptions( final String... args ) throws ParseException { 42 | MainOptions mainOptions = new MainOptions(); 43 | Options options = mainOptions.getOptions(); 44 | Properties defaultValues = mainOptions.getDefaultValues(); 45 | return new IgnoreUnknownParser().parse( options, Arrays.copyOf( args, args.length ), defaultValues, false ); 46 | } 47 | 48 | private static CommandLine getSubOptions( final CommandLine mainOptions, final String... args ) throws ParseException { 49 | String givenMode = FluentIterable.of( "console", "viewpage", "server", "help", "version" ) 50 | .firstMatch( new InCommandline( mainOptions ) ).orNull(); 51 | Options options = SubOptions.getSubOptions( givenMode ).getOptions(); 52 | return new IgnoreUnknownParser().parse( options, Arrays.copyOf( args, args.length ), false ); 53 | } 54 | 55 | private static CommandLine getLogOptions( final String... args ) throws ParseException { 56 | LogOptions logOptions = new LogOptions(); 57 | Options options = logOptions.getOptions(); 58 | return new IgnoreUnknownParser().parse( options, Arrays.copyOf( args, args.length ), false ); 59 | } 60 | 61 | private OptionParser() { 62 | // prevent instantiation 63 | } 64 | 65 | /** 66 | * @author HerrLock 67 | */ 68 | public static final class InCommandline implements Predicate { 69 | private final CommandLine commandline; 70 | 71 | public InCommandline( final CommandLine commandline ) { 72 | this.commandline = commandline; 73 | } 74 | 75 | @Override 76 | public boolean apply( final String input ) { 77 | return this.commandline.hasOption( input ); 78 | } 79 | } 80 | 81 | /** 82 | * @author HerrLock 83 | */ 84 | public static class CommandLineContainer { 85 | 86 | private CommandLine mainCmd; 87 | private CommandLine subCmd; 88 | private CommandLine logCmd; 89 | 90 | CommandLineContainer() { 91 | // prevent instantiation from outside 92 | } 93 | 94 | public CommandLine getMainCmd() { 95 | return this.mainCmd; 96 | } 97 | 98 | public CommandLine getSubCmd() { 99 | return this.subCmd; 100 | } 101 | 102 | public CommandLine getLogCmd() { 103 | return this.logCmd; 104 | } 105 | 106 | void setMainCmd( final CommandLine mainCmd ) { 107 | this.mainCmd = mainCmd; 108 | } 109 | 110 | void setSubCmd( final CommandLine subCmd ) { 111 | this.subCmd = subCmd; 112 | } 113 | 114 | void setLogCmd( final CommandLine logCmd ) { 115 | this.logCmd = logCmd; 116 | } 117 | } 118 | 119 | } 120 | --------------------------------------------------------------------------------