[shonen_jump_plus] Optimize comic details parsing and use AppStore to get latest app version (#122)

This commit is contained in:
LiuliFox
2025-08-08 14:33:53 +08:00
committed by GitHub
parent ee0a98ec33
commit 2b8c532817
2 changed files with 58 additions and 21 deletions

View File

@@ -66,7 +66,7 @@
"name": "少年ジャンプ+", "name": "少年ジャンプ+",
"fileName": "shonen_jump_plus.js", "fileName": "shonen_jump_plus.js",
"key": "shonen_jump_plus", "key": "shonen_jump_plus",
"version": "1.0.2" "version": "1.1.0"
}, },
{ {
"name": "hitomi.la", "name": "hitomi.la",

View File

@@ -1,7 +1,7 @@
class ShonenJumpPlus extends ComicSource { class ShonenJumpPlus extends ComicSource {
name = "少年ジャンプ+"; name = "少年ジャンプ+";
key = "shonen_jump_plus"; key = "shonen_jump_plus";
version = "1.0.2"; version = "1.1.0";
minAppVersion = "1.2.1"; minAppVersion = "1.2.1";
url = url =
"https://git.nyne.dev/nyne/venera-configs/raw/branch/main/shonen_jump_plus.js"; "https://git.nyne.dev/nyne/venera-configs/raw/branch/main/shonen_jump_plus.js";
@@ -10,13 +10,14 @@ class ShonenJumpPlus extends ComicSource {
bearerToken = null; bearerToken = null;
userAccountId = null; userAccountId = null;
tokenExpiry = 0; tokenExpiry = 0;
latestVersion = "4.0.21";
get headers() { get headers() {
return { return {
"Origin": "https://shonenjumpplus.com", "Origin": "https://shonenjumpplus.com",
"Referer": "https://shonenjumpplus.com/", "Referer": "https://shonenjumpplus.com/",
"X-Giga-Device-Id": this.deviceId, "X-Giga-Device-Id": this.deviceId,
"User-Agent": "ShonenJumpPlus-Android/4.0.21", "User-Agent": `ShonenJumpPlus-Android/${this.latestVersion}`,
}; };
} }
@@ -30,7 +31,14 @@ class ShonenJumpPlus extends ComicSource {
return result; return result;
} }
init() { } async init() {
const url = "https://apps.apple.com/jp/app/少年ジャンプ-人気漫画が読める雑誌アプリ/id875750302";
const resp = await Network.get(url);
const match = resp.body.match(/":\[\{\\"versionDisplay\\":\\"([\d.]+)\\",\\"rele/);
if (match) {
this.latestVersion = match[1];
}
}
explore = [ explore = [
{ {
@@ -85,7 +93,8 @@ class ShonenJumpPlus extends ComicSource {
? cover.replace("{height}", "500").replace("{width}", "500") ? cover.replace("{height}", "500").replace("{width}", "500")
: "", : "",
tags: [], tags: [],
description: `Ranking: ${item.rank} · Views: ${item.viewCount || "Unknown" description: `Ranking: ${item.rank} · Views: ${
item.viewCount || "Unknown"
}`, }`,
}; };
} }
@@ -116,6 +125,9 @@ class ShonenJumpPlus extends ComicSource {
const pageInfo = response?.data?.search?.pageInfo || {}; const pageInfo = response?.data?.search?.pageInfo || {};
const comics = edges.map(({ node }) => { const comics = edges.map(({ node }) => {
const authors = (node.author?.name || "").split(/\s*\/\s*/).filter(
Boolean,
);
const cover = node.latestIssue?.thumbnailUriTemplate || const cover = node.latestIssue?.thumbnailUriTemplate ||
node.thumbnailUriTemplate; node.thumbnailUriTemplate;
if (node.__typename === "Series") { if (node.__typename === "Series") {
@@ -123,9 +135,8 @@ class ShonenJumpPlus extends ComicSource {
id: node.databaseId, id: node.databaseId,
title: node.title || "", title: node.title || "",
cover: this.replaceCoverUrl(cover), cover: this.replaceCoverUrl(cover),
extra: { description: node.description || "",
author: node.author?.name || "", tags: authors,
},
}); });
} }
if (node.__typename === "MagazineLabel") { if (node.__typename === "MagazineLabel") {
@@ -150,16 +161,40 @@ class ShonenJumpPlus extends ComicSource {
loadInfo: async (id) => { loadInfo: async (id) => {
await this.ensureAuth(); await this.ensureAuth();
const seriesData = await this.fetchSeriesDetail(id); const seriesData = await this.fetchSeriesDetail(id);
const chapters = await this.fetchEpisodes(id); const episodes = await this.fetchEpisodes(id);
const { chapters, latestPublishAt } = episodes.reduce(
(acc, ep) => ({
chapters: {
...acc.chapters,
[ep.databaseId]: ep.title || "",
},
latestPublishAt:
ep.publishedAt && ep.publishedAt > acc.latestPublishAt
? ep.publishedAt
: acc.latestPublishAt,
}),
{ chapters: {}, latestPublishAt: "" },
);
const maxDate = latestPublishAt > seriesData.openAt
? latestPublishAt
: seriesData.openAt;
const updateDate = new Date(new Date(maxDate) - 60 * 60 * 1000);
const authors = (seriesData.author?.name || "").split(/\s*\/\s*/).filter(
Boolean,
);
return new ComicDetails({ return new ComicDetails({
title: seriesData.title || "", title: seriesData.title || "",
subtitle: seriesData.author?.name || "", subtitle: authors.join(" / "),
cover: this.replaceCoverUrl(seriesData.thumbnailUriTemplate), cover: this.replaceCoverUrl(seriesData.thumbnailUriTemplate),
description: seriesData.descriptionBanner?.text || "", description: seriesData.description || "",
tags: { tags: {
"Author": [seriesData.author?.name || ""], "Author": authors,
"Update": [updateDate.toISOString().slice(0, 10)],
}, },
url: `https://shonenjumpplus.com/app/episode/${seriesData.publisherId}`,
chapters, chapters,
}); });
}, },
@@ -264,11 +299,10 @@ class ShonenJumpPlus extends ComicSource {
"SeriesDetailEpisodeList", "SeriesDetailEpisodeList",
{ id, episodeOffset: 0, episodeFirst: 1500, episodeSort: "NUMBER_ASC" }, { id, episodeOffset: 0, episodeFirst: 1500, episodeSort: "NUMBER_ASC" },
); );
const episodes = response?.data?.series?.episodes?.edges || []; const episodes = (response?.data?.series?.episodes?.edges || []).map(
return episodes.reduce((chapters, { node }) => ({ (edge) => edge.node
...chapters, );
[node.databaseId]: node.title || "", return episodes;
}), {});
} }
async fetchEpisodePages(episodeId) { async fetchEpisodePages(episodeId) {
@@ -352,7 +386,7 @@ const GraphQLQueries = {
edges { edges {
node { node {
__typename __typename
... on Series { id databaseId title thumbnailUriTemplate author { name } } ... on Series { id databaseId title thumbnailUriTemplate author { name } description }
... on MagazineLabel { id databaseId title thumbnailUriTemplate latestIssue { thumbnailUriTemplate } } ... on MagazineLabel { id databaseId title thumbnailUriTemplate latestIssue { thumbnailUriTemplate } }
} }
} }
@@ -361,15 +395,18 @@ const GraphQLQueries = {
"SeriesDetail": `query SeriesDetail($id: String!) { "SeriesDetail": `query SeriesDetail($id: String!) {
series(databaseId: $id) { series(databaseId: $id) {
id databaseId title thumbnailUriTemplate id databaseId title thumbnailUriTemplate
author { name } descriptionBanner { text } author { name }
description
hashtags serialUpdateScheduleLabel hashtags serialUpdateScheduleLabel
openAt
publisherId
} }
}`, }`,
"SeriesDetailEpisodeList": "SeriesDetailEpisodeList":
`query SeriesDetailEpisodeList($id: String!, $episodeOffset: Int, $episodeFirst: Int, $episodeSort: ReadableProductSorting) { `query SeriesDetailEpisodeList($id: String!, $episodeOffset: Int, $episodeFirst: Int, $episodeSort: ReadableProductSorting) {
series(databaseId: $id) { series(databaseId: $id) {
episodes: readableProducts(types: [EPISODE], first: $episodeFirst, offset: $episodeOffset, sort: $episodeSort) { episodes: readableProducts(types: [EPISODE], first: $episodeFirst, offset: $episodeOffset, sort: $episodeSort) {
edges { node { databaseId title } } edges { node { databaseId title publishedAt } }
} }
} }
}`, }`,