diff --git a/src/main/java/com/pcdd/sonovel/action/Action.java b/src/main/java/com/pcdd/sonovel/action/Action.java deleted file mode 100644 index 8a55a58..0000000 --- a/src/main/java/com/pcdd/sonovel/action/Action.java +++ /dev/null @@ -1,12 +0,0 @@ -package com.pcdd.sonovel.action; - -import org.jline.terminal.Terminal; - -/** - * @author pcdd - */ -public interface Action { - - void execute(Terminal terminal); - -} diff --git a/src/main/java/com/pcdd/sonovel/action/CheckUpdateAction.java b/src/main/java/com/pcdd/sonovel/action/CheckUpdateAction.java index 47863ef..b6173ed 100644 --- a/src/main/java/com/pcdd/sonovel/action/CheckUpdateAction.java +++ b/src/main/java/com/pcdd/sonovel/action/CheckUpdateAction.java @@ -91,13 +91,14 @@ private String getDownloadUrl(String version) { private void download(String url) { // HEAD 请求不会下载文件内容,只会返回文件的元数据(例如文件大小) - long fileSize = HttpUtil.createRequest(Method.HEAD, url) + HttpResponse resp = HttpUtil.createRequest(Method.HEAD, url) .timeout(10_000) - .execute() - .contentLength(); + .execute(); + long fileSize = resp.contentLength(); + resp.close(); + // 设置进度条 ProgressBar pb = new ProgressBar("下载最新版", fileSize); - // 下载到上一级路径 File file = new File(System.getProperty("user.dir")).getParentFile(); @@ -117,10 +118,11 @@ public void progress(long total, long step) { @Override public void finish() { pb.setExtraMessage("下载完成"); - pb.close(); Console.log("<== 下载位置: {}", file + File.separator + FileUtil.getName(url)); } }); + + pb.close(); } -} +} \ No newline at end of file diff --git a/src/main/java/com/pcdd/sonovel/core/ChapterFilter.java b/src/main/java/com/pcdd/sonovel/core/ChapterFilter.java index 0120fa6..5b7689c 100644 --- a/src/main/java/com/pcdd/sonovel/core/ChapterFilter.java +++ b/src/main/java/com/pcdd/sonovel/core/ChapterFilter.java @@ -29,7 +29,7 @@ public String filter(Chapter chapter) { * 建造者类,用于动态组合过滤步骤 */ public class FilterBuilder { - private String title; + private final String title; private String content; private boolean applyEscapeFilter; private boolean applyAdsFilter; diff --git a/src/main/java/com/pcdd/sonovel/handle/EpubMergeHandler.java b/src/main/java/com/pcdd/sonovel/handle/EpubMergeHandler.java index 0965f90..5f9cbf3 100644 --- a/src/main/java/com/pcdd/sonovel/handle/EpubMergeHandler.java +++ b/src/main/java/com/pcdd/sonovel/handle/EpubMergeHandler.java @@ -24,6 +24,8 @@ */ public class EpubMergeHandler implements PostProcessingHandler { + public static final String COVER_NAME = "cover.html"; + @SneakyThrows @Override public void handle(Book b, File saveDir) { @@ -52,8 +54,7 @@ public void handle(Book b, File saveDir) { meta.setRights(List.of("本电子书由 so-novel(https://github.com/freeok/so-novel) 制作生成。仅供交流使用,不得用于商业用途。")); // 添加封面页 - book.addSection("封面", new Resource(ResourceUtil.readBytes("templates/chapter_cover.html"), - "cover.html")); + book.addSection("封面", new Resource(ResourceUtil.readBytes("templates/chapter_cover.html"), COVER_NAME)); List files = FileUtils.sortFilesByName(saveDir); int len = String.valueOf(files.size()).length(); @@ -77,7 +78,7 @@ public void handle(Book b, File saveDir) { // 设置 guide,用于指定封面 book.getGuide().addReference(new GuideReference(new Resource(ResourceUtil.readBytes("templates/chapter_cover.html"), - "cover.html"), "封面", "cover.html")); + COVER_NAME), "封面", COVER_NAME)); EpubWriter epubWriter = new EpubWriter(); String savePath = StrUtil.format("{}/{}.epub", saveDir.getParent(), b.getBookName()); diff --git a/src/main/java/com/pcdd/sonovel/parse/BookParser.java b/src/main/java/com/pcdd/sonovel/parse/BookParser.java index bdfeede..9138a80 100644 --- a/src/main/java/com/pcdd/sonovel/parse/BookParser.java +++ b/src/main/java/com/pcdd/sonovel/parse/BookParser.java @@ -29,6 +29,7 @@ public class BookParser extends Source { private static final int TIMEOUT_MILLS = 15_000; + public static final String CONTENT = "content"; public BookParser(int sourceId) { super(sourceId); @@ -41,9 +42,9 @@ public Book parse(String url) { .timeout(TIMEOUT_MILLS) .header(Header.USER_AGENT.getValue(), RandomUA.generate()) .get(); - String bookName = document.select(r.getBookName()).attr("content"); - String author = document.select(r.getAuthor()).attr("content"); - String intro = document.select(r.getIntro()).attr("content"); + String bookName = document.select(r.getBookName()).attr(CONTENT); + String author = document.select(r.getAuthor()).attr(CONTENT); + String intro = document.select(r.getIntro()).attr(CONTENT); intro = StrUtil.cleanBlank(intro); String coverUrl = document.select(r.getCoverUrl()).attr("src"); diff --git a/src/main/java/com/pcdd/sonovel/parse/ChapterParser.java b/src/main/java/com/pcdd/sonovel/parse/ChapterParser.java index 1e90c6d..00b1f6f 100644 --- a/src/main/java/com/pcdd/sonovel/parse/ChapterParser.java +++ b/src/main/java/com/pcdd/sonovel/parse/ChapterParser.java @@ -8,6 +8,7 @@ import com.pcdd.sonovel.model.ConfigBean; import com.pcdd.sonovel.model.SearchResult; import com.pcdd.sonovel.util.CrawlUtils; +import com.pcdd.sonovel.util.ExceptionUtils; import com.pcdd.sonovel.util.RandomUA; import org.jsoup.Jsoup; import org.jsoup.nodes.Document; @@ -38,6 +39,7 @@ public ChapterParser(ConfigBean config) { public Chapter parse(Chapter chapter, CountDownLatch latch, SearchResult sr) { try { Console.log("<== 正在下载: 【{}】", chapter.getTitle()); + ExceptionUtils.randomThrow(); chapter.setContent(crawl(chapter.getUrl(), false)); latch.countDown(); return chapterConverter.convert(chapter, config.getExtName()); @@ -50,7 +52,7 @@ public Chapter parse(Chapter chapter, CountDownLatch latch, SearchResult sr) { private Chapter retry(Chapter chapter, CountDownLatch latch, SearchResult sr) { for (int attempt = 1; attempt <= config.getMaxRetryAttempts(); attempt++) { try { - Console.log("==> 正在重试下载失败章节: 【{}】,尝试次数: {}/{}", chapter.getTitle(), attempt, config.getMaxRetryAttempts()); + Console.log("==> 章节下载失败,正在重试: 【{}】,尝试次数: {}/{}", chapter.getTitle(), attempt, config.getMaxRetryAttempts()); chapter.setContent(crawl(chapter.getUrl(), true)); Console.log("<== 重试成功: 【{}】", chapter.getTitle()); latch.countDown(); @@ -107,9 +109,10 @@ private void saveErrorLog(Chapter chapter, SearchResult sr, String errMsg) { try (PrintWriter pw = new PrintWriter(new FileWriter(path, true))) { // 自带换行符 pw.println(line); + } catch (IOException e) { - throw new RuntimeException(e); + Console.error(e); } } -} +} \ No newline at end of file diff --git a/src/main/java/com/pcdd/sonovel/util/CrawlUtils.java b/src/main/java/com/pcdd/sonovel/util/CrawlUtils.java index 723a7bd..4eb8c1f 100644 --- a/src/main/java/com/pcdd/sonovel/util/CrawlUtils.java +++ b/src/main/java/com/pcdd/sonovel/util/CrawlUtils.java @@ -54,7 +54,7 @@ public Connection.Method buildMethod(String method) { case "head" -> Connection.Method.HEAD; case "options" -> Connection.Method.OPTIONS; case "trace" -> Connection.Method.TRACE; - default -> Connection.Method.POST; + default -> throw new IllegalArgumentException("Unsupported request method: " + method); }; } diff --git a/src/main/java/com/pcdd/sonovel/util/ExceptionUtils.java b/src/main/java/com/pcdd/sonovel/util/ExceptionUtils.java index 01f4f23..a24d5b8 100644 --- a/src/main/java/com/pcdd/sonovel/util/ExceptionUtils.java +++ b/src/main/java/com/pcdd/sonovel/util/ExceptionUtils.java @@ -11,7 +11,9 @@ public class ExceptionUtils { // 随机抛异常,测试用 public void randomThrow() { - int i = System.currentTimeMillis() % 2 == 0 ? 0 : 1 / 0; + if (System.currentTimeMillis() % 2 == 0) { + throw new NullPointerException("随机抛 NPE"); + } } -} +} \ No newline at end of file diff --git a/src/main/java/com/pcdd/sonovel/util/FileUtils.java b/src/main/java/com/pcdd/sonovel/util/FileUtils.java index 15f9c2f..73cea38 100644 --- a/src/main/java/com/pcdd/sonovel/util/FileUtils.java +++ b/src/main/java/com/pcdd/sonovel/util/FileUtils.java @@ -5,6 +5,7 @@ import java.io.File; import java.util.Arrays; import java.util.List; +import java.util.Objects; /** * @author pcdd @@ -15,7 +16,7 @@ public class FileUtils { // 文件排序,按文件名升序 public List sortFilesByName(File dir) { - return Arrays.stream(dir.listFiles()) + return Arrays.stream(Objects.requireNonNull(dir.listFiles())) .sorted((o1, o2) -> { String s1 = o1.getName(); String s2 = o2.getName();