From 996638034e436b4463e312791ee74881723e2894 Mon Sep 17 00:00:00 2001 From: FAFITS Date: Thu, 21 May 2026 20:51:09 +0700 Subject: [PATCH 1/5] Update ZumiNovel.ts Fix Popular (Type) --- plugins/vietnamese/ZumiNovel.ts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/plugins/vietnamese/ZumiNovel.ts b/plugins/vietnamese/ZumiNovel.ts index cdd5c9ae..d54c89f2 100644 --- a/plugins/vietnamese/ZumiNovel.ts +++ b/plugins/vietnamese/ZumiNovel.ts @@ -181,10 +181,6 @@ class ZumiNovelPlugin implements Plugin.PluginBase { if (opts.type) { params.set('type', opts.type); - } else if (!opts.showRaw) { - params.append('type', 'original'); - params.append('type', 'translated'); - params.append('type', 'ai_translated'); } params.set('includeDescription', 'false'); From df011abfc783acdfd7a275b956cd657d38a62064 Mon Sep 17 00:00:00 2001 From: FAFITS Date: Thu, 21 May 2026 20:51:39 +0700 Subject: [PATCH 2/5] Update ZumiNovel.ts Upver --- plugins/vietnamese/ZumiNovel.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/vietnamese/ZumiNovel.ts b/plugins/vietnamese/ZumiNovel.ts index d54c89f2..d42a9d8b 100644 --- a/plugins/vietnamese/ZumiNovel.ts +++ b/plugins/vietnamese/ZumiNovel.ts @@ -127,7 +127,7 @@ class ZumiNovelPlugin implements Plugin.PluginBase { name = 'ZumiNovel'; icon = 'src/vi/zuminovel/icon.png'; site = SITE; - version = '1.0.3'; + version = '1.0.4'; pluginSettings: Plugin.PluginSettings = { showRaw: { From 7ea70de2003590ca6f1433d89dd7b4098ecf3506 Mon Sep 17 00:00:00 2001 From: FAFITS Date: Thu, 21 May 2026 21:37:33 +0700 Subject: [PATCH 3/5] Update jukanovel.ts Fix parseChapter API --- plugins/vietnamese/jukanovel.ts | 33 +++++++++++++++++++++++++++------ 1 file changed, 27 insertions(+), 6 deletions(-) diff --git a/plugins/vietnamese/jukanovel.ts b/plugins/vietnamese/jukanovel.ts index 05154f03..6389d4a5 100644 --- a/plugins/vietnamese/jukanovel.ts +++ b/plugins/vietnamese/jukanovel.ts @@ -102,15 +102,38 @@ class JukaNovelPlugin implements Plugin.PluginBase { }; } async parseChapter(chapterPath: string): Promise { + const chapterIdMatch = chapterPath.match(/\/(\d+)/); + if (!chapterIdMatch) { + throw new Error('Không thể tìm thấy ID chương.'); + } + const chapterId = chapterIdMatch[1]; const response = await fetchText(`${this.site}${chapterPath}`); const $ = loadCheerio(response); this.checkLogin($); const scriptContent = $('script:contains("__READER_DATA__")').html() || ''; - const match = scriptContent.match(/window\.__READER_DATA__\s*=\s*(.*?});/); - if (!match) throw new Error('Không tìm thấy dữ liệu chương.'); + const tokenMatch = scriptContent.match(new RegExp(`"chapter_id":${chapterId},"token":"([^"]+)"`)); + const token = tokenMatch ? tokenMatch[1] : null; + + const cipherKeyMatch = scriptContent.match(/"cipherKey":"([^"]+)"/); + const cipherKey = cipherKeyMatch ? cipherKeyMatch[1] : ''; + + if (!token) throw new Error('Không tìm thấy token cho chương này.'); + + const getDataContent = await fetchText(`${this.site}/api/reader/chapter/${chapterId}`, { + headers: { + 'accept': 'application/json', + 'x-requested-with': 'XMLHttpRequest', + 'referer': `${this.site}${chapterPath}`, + 'x-reader-token': token + } + }); try { - const readerData = JSON.parse(match[1]); + const chapterData = JSON.parse(getDataContent); + const readerData = { + cipherKey: cipherKey, + chapter: chapterData + }; const chapterContent = this.decryptJukaNovel(readerData); if (!chapterContent) throw new Error('chapterContent = null'); return chapterContent; @@ -156,9 +179,7 @@ class JukaNovelPlugin implements Plugin.PluginBase { content = contentCipher(chapter.raw_content); } else { content = - contentCipher(chapter.published_content) || - contentCipher(chapter.translated_content) || - contentCipher(chapter.raw_content); + contentCipher(chapter.published_content || chapter.translated_content || chapter.raw_content); } if (!content) return ''; From ba197612c04536027eb39e786d545c92bec68e2e Mon Sep 17 00:00:00 2001 From: FAFITS Date: Thu, 21 May 2026 21:39:19 +0700 Subject: [PATCH 4/5] Update jukanovel.ts UpVerJuka --- plugins/vietnamese/jukanovel.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/vietnamese/jukanovel.ts b/plugins/vietnamese/jukanovel.ts index 6389d4a5..329714d3 100644 --- a/plugins/vietnamese/jukanovel.ts +++ b/plugins/vietnamese/jukanovel.ts @@ -12,7 +12,7 @@ class JukaNovelPlugin implements Plugin.PluginBase { name = 'JukaNovel'; icon = 'src/vi/jukanovel/icon.png'; site = 'https://jukaza.site'; - version = '1.0.5'; + version = '1.0.6'; pluginSettings: Plugin.PluginSettings = { preferRaw: { From df967e379e7e5555a3078804df48fb5ce4272506 Mon Sep 17 00:00:00 2001 From: FAFITS Date: Thu, 21 May 2026 21:43:51 +0700 Subject: [PATCH 5/5] Fix Format --- electron/main/main.ts | 10 +++++++++- electron/main/protocols/lnproxy.ts | 13 ++++++------ plugins/vietnamese/jukanovel.ts | 32 +++++++++++++++++++----------- 3 files changed, 35 insertions(+), 20 deletions(-) diff --git a/electron/main/main.ts b/electron/main/main.ts index 1755b0b0..275c0a12 100644 --- a/electron/main/main.ts +++ b/electron/main/main.ts @@ -7,7 +7,15 @@ import { registerLnproxyProtocol } from './protocols/lnproxy.js'; app.commandLine.appendSwitch('disable-features', 'PartitionedCookies'); protocol.registerSchemesAsPrivileged([ - { scheme: 'lnproxy', privileges: { standard: true, secure: true, supportFetchAPI: true, corsEnabled: true } } + { + scheme: 'lnproxy', + privileges: { + standard: true, + secure: true, + supportFetchAPI: true, + corsEnabled: true, + }, + }, ]); const __filename = fileURLToPath(import.meta.url); diff --git a/electron/main/protocols/lnproxy.ts b/electron/main/protocols/lnproxy.ts index d5ca5c49..3dd9c7e3 100644 --- a/electron/main/protocols/lnproxy.ts +++ b/electron/main/protocols/lnproxy.ts @@ -3,7 +3,7 @@ import { performNetRequest } from '../ipc/fetch-handler.js'; import { customSession } from '../main.js'; export function registerLnproxyProtocol() { - customSession.protocol.handle('lnproxy', async (req) => { + customSession.protocol.handle('lnproxy', async req => { // Handle OPTIONS request for preflight just in case, though Custom Protocol with corsEnabled shouldn't need it. if (req.method === 'OPTIONS') { return new Response(null, { @@ -11,8 +11,8 @@ export function registerLnproxyProtocol() { headers: { 'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Methods': '*', - 'Access-Control-Allow-Headers': '*' - } + 'Access-Control-Allow-Headers': '*', + }, }); } @@ -46,15 +46,15 @@ export function registerLnproxyProtocol() { const responseData = await performNetRequest(targetUrl, { method: req.method, headers: headers, - body: bodyData + body: bodyData, }); const resHeaders = new Headers(responseData.headers); - + // Node fetch/net automatically decompresses but keeps original headers, causing issues when piped to Chromium resHeaders.delete('content-encoding'); resHeaders.delete('content-length'); - + // Always allow CORS resHeaders.set('Access-Control-Allow-Origin', '*'); resHeaders.set('Access-Control-Allow-Headers', '*'); @@ -67,7 +67,6 @@ export function registerLnproxyProtocol() { statusText: responseData.statusMessage, headers: resHeaders, }); - } catch (error) { console.error('[lnproxy] Request error:', error); return new Response(String(error), { status: 500 }); diff --git a/plugins/vietnamese/jukanovel.ts b/plugins/vietnamese/jukanovel.ts index 329714d3..922112fb 100644 --- a/plugins/vietnamese/jukanovel.ts +++ b/plugins/vietnamese/jukanovel.ts @@ -111,7 +111,9 @@ class JukaNovelPlugin implements Plugin.PluginBase { const $ = loadCheerio(response); this.checkLogin($); const scriptContent = $('script:contains("__READER_DATA__")').html() || ''; - const tokenMatch = scriptContent.match(new RegExp(`"chapter_id":${chapterId},"token":"([^"]+)"`)); + const tokenMatch = scriptContent.match( + new RegExp(`"chapter_id":${chapterId},"token":"([^"]+)"`), + ); const token = tokenMatch ? tokenMatch[1] : null; const cipherKeyMatch = scriptContent.match(/"cipherKey":"([^"]+)"/); @@ -119,20 +121,23 @@ class JukaNovelPlugin implements Plugin.PluginBase { if (!token) throw new Error('Không tìm thấy token cho chương này.'); - const getDataContent = await fetchText(`${this.site}/api/reader/chapter/${chapterId}`, { - headers: { - 'accept': 'application/json', - 'x-requested-with': 'XMLHttpRequest', - 'referer': `${this.site}${chapterPath}`, - 'x-reader-token': token - } - }); + const getDataContent = await fetchText( + `${this.site}/api/reader/chapter/${chapterId}`, + { + headers: { + 'accept': 'application/json', + 'x-requested-with': 'XMLHttpRequest', + 'referer': `${this.site}${chapterPath}`, + 'x-reader-token': token, + }, + }, + ); try { const chapterData = JSON.parse(getDataContent); const readerData = { cipherKey: cipherKey, - chapter: chapterData + chapter: chapterData, }; const chapterContent = this.decryptJukaNovel(readerData); if (!chapterContent) throw new Error('chapterContent = null'); @@ -178,8 +183,11 @@ class JukaNovelPlugin implements Plugin.PluginBase { if (this.preferRaw) { content = contentCipher(chapter.raw_content); } else { - content = - contentCipher(chapter.published_content || chapter.translated_content || chapter.raw_content); + content = contentCipher( + chapter.published_content || + chapter.translated_content || + chapter.raw_content, + ); } if (!content) return '';