From a6dbe19e762bd4835f1657b76e6517aebe271e8d Mon Sep 17 00:00:00 2001 From: ZayrexDev Date: Mon, 5 Jan 2026 00:34:29 +0800 Subject: [PATCH 01/11] Refactor argument list handling in Main.java for improved readability --- src/main/java/xyz/zcraft/acgpicdownload/Main.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/xyz/zcraft/acgpicdownload/Main.java b/src/main/java/xyz/zcraft/acgpicdownload/Main.java index 0327503..52974ca 100644 --- a/src/main/java/xyz/zcraft/acgpicdownload/Main.java +++ b/src/main/java/xyz/zcraft/acgpicdownload/Main.java @@ -69,12 +69,12 @@ public static void main(String[] args) { } if (argList.isEmpty()) { GUI.start(args); - } else if (argList.get(0).equalsIgnoreCase("fetch")) { - argList.remove(0); + } else if (argList.getFirst().equalsIgnoreCase("fetch")) { + argList.removeFirst(); Fetch f = new Fetch(); f.enableConsoleProgressBar = true; f.invoke(argList, new Logger("Fetch", System.out)); - } else if (argList.get(0).equalsIgnoreCase("pixiv")) { + } else if (argList.getFirst().equalsIgnoreCase("pixiv")) { Pixiv p = new Pixiv(); p.invoke(argList, new Logger("Pixiv", System.out)); } From 3ed6a8d582d9ac36fe1a4e09a2195da2583e47db Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 11 May 2026 07:04:45 +0000 Subject: [PATCH 02/11] Implement user/ranking/search TODOs in pixiv Fetch command Agent-Logs-Url: https://github.com/ZayrexDev/ACGPicDownload/sessions/84502a8e-82b0-4633-b0ee-def3925ff21d Co-authored-by: ZayrexDev <73475219+ZayrexDev@users.noreply.github.com> --- .../commands/pixiv/sub/Fetch.java | 331 +++++++++++++++++- 1 file changed, 327 insertions(+), 4 deletions(-) diff --git a/src/main/java/xyz/zcraft/acgpicdownload/commands/pixiv/sub/Fetch.java b/src/main/java/xyz/zcraft/acgpicdownload/commands/pixiv/sub/Fetch.java index 33d5625..9576e50 100644 --- a/src/main/java/xyz/zcraft/acgpicdownload/commands/pixiv/sub/Fetch.java +++ b/src/main/java/xyz/zcraft/acgpicdownload/commands/pixiv/sub/Fetch.java @@ -4,19 +4,39 @@ import lombok.Getter; import xyz.zcraft.acgpicdownload.commands.pixiv.Profile; import xyz.zcraft.acgpicdownload.commands.pixiv.SubCommand; +import xyz.zcraft.acgpicdownload.util.pixiv.From; import xyz.zcraft.acgpicdownload.util.pixiv.PixivArtwork; import xyz.zcraft.acgpicdownload.util.pixiv.PixivFetchUtil; import java.io.IOException; +import java.util.HashSet; import java.util.LinkedList; import java.util.List; +import java.util.Set; public class Fetch extends SubCommand { private ArtProvider ap; private boolean append = false; + private static final String[][] RANKING_MAJORS = { + {"daily", "daily_r18"}, {"weekly", "weekly_r18"}, + {"monthly"}, {"rookie"}, {"original"}, + {"daily_ai", "daily_r18_ai"}, {"male", "male_r18"}, {"female", "female_r18"} + }; + private static final String[] SEARCH_SUFFIX = { + "", + "30000users入り", + "20000users入り", + "10000users入り", + "5000users入り", + "1000users入り", + "500users入り", + "300users入り", + "100users入り", + "50users入り" + }; public List invoke(List argList, Profile profile, List previous) { - if (argList.isEmpty()) { + if (argList.size() < 2) { out.err("Please specify a fetch mode: -discovery, -user, -ranking, -search"); throw new IllegalArgumentException("Please specify a fetch mode: -discovery, -user, -ranking, -search"); } @@ -79,13 +99,299 @@ public List invoke(List argList, Profile profile, List PixivFetchUtil.getDiscovery(finalDiscMode, finalCount, profile.cookie(), profile.proxyHost(), profile.proxyPort()); } case User -> { - // TODO + String uid = null; + int relatedDepth = 0; + + for (int i = 2; i < argList.size(); i++) { + if (!argList.get(i).startsWith("-")) { + if (uid == null) uid = argList.get(i); + continue; + } + switch (argList.get(i).toLowerCase()) { + case "-u", "-uid", "-user" -> { + if (argList.size() > i + 1) { + i++; + uid = argList.get(i); + } else { + out.err("Please specify user uid"); + throw new IllegalArgumentException("Please specify user uid"); + } + } + case "-r", "-related" -> { + if (argList.size() > i + 1) { + i++; + relatedDepth = Integer.parseInt(argList.get(i)); + if (relatedDepth < 0) { + out.err("Related depth must be >= 0"); + throw new IllegalArgumentException("Related depth must be >= 0"); + } + } else { + out.err("Please specify related depth"); + throw new IllegalArgumentException("Please specify related depth"); + } + } + case "-a", "-append" -> append = true; + } + } + + if (uid == null || uid.trim().isEmpty()) { + out.err("Please specify user uid"); + throw new IllegalArgumentException("Please specify user uid"); + } + uid = uid.trim(); + if (uid.startsWith("https://www.pixiv.net/users/")) { + uid = uid.substring(uid.lastIndexOf("/") + 1); + } + final String finalUid = uid; + final int finalRelatedDepth = relatedDepth; + + out.info("Ready to get user artworks: uid=" + finalUid + ",relatedDepth=" + finalRelatedDepth + + (profile.proxyHost() != null ? ",proxy=" + profile.proxyHost() + ":" + profile.proxyPort() : "")); + + ap = () -> { + Set artIDs = PixivFetchUtil.fetchUser(finalUid, profile.proxyHost(), profile.proxyPort()); + List queryString = PixivFetchUtil.buildQueryString(artIDs); + LinkedList pixivArtworks = new LinkedList<>(); + for (String s : queryString) { + pixivArtworks.addAll(PixivFetchUtil.getUserArtworks(s, finalUid, profile.proxyHost(), profile.proxyPort())); + } + fetchRelatedArtworks(pixivArtworks, finalRelatedDepth, profile); + return pixivArtworks; + }; } case Ranking -> { - // TODO + String major = "daily"; + String minor = ""; + boolean r18 = false; + + for (int i = 2; i < argList.size(); i++) { + if (!argList.get(i).startsWith("-")) continue; + switch (argList.get(i).toLowerCase()) { + case "-major" -> { + if (argList.size() > i + 1) { + i++; + major = argList.get(i).toLowerCase(); + } else { + out.err("Please specify ranking major"); + throw new IllegalArgumentException("Please specify ranking major"); + } + } + case "-minor" -> { + if (argList.size() > i + 1) { + i++; + minor = argList.get(i).toLowerCase(); + } else { + out.err("Please specify ranking minor"); + throw new IllegalArgumentException("Please specify ranking minor"); + } + } + case "-r18" -> r18 = true; + case "-a", "-append" -> append = true; + } + } + + int majorIdx = switch (major) { + case "daily" -> 0; + case "weekly" -> 1; + case "monthly" -> 2; + case "rookie" -> 3; + case "original" -> 4; + case "daily_ai" -> 5; + case "male" -> 6; + case "female" -> 7; + default -> -1; + }; + if (majorIdx < 0) { + out.err("Unknown ranking major: " + major); + throw new IllegalArgumentException("Unknown ranking major: " + major); + } + if (r18 && RANKING_MAJORS[majorIdx].length == 1) { + out.err("Ranking major does not support r18: " + major); + throw new IllegalArgumentException("Ranking major does not support r18: " + major); + } + + Set allowedMinor = new HashSet<>(List.of("")); + if (majorIdx == 0 || majorIdx == 1 || majorIdx == 2 || majorIdx == 3) { + allowedMinor.add("illust"); + allowedMinor.add("manga"); + } + if (majorIdx == 0 || majorIdx == 1) { + allowedMinor.add("ugoira"); + } + if (!allowedMinor.contains(minor)) { + out.err("Invalid ranking minor " + minor + " for major " + major); + throw new IllegalArgumentException("Invalid ranking minor " + minor + " for major " + major); + } + + final String finalMajor = RANKING_MAJORS[majorIdx][r18 ? 1 : 0]; + final String finalMinor = minor; + final String rankingInfoPrefix = finalMajor + (finalMinor.isEmpty() ? "" : "-" + finalMinor); + out.info("Ready to get ranking: major=" + finalMajor + ",minor=" + (finalMinor.isEmpty() ? "all" : finalMinor) + + (profile.proxyHost() != null ? ",proxy=" + profile.proxyHost() + ":" + profile.proxyPort() : "")); + + ap = () -> { + LinkedList ids = PixivFetchUtil.getRankingIDs(finalMajor, finalMinor, profile.cookie(), profile.proxyHost(), profile.proxyPort()); + LinkedList pixivArtworks = new LinkedList<>(); + int failed = 0; + for (int idx = 0; idx < ids.size(); idx++) { + int tries = 0; + while (tries <= 5) { + try { + PixivArtwork a = PixivFetchUtil.getArtwork(ids.get(idx), profile.cookie(), profile.proxyHost(), profile.proxyPort()); + a.setFrom(From.Ranking); + a.setRanking(rankingInfoPrefix + "#" + (idx + 1)); + pixivArtworks.add(a); + break; + } catch (Exception e) { + tries++; + if (tries > 5) { + failed++; + out.warn("Failed to fetch ranking artwork id=" + ids.get(idx)); + break; + } + try { + Thread.sleep(2000); + } catch (InterruptedException ignored) { + } + } + } + } + if (failed > 0) { + out.warn("Failed to fetch " + failed + " ranking artworks."); + } + return pixivArtworks; + }; } case Search -> { - // TODO + String keyword = null; + String type = "top"; + int searchMode = 0; + int page = 1; + int relatedDepth = 0; + String suffix = ""; + + for (int i = 2; i < argList.size(); i++) { + if (!argList.get(i).startsWith("-")) { + if (keyword == null) keyword = argList.get(i); + continue; + } + switch (argList.get(i).toLowerCase()) { + case "-k", "-kw", "-keyword" -> { + if (argList.size() > i + 1) { + i++; + keyword = argList.get(i); + } else { + out.err("Please specify search keyword"); + throw new IllegalArgumentException("Please specify search keyword"); + } + } + case "-t", "-type" -> { + if (argList.size() > i + 1) { + i++; + type = argList.get(i).toLowerCase(); + } else { + out.err("Please specify search type: top|illust|manga"); + throw new IllegalArgumentException("Please specify search type: top|illust|manga"); + } + } + case "-m", "-mode" -> { + if (argList.size() > i + 1) { + i++; + String modeValue = argList.get(i).toLowerCase(); + searchMode = switch (modeValue) { + case "all" -> 0; + case "safe" -> 1; + case "r18", "adult" -> 2; + default -> -1; + }; + if (searchMode < 0) { + out.err("Unknown search mode: " + modeValue); + throw new IllegalArgumentException("Unknown search mode: " + modeValue); + } + } else { + out.err("Please specify search mode: all|safe|r18"); + throw new IllegalArgumentException("Please specify search mode: all|safe|r18"); + } + } + case "-p", "-page" -> { + if (argList.size() > i + 1) { + i++; + page = Integer.parseInt(argList.get(i)); + if (page < 1) { + out.err("Page must be >= 1"); + throw new IllegalArgumentException("Page must be >= 1"); + } + } else { + out.err("Please specify page number"); + throw new IllegalArgumentException("Please specify page number"); + } + } + case "-s", "-suffix" -> { + if (argList.size() > i + 1) { + i++; + String suffixArg = argList.get(i); + try { + int suffixIdx = Integer.parseInt(suffixArg); + if (suffixIdx < 0 || suffixIdx >= SEARCH_SUFFIX.length) { + out.err("Suffix index must be between 0 and " + (SEARCH_SUFFIX.length - 1)); + throw new IllegalArgumentException("Suffix index must be between 0 and " + (SEARCH_SUFFIX.length - 1)); + } + suffix = SEARCH_SUFFIX[suffixIdx]; + } catch (NumberFormatException ignored) { + suffix = suffixArg; + } + } else { + out.err("Please specify suffix or suffix index"); + throw new IllegalArgumentException("Please specify suffix or suffix index"); + } + } + case "-r", "-related" -> { + if (argList.size() > i + 1) { + i++; + relatedDepth = Integer.parseInt(argList.get(i)); + if (relatedDepth < 0) { + out.err("Related depth must be >= 0"); + throw new IllegalArgumentException("Related depth must be >= 0"); + } + } else { + out.err("Please specify related depth"); + throw new IllegalArgumentException("Please specify related depth"); + } + } + case "-a", "-append" -> append = true; + } + } + + if (keyword == null || keyword.trim().isEmpty()) { + out.err("Please specify search keyword"); + throw new IllegalArgumentException("Please specify search keyword"); + } + if (!List.of("top", "illust", "manga").contains(type)) { + out.err("Unknown search type: " + type); + throw new IllegalArgumentException("Unknown search type: " + type); + } + + final String finalKeyword = keyword + suffix; + final String finalType = type; + final int finalSearchMode = searchMode; + final int finalPage = page; + final int finalRelatedDepth = relatedDepth; + + out.info("Ready to search: keyword=" + finalKeyword + ",type=" + finalType + + (finalType.equals("top") ? "" : ",mode=" + PixivFetchUtil.DISCOVERY_MODES[finalSearchMode] + ",page=" + finalPage) + + ",relatedDepth=" + finalRelatedDepth + + (profile.proxyHost() != null ? ",proxy=" + profile.proxyHost() + ":" + profile.proxyPort() : "")); + + ap = () -> { + LinkedList pixivArtworks = new LinkedList<>(); + switch (finalType) { + case "top" -> pixivArtworks.addAll(PixivFetchUtil.searchTopArtworks(finalKeyword, profile.cookie(), profile.proxyHost(), profile.proxyPort())); + case "illust" -> pixivArtworks.addAll(PixivFetchUtil.searchIllustArtworks(finalKeyword, finalSearchMode, finalPage, profile.cookie(), profile.proxyHost(), profile.proxyPort())); + case "manga" -> pixivArtworks.addAll(PixivFetchUtil.searchMangaArtworks(finalKeyword, finalSearchMode, finalPage, profile.cookie(), profile.proxyHost(), profile.proxyPort())); + } + fetchRelatedArtworks(pixivArtworks, finalRelatedDepth, profile); + return pixivArtworks; + }; } } @@ -141,6 +447,23 @@ public List invoke(List argList, Profile profile, List artworks, int depth, Profile profile) throws IOException { + if (depth <= 0) return; + List currentLayer = new LinkedList<>(artworks); + for (int i = 0; i < depth; i++) { + List nextLayer = new LinkedList<>(); + for (PixivArtwork artwork : currentLayer) { + try { + nextLayer.addAll(PixivFetchUtil.getRelated(artwork, 18, profile.cookie(), profile.proxyHost(), profile.proxyPort())); + } catch (IOException e) { + // ignore a single artwork and continue to fetch other related artworks + } + } + artworks.addAll(nextLayer); + currentLayer = nextLayer; + } + } + public enum Mode { Discovery, User, Ranking, Search; From 28f8fba0afde402e41cd87271a3be5511ade7e0c Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 11 May 2026 07:08:58 +0000 Subject: [PATCH 03/11] Implement Pixiv CLI fetch modes (user/ranking/search) by porting GUI fetch behavior Agent-Logs-Url: https://github.com/ZayrexDev/ACGPicDownload/sessions/84502a8e-82b0-4633-b0ee-def3925ff21d Co-authored-by: ZayrexDev <73475219+ZayrexDev@users.noreply.github.com> --- .../commands/pixiv/sub/Fetch.java | 39 ++++++++++++------- 1 file changed, 25 insertions(+), 14 deletions(-) diff --git a/src/main/java/xyz/zcraft/acgpicdownload/commands/pixiv/sub/Fetch.java b/src/main/java/xyz/zcraft/acgpicdownload/commands/pixiv/sub/Fetch.java index 9576e50..293a5e7 100644 --- a/src/main/java/xyz/zcraft/acgpicdownload/commands/pixiv/sub/Fetch.java +++ b/src/main/java/xyz/zcraft/acgpicdownload/commands/pixiv/sub/Fetch.java @@ -17,6 +17,9 @@ public class Fetch extends SubCommand { private ArtProvider ap; private boolean append = false; + private static final int RANKING_MAX_RETRY_ATTEMPTS = 5; + private static final int RANKING_RETRY_DELAY_MS = 2000; + private static final int RELATED_ARTWORKS_LIMIT = 18; private static final String[][] RANKING_MAJORS = { {"daily", "daily_r18"}, {"weekly", "weekly_r18"}, {"monthly"}, {"rookie"}, {"original"}, @@ -142,6 +145,10 @@ public List invoke(List argList, Profile profile, List= 0) uid = uid.substring(0, splitIdx); + splitIdx = uid.indexOf('#'); + if (splitIdx >= 0) uid = uid.substring(0, splitIdx); final String finalUid = uid; final int finalRelatedDepth = relatedDepth; @@ -206,8 +213,8 @@ public List invoke(List argList, Profile profile, List allowedMinor = new HashSet<>(List.of("")); @@ -234,27 +241,30 @@ public List invoke(List argList, Profile profile, List pixivArtworks = new LinkedList<>(); int failed = 0; for (int idx = 0; idx < ids.size(); idx++) { - int tries = 0; - while (tries <= 5) { + boolean success = false; + for (int attempt = 1; attempt <= RANKING_MAX_RETRY_ATTEMPTS; attempt++) { try { PixivArtwork a = PixivFetchUtil.getArtwork(ids.get(idx), profile.cookie(), profile.proxyHost(), profile.proxyPort()); a.setFrom(From.Ranking); a.setRanking(rankingInfoPrefix + "#" + (idx + 1)); pixivArtworks.add(a); + success = true; break; } catch (Exception e) { - tries++; - if (tries > 5) { - failed++; - out.warn("Failed to fetch ranking artwork id=" + ids.get(idx)); - break; - } + if (attempt == RANKING_MAX_RETRY_ATTEMPTS) break; try { - Thread.sleep(2000); - } catch (InterruptedException ignored) { + Thread.sleep(RANKING_RETRY_DELAY_MS); + } catch (InterruptedException interruptedException) { + out.warn("Ranking fetch interrupted during retry delay for artwork id=" + ids.get(idx)); + Thread.currentThread().interrupt(); + break; } } } + if (!success) { + failed++; + out.warn("Failed to fetch ranking artwork id=" + ids.get(idx)); + } } if (failed > 0) { out.warn("Failed to fetch " + failed + " ranking artworks."); @@ -339,6 +349,7 @@ public List invoke(List argList, Profile profile, List artworks, int depth, List nextLayer = new LinkedList<>(); for (PixivArtwork artwork : currentLayer) { try { - nextLayer.addAll(PixivFetchUtil.getRelated(artwork, 18, profile.cookie(), profile.proxyHost(), profile.proxyPort())); + nextLayer.addAll(PixivFetchUtil.getRelated(artwork, RELATED_ARTWORKS_LIMIT, profile.cookie(), profile.proxyHost(), profile.proxyPort())); } catch (IOException e) { - // ignore a single artwork and continue to fetch other related artworks + out.warn(String.format("Failed to fetch related artworks for id=%s: %s", artwork.getId(), e.getMessage())); } } artworks.addAll(nextLayer); From 2e9cfa38535435f20d08eb9bc1b20d1560255a3e Mon Sep 17 00:00:00 2001 From: Zayrex Date: Mon, 11 May 2026 15:15:31 +0800 Subject: [PATCH 04/11] Change fetchRelatedArtworks method to instance method --- .../xyz/zcraft/acgpicdownload/commands/pixiv/sub/Fetch.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/xyz/zcraft/acgpicdownload/commands/pixiv/sub/Fetch.java b/src/main/java/xyz/zcraft/acgpicdownload/commands/pixiv/sub/Fetch.java index 293a5e7..99c0a09 100644 --- a/src/main/java/xyz/zcraft/acgpicdownload/commands/pixiv/sub/Fetch.java +++ b/src/main/java/xyz/zcraft/acgpicdownload/commands/pixiv/sub/Fetch.java @@ -458,7 +458,7 @@ public List invoke(List argList, Profile profile, List artworks, int depth, Profile profile) throws IOException { + private void fetchRelatedArtworks(List artworks, int depth, Profile profile) throws IOException { if (depth <= 0) return; List currentLayer = new LinkedList<>(artworks); for (int i = 0; i < depth; i++) { From d9d2a9362225c335043f01789a9f7da2819e28d3 Mon Sep 17 00:00:00 2001 From: Zayrex Date: Mon, 11 May 2026 15:35:12 +0800 Subject: [PATCH 05/11] Update Fetch.java --- .../zcraft/acgpicdownload/commands/pixiv/sub/Fetch.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/main/java/xyz/zcraft/acgpicdownload/commands/pixiv/sub/Fetch.java b/src/main/java/xyz/zcraft/acgpicdownload/commands/pixiv/sub/Fetch.java index 99c0a09..ba29ecd 100644 --- a/src/main/java/xyz/zcraft/acgpicdownload/commands/pixiv/sub/Fetch.java +++ b/src/main/java/xyz/zcraft/acgpicdownload/commands/pixiv/sub/Fetch.java @@ -439,7 +439,12 @@ public List invoke(List argList, Profile profile, List(); + if (append && previous != null) { + out.info("Appending to previous " + previous.size() + " artworks, total " + (previous.size() + art.size()) + " artworks."); + return previous; + } else { + return new LinkedList<>(); + } } System.out.println("\033[32mGot " + art.size() + " artworks\033[0m"); From 98fb806e680d9f4428e6e7e8d6937d8a59d63bf9 Mon Sep 17 00:00:00 2001 From: Zayrex Date: Mon, 11 May 2026 15:52:45 +0800 Subject: [PATCH 06/11] Return immutable list when appending artwork data Change return type to an immutable list when appending. --- .../java/xyz/zcraft/acgpicdownload/commands/pixiv/sub/Load.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/xyz/zcraft/acgpicdownload/commands/pixiv/sub/Load.java b/src/main/java/xyz/zcraft/acgpicdownload/commands/pixiv/sub/Load.java index 16a62c7..678c100 100644 --- a/src/main/java/xyz/zcraft/acgpicdownload/commands/pixiv/sub/Load.java +++ b/src/main/java/xyz/zcraft/acgpicdownload/commands/pixiv/sub/Load.java @@ -46,7 +46,7 @@ public List invoke(List argList, Profile profile, List Date: Mon, 11 May 2026 15:58:55 +0800 Subject: [PATCH 07/11] Refactor artwork data merging logic in Load.java --- .../xyz/zcraft/acgpicdownload/commands/pixiv/sub/Load.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main/java/xyz/zcraft/acgpicdownload/commands/pixiv/sub/Load.java b/src/main/java/xyz/zcraft/acgpicdownload/commands/pixiv/sub/Load.java index 678c100..808a329 100644 --- a/src/main/java/xyz/zcraft/acgpicdownload/commands/pixiv/sub/Load.java +++ b/src/main/java/xyz/zcraft/acgpicdownload/commands/pixiv/sub/Load.java @@ -45,8 +45,10 @@ public List invoke(List argList, Profile profile, List(); + result.addAll(previous); + result.addAll(list); + return List.copyOf(result); } else { return list; } From 9e1599478479b077427cb96f473435e92636f34a Mon Sep 17 00:00:00 2001 From: Zayrex Date: Mon, 11 May 2026 16:00:10 +0800 Subject: [PATCH 08/11] Update Load.java --- .../java/xyz/zcraft/acgpicdownload/commands/pixiv/sub/Load.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/xyz/zcraft/acgpicdownload/commands/pixiv/sub/Load.java b/src/main/java/xyz/zcraft/acgpicdownload/commands/pixiv/sub/Load.java index 808a329..1e2bd3d 100644 --- a/src/main/java/xyz/zcraft/acgpicdownload/commands/pixiv/sub/Load.java +++ b/src/main/java/xyz/zcraft/acgpicdownload/commands/pixiv/sub/Load.java @@ -8,6 +8,7 @@ import java.nio.file.Files; import java.nio.file.Path; import java.util.List; +import java.util.LinkedList; public class Load extends SubCommand { private String fileName; From c88c267243fddc12d4e57a1af00202b7420e3912 Mon Sep 17 00:00:00 2001 From: Zayrex Date: Mon, 11 May 2026 16:07:06 +0800 Subject: [PATCH 09/11] Update Load.java --- .../xyz/zcraft/acgpicdownload/commands/pixiv/sub/Load.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/java/xyz/zcraft/acgpicdownload/commands/pixiv/sub/Load.java b/src/main/java/xyz/zcraft/acgpicdownload/commands/pixiv/sub/Load.java index 1e2bd3d..631b076 100644 --- a/src/main/java/xyz/zcraft/acgpicdownload/commands/pixiv/sub/Load.java +++ b/src/main/java/xyz/zcraft/acgpicdownload/commands/pixiv/sub/Load.java @@ -41,7 +41,10 @@ public List invoke(List argList, Profile profile, List list = JSONArray.parseArray(s, PixivArtwork.class); + final List list = JSONArray.parseArray(s, PixivArtwork.class) + .stream() + .filter(e -> e != null) + .toList(); out.info("Read " + list.size() + " artwork data from file: " + fileName); if (append && previous != null && !previous.isEmpty()) { From a37ea85148867abfc7847183d311cb109a482e36 Mon Sep 17 00:00:00 2001 From: Zayrex Date: Mon, 11 May 2026 16:14:49 +0800 Subject: [PATCH 10/11] Refactor artwork data saving to use original JSON --- .../xyz/zcraft/acgpicdownload/commands/pixiv/sub/Save.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/main/java/xyz/zcraft/acgpicdownload/commands/pixiv/sub/Save.java b/src/main/java/xyz/zcraft/acgpicdownload/commands/pixiv/sub/Save.java index 052ed0b..36a8cbf 100644 --- a/src/main/java/xyz/zcraft/acgpicdownload/commands/pixiv/sub/Save.java +++ b/src/main/java/xyz/zcraft/acgpicdownload/commands/pixiv/sub/Save.java @@ -52,11 +52,10 @@ public List invoke(List argList, Profile profile, List>) e -> Stream.of(e.getOrigJson()) - ).toList() + previous , (format ? new JSONWriter.Feature[]{JSONWriter.Feature.PrettyFormat} : new JSONWriter.Feature[]{})) ); out.info("File written to " + fileName); From 4cf66b9567f2f85f69671963bba14e312e26b793 Mon Sep 17 00:00:00 2001 From: ZayrexDev Date: Mon, 11 May 2026 18:53:49 +0800 Subject: [PATCH 11/11] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=91=BD=E4=BB=A4?= =?UTF-8?q?=E8=A1=8C=E6=97=A0=E6=B3=95=E4=B8=8B=E8=BD=BD=E7=9A=84=E9=97=AE?= =?UTF-8?q?=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../commands/pixiv/sub/Complete.java | 2 +- .../acgpicdownload/util/dl/DownloadUtil.java | 18 +++++++++------- .../acgpicdownload/util/pixiv/NamingRule.java | 6 +++--- .../util/pixiv/PixivAccount.java | 2 +- .../util/pixiv/PixivArtwork.java | 21 ++++++++++++------- .../util/pixiv/PixivFetchUtil.java | 5 ----- 6 files changed, 29 insertions(+), 25 deletions(-) diff --git a/src/main/java/xyz/zcraft/acgpicdownload/commands/pixiv/sub/Complete.java b/src/main/java/xyz/zcraft/acgpicdownload/commands/pixiv/sub/Complete.java index 748dc14..f0e56ea 100644 --- a/src/main/java/xyz/zcraft/acgpicdownload/commands/pixiv/sub/Complete.java +++ b/src/main/java/xyz/zcraft/acgpicdownload/commands/pixiv/sub/Complete.java @@ -48,7 +48,7 @@ public List invoke(List argList, Profile profile, List result = new LinkedList<>(); previous.stream().filter(p -> p.getLikeCount() != 0 || p.getBookmarkData() != null).forEach(result::add); - final List list = previous.stream().filter(p -> p.getLikeCount() == 0 && p.getBookmarkData() == null).toList(); + final List list = previous.stream().filter(a -> !a.isComplete()).toList(); final List failedList = new LinkedList<>(); out.info("Got " + list.size() + " artworks to complete data."); diff --git a/src/main/java/xyz/zcraft/acgpicdownload/util/dl/DownloadUtil.java b/src/main/java/xyz/zcraft/acgpicdownload/util/dl/DownloadUtil.java index 28ec3f0..daa8c44 100644 --- a/src/main/java/xyz/zcraft/acgpicdownload/util/dl/DownloadUtil.java +++ b/src/main/java/xyz/zcraft/acgpicdownload/util/dl/DownloadUtil.java @@ -1,5 +1,6 @@ package xyz.zcraft.acgpicdownload.util.dl; +import com.alibaba.fastjson2.JSONObject; import com.alibaba.fastjson2.JSONWriter.Feature; import com.madgag.gif.fmsware.AnimatedGifEncoder; import org.jetbrains.annotations.NotNull; @@ -11,6 +12,7 @@ import javax.imageio.ImageIO; import java.io.*; import java.net.HttpURLConnection; +import java.net.URI; import java.net.URL; import java.net.URLConnection; import java.nio.charset.StandardCharsets; @@ -29,7 +31,7 @@ public static void download(File file, String link, String referer) throws IOExc InputStream is = null; FileOutputStream fos = null; try { - URL url = new URL(link); + URL url = URI.create(link).toURL(); HttpURLConnection c = (HttpURLConnection) url.openConnection(); if (referer != null) { @@ -77,7 +79,7 @@ public void download(Result r, File toDic, DownloadResult d, boolean saveFullRes } } - URL url = new URL(r.getUrl()); + URL url = URI.create(r.getUrl()).toURL(); URLConnection c = url.openConnection(); if (referer != null) { @@ -174,7 +176,7 @@ private void downloadPixivGif(@NotNull PixivDownload a, File toDic, String cooki return; } } - URL url = new URL(gifData.getSrc()); + URL url = URI.create(gifData.getSrc()).toURL(); URLConnection c = url.openConnection(); c.setRequestProperty("Referer", PixivDownloadUtil.REFERER); final InputStream inputStream = c.getInputStream(); @@ -198,11 +200,11 @@ private void downloadPixivGif(@NotNull PixivDownload a, File toDic, String cooki age.finish(); - if (fullResult && a.getArtwork().getOrigJson() != null) { + if (fullResult) { File jsonf = new File(toDic, namingRule.name(a.getArtwork()).concat(".json")); BufferedOutputStream jsonos = new BufferedOutputStream(new FileOutputStream(jsonf)); - String str = a.getArtwork().getOrigJson().toJSONString(Feature.PrettyFormat); + String str = JSONObject.from(a.getArtwork()).toJSONString(Feature.PrettyFormat); jsonos.write(str.getBytes(StandardCharsets.UTF_8)); jsonos.flush(); jsonos.close(); @@ -252,7 +254,7 @@ private void downloadPixivIllusion(@NotNull PixivDownload a, File toDic, String for (int i = 0, pagesSize = pages.size(); i < pagesSize; i++) { a.setProgress(i); String s = pages.get(i); - URL url = new URL(s); + URL url = URI.create(s).toURL(); URLConnection c = url.openConnection(); c.setRequestProperty("Referer", PixivDownloadUtil.REFERER); @@ -277,11 +279,11 @@ private void downloadPixivIllusion(@NotNull PixivDownload a, File toDic, String fos.close(); } - if (fullResult && a.getArtwork().getOrigJson() != null) { + if (fullResult) { File jsonf = new File(toDic, namingRule.name(a.getArtwork()).concat(".json")); BufferedOutputStream jsonos = new BufferedOutputStream(new FileOutputStream(jsonf)); - String str = a.getArtwork().getOrigJson().toJSONString(Feature.PrettyFormat); + String str = JSONObject.from(a.getArtwork()).toJSONString(Feature.PrettyFormat); jsonos.write(str.getBytes(StandardCharsets.UTF_8)); jsonos.flush(); jsonos.close(); diff --git a/src/main/java/xyz/zcraft/acgpicdownload/util/pixiv/NamingRule.java b/src/main/java/xyz/zcraft/acgpicdownload/util/pixiv/NamingRule.java index 99d2af2..5bfef47 100644 --- a/src/main/java/xyz/zcraft/acgpicdownload/util/pixiv/NamingRule.java +++ b/src/main/java/xyz/zcraft/acgpicdownload/util/pixiv/NamingRule.java @@ -5,7 +5,7 @@ public record NamingRule(String rule, int multiP, String folderRule) { public String name(PixivArtwork artwork, int p) { - JSONObject clone = artwork.getOrigJson().clone(); + JSONObject clone = JSONObject.from(artwork); if (p != -1) { clone.put("p", p); clone.put("dp", "0".repeat(Math.max(4 - String.valueOf(p).length(), 0)).concat(String.valueOf(p))); @@ -14,10 +14,10 @@ public String name(PixivArtwork artwork, int p) { } public String name(PixivArtwork artwork) { - return FetchUtil.replaceArgument(rule, artwork.getOrigJson()); + return FetchUtil.replaceArgument(rule, JSONObject.from(artwork)); } public String nameFolder(PixivArtwork artwork) { - return FetchUtil.replaceArgument(folderRule, artwork.getOrigJson()); + return FetchUtil.replaceArgument(folderRule, JSONObject.from(artwork)); } } diff --git a/src/main/java/xyz/zcraft/acgpicdownload/util/pixiv/PixivAccount.java b/src/main/java/xyz/zcraft/acgpicdownload/util/pixiv/PixivAccount.java index a92af9b..7207472 100644 --- a/src/main/java/xyz/zcraft/acgpicdownload/util/pixiv/PixivAccount.java +++ b/src/main/java/xyz/zcraft/acgpicdownload/util/pixiv/PixivAccount.java @@ -16,5 +16,5 @@ public class PixivAccount { @JSONField(name = "cookie") private String cookie; - private String token; + private transient String token; } diff --git a/src/main/java/xyz/zcraft/acgpicdownload/util/pixiv/PixivArtwork.java b/src/main/java/xyz/zcraft/acgpicdownload/util/pixiv/PixivArtwork.java index ad625a7..c49e589 100644 --- a/src/main/java/xyz/zcraft/acgpicdownload/util/pixiv/PixivArtwork.java +++ b/src/main/java/xyz/zcraft/acgpicdownload/util/pixiv/PixivArtwork.java @@ -72,15 +72,15 @@ public class PixivArtwork { @JSONField(name = "viewCount") private int viewCount; - private LinkedHashSet translatedTags = new LinkedHashSet<>(); - private String imageUrl; - private GifData gifData; - private From from; + private transient LinkedHashSet translatedTags = new LinkedHashSet<>(); + private transient String imageUrl; + private transient GifData gifData; + private transient From from; - private JSONObject origJson; - private String ranking; - private String search; + private transient String ranking; + private transient String search; + @JSONField(serialize = false) public String getTypeString() { if (illustType == 2) return ResourceBundleUtil.getString("fetch.pixiv.type.gif"); else if (illustType == 1 || illustType == 0) @@ -88,6 +88,7 @@ else if (illustType == 1 || illustType == 0) else return "?"; } + @JSONField(serialize = false) public String getFromString() { if(from == null) return null; if (from.equals(From.Ranking)) { @@ -99,6 +100,7 @@ public String getFromString() { } } + @JSONField(serialize = false) public String getTagsString() { if (translatedTags == null || translatedTags.isEmpty()) { if (originalTags == null) return null; @@ -117,4 +119,9 @@ public String getTagsString() { return sb.toString(); } } + + @JSONField(serialize = false) + public boolean isComplete() { + return urls != null && urls.containsKey("original") && urls.getString("original") != null; + } } diff --git a/src/main/java/xyz/zcraft/acgpicdownload/util/pixiv/PixivFetchUtil.java b/src/main/java/xyz/zcraft/acgpicdownload/util/pixiv/PixivFetchUtil.java index d805510..6753da5 100644 --- a/src/main/java/xyz/zcraft/acgpicdownload/util/pixiv/PixivFetchUtil.java +++ b/src/main/java/xyz/zcraft/acgpicdownload/util/pixiv/PixivFetchUtil.java @@ -309,7 +309,6 @@ public static PixivArtwork getArtwork(@NotNull String id, String cookieString, S } JSONObject jsonObject = JSONObject.parseObject(c.get().body().ownText()).getJSONObject("body"); PixivArtwork pixivArtwork = jsonObject.to(PixivArtwork.class); - pixivArtwork.setOrigJson(jsonObject); JSONArray jsonArray = jsonObject.getJSONObject("tags").getJSONArray("tags"); LinkedHashSet tags = new LinkedHashSet<>(); for (int i = 0; i < jsonArray.size(); i++) { @@ -461,7 +460,6 @@ public static List getUserArtworks(@NotNull String queryString, @N } a.setTranslatedTags(translatedTags); a.setFrom(From.User); - a.setOrigJson(jsonObject); artworks.add(a); } @@ -558,7 +556,6 @@ public static LinkedList parseArtworks(String jsonString, boolean for (Object t : a.getOriginalTags()) { a.getTranslatedTags().add(translateTag(t.toString(), tran)); } - a.setOrigJson(jsonObject); artworks.add(a); } @@ -582,7 +579,6 @@ public static LinkedList parseArtworks(String jsonString) { for (int i = 0; i < illust.size(); i++) { JSONObject jsonObject = illust.getJSONObject(i); PixivArtwork a = jsonObject.to(PixivArtwork.class); - a.setOrigJson(jsonObject); a.setFrom(From.Discovery); for (Object t : a.getOriginalTags()) { a.getTranslatedTags().add(translateTag(t.toString(), tran)); @@ -656,7 +652,6 @@ public static List getRelated(@NotNull PixivArtwork artwork, @Rang JSONObject jsonObject = illusts.getJSONObject(i); PixivArtwork object = jsonObject.to(PixivArtwork.class); if (object.getTitle() == null) continue; - object.setOrigJson(jsonObject); object.setFrom(From.Related); artworks.add(object); }