ComicRead

为漫画站增加双页阅读、翻译等优化体验的增强功能。百合会(记录阅读历史、自动签到等)、百合会新站、E-Hentai(关联外站、快捷收藏、标签染色、识别广告页等)、nhentai(彻底屏蔽漫画、无限滚动)、Yurifans(自动签到)、拷贝漫画(copymanga)(显示最后阅读记录、解锁隐藏漫画)、再漫画、漫画柜(manhuagui)、动漫屋(dm5)、mangabz、komiic、無限動漫、绅士漫画(wnacg)、禁漫天堂、NoyAcg、熱辣漫畫、hanime1、hitomi、hdoujin、SchaleNetwork、nude-moon、HentaiZap、IMHentai、HentaiEra、HentaiEnvy、MangaDex、welovemanga、kisslove(klz9)、kemono、nekohouse、Pixiv、明日方舟泰拉记事社、最前線、芸能ヌード、Tachidesk、LANraragi

< Feedback on ComicRead

Review: OK - script works, but has bugs

§
Posted: 08. 08. 2026

请问作者可以更新一下再漫画网页的代码吗?现在显示为“Cannot read properties of undefined (reading 'length')”

§
Posted: 08. 08. 2026

附议

§
Posted: 08. 08. 2026

翻了下过往评论,作者今年现实比较忙碌,再漫画这个问题是今天才出现,应该是网页改版/接口更新的原因。
我让ai辅助改了下,替换掉原代码从“ // #漫画站(中文)[再漫画](https://manhua.zaimanhua.com/)”下面三个case的部分即可应急使用。
当然更稳健的更新,还得期待作者更优雅的更新:

// #漫画站(中文)[再漫画](https://manhua.zaimanhua.com/)
// test: https://manhua.zaimanhua.com/view/heimaohemonvdeketang/64175/133789
case 'www.zaimanhua.com':
case 'manhua.zaimanhua.com':
case 'm.zaimanhua.com':
{
const isMobile = location.host === 'm.zaimanhua.com';
const apiBase = isMobile ? 'https://manhua.zaimanhua.com' : '';
const apiReferer = isMobile ? 'https://manhua.zaimanhua.com/' : location.href;

const getZaimanhuaAuthHeaders = () => {
let token = '';

try {
// 从 Cookie 读取
token =
document.cookie
.split(';')
.map(c => c.trim())
.find(c =>
/^(token|authorization|access_token|jwt|zm_token|zaimanhua_token|zaimanhua_web_token)=/.test(c)
)
?.split('=')
.slice(1)
.join('=') || '';

// 兜底从 localStorage / sessionStorage 读取
if (!token) {
const win = typeof unsafeWindow !== 'undefined' ? unsafeWindow : window;

for (const storage of [win.localStorage, win.sessionStorage].filter(Boolean)) {
token =
Object.keys(storage)
.filter(key =>
/token|authorization|access_token|jwt|zm_token|zaimanhua/i.test(key)
)
.map(key => storage.getItem(key))
.find(Boolean) || '';

if (token) break;
}
}
} catch (error) {
console.warn('zaiManHua: 读取本地 token 失败', error);
}

token = String(token || '').trim();

try {
token = decodeURIComponent(token);
} catch {
// 解码失败就保持原样
}

token = token.replace(/^["']+|["']+$/g, '');

// 如果 token 被存成了 JSON 字符串,尝试解析
try {
const parsed = JSON.parse(token);

if (typeof parsed === 'string') {
token = parsed;
} else if (parsed && typeof parsed === 'object') {
token =
parsed.token ||
parsed.access_token ||
parsed.authorization ||
parsed.jwt ||
parsed?.data?.token ||
'';
}
} catch {
// 不是 JSON 就保持原样
}

if (!token) return {};

return {
Authorization: /^bearer\s+/i.test(token) ? token : `Bearer ${token}`
};
};

const zaiRequest = async (url, silent = false) => {
const res = await main.request(apiBase + url, {
responseType: 'json',
headers: {
Accept: 'application/json, text/plain, */*',
Referer: apiReferer,
...getZaimanhuaAuthHeaders()
}
});

const body = res?.response ?? {};

if (body.errno && Number(body.errno) !== 0) {
if (!silent) {
main.toast.error(`${helper.t('alert.comic_load_error')}: ${body.errmsg}`, {
throw: true
});
}
throw new Error(body.errmsg || helper.t('alert.comic_load_error'));
}

return body?.data ?? {};
};

const getChapterInfo = (comicId, chapterId, silent = false) =>
zaiRequest(
`/api/v1/comic2/chapter/detail?comic_id=${comicId}&chapter_id=${chapterId}`,
silent
).then(data => data?.chapterInfo ?? {});

const getComicInfoByPy = (comicPy, silent = false) =>
zaiRequest(
`/api/v1/comic2/comic/detail?comic_py=${encodeURIComponent(comicPy)}`,
silent
).then(data => data?.comicInfo ?? {});

const getComicInfoById = (comicId, silent = false) =>
zaiRequest(
`/api/v1/comic2/comic/detail?id=${comicId}`,
silent
).then(data => data?.comicInfo ?? {});

const getSortedChapters = (comicInfo, chapterId) => {
const groups = Array.isArray(comicInfo?.chapterList)
? comicInfo.chapterList
: [];

const group =
groups.find(
g =>
Array.isArray(g?.data) &&
g.data.some(ch => Number(ch?.chapter_id) === Number(chapterId))
) ?? groups[0];

const chapters = Array.isArray(group?.data) ? [...group.data] : [];

return chapters.sort(
(a, b) =>
(Number(a?.chapter_order) || 0) - (Number(b?.chapter_order) || 0)
);
};

const extractImgList = chapterInfo => {
let imgList = chapterInfo?.page_url_hd;

if (!Array.isArray(imgList) || imgList.length === 0) {
imgList = chapterInfo?.page_url;
}

if (!Array.isArray(imgList)) {
return [];
}

return imgList.filter(url => Boolean(url));
};

if (isMobile) {
options = {
name: 'zaiManHua',

async getImgList({ setState }) {
const urlParams = new URLSearchParams(location.search);
const comicId = Number(urlParams.get('comic_id'));
const chapterId = Number(urlParams.get('chapter_id'));

if (!comicId || !chapterId) {
throw new Error(helper.t('site.changed_load_failed'));
}

// 获取上一话 / 下一话
try {
const comicInfo = await getComicInfoById(comicId, true);
const chapters = getSortedChapters(comicInfo, chapterId);

const index = chapters.findIndex(
ch => Number(ch?.chapter_id) === Number(chapterId)
);

setState('manga', {
onPrev:
index > 0
? () =>
location.assign(
`/pages/comic/page?comic_id=${comicId}&chapter_id=${
chapters[index - 1].chapter_id
}`
)
: undefined,
onNext:
index !== -1 && index + 1 < chapters.length
? () =>
location.assign(
`/pages/comic/page?comic_id=${comicId}&chapter_id=${
chapters[index + 1].chapter_id
}`
)
: undefined
});
} catch (error) {
console.warn('zaiManHua mobile: 获取上/下话失败', error);
}

const chapterInfo = await getChapterInfo(comicId, chapterId);
const imgList = extractImgList(chapterInfo);

if (imgList.length === 0) {
throw new Error(helper.t('alert.comic_load_error'));
}

return imgList;
},

SPA: {
isMangaPage: () => location.pathname === '/pages/comic/page'
}
};
} else {
options = {
name: 'zaiManHua',

wait: () =>
Boolean(helper.querySelector('.scrollbar-demo-item')) ||
location.pathname.startsWith('/view/'),

async getImgList({ setState }) {
const match = location.pathname.match(/^\/view\/([^/]+)\/(\d+)\/(\d+)/);
if (!match) throw new Error(helper.t('site.changed_load_failed'));

const comicPy = decodeURIComponent(match[1]);
const comicId = Number(match[2]);
const chapterId = Number(match[3]);

// 获取上一话 / 下一话
try {
const comicInfo = await getComicInfoByPy(comicPy, true);
const chapters = getSortedChapters(comicInfo, chapterId);

const index = chapters.findIndex(
ch => Number(ch?.chapter_id) === Number(chapterId)
);

const base = `/view/${encodeURIComponent(comicPy)}/${comicId}`;

setState('manga', {
onPrev:
index > 0
? () =>
location.assign(`${base}/${chapters[index - 1].chapter_id}`)
: undefined,
onNext:
index !== -1 && index + 1 < chapters.length
? () =>
location.assign(`${base}/${chapters[index + 1].chapter_id}`)
: undefined
});
} catch (error) {
console.warn('zaiManHua: 获取上/下话失败', error);
}

const chapterInfo = await getChapterInfo(comicId, chapterId);
const imgList = extractImgList(chapterInfo);

if (imgList.length === 0) {
throw new Error(helper.t('alert.comic_load_error'));
}

return imgList;
},

SPA: {
isMangaPage: () => location.pathname.startsWith('/view/')
}
};
}

break;
}

Post reply

Sign in to post a reply.