From 9829f9e4556af9d148df66cfd05ccfdd26183e07 Mon Sep 17 00:00:00 2001 From: Batorian Date: Fri, 28 Feb 2025 17:59:06 +0100 Subject: [PATCH 1/6] genesis: fix --- src/plugins/english/genesis.ts | 427 +++++++++++++++++++-------------- 1 file changed, 241 insertions(+), 186 deletions(-) diff --git a/src/plugins/english/genesis.ts b/src/plugins/english/genesis.ts index fcd45cad7..730724702 100644 --- a/src/plugins/english/genesis.ts +++ b/src/plugins/english/genesis.ts @@ -18,7 +18,7 @@ class Genesis implements Plugin.PluginBase { icon = 'src/en/genesis/icon.png'; customCSS = 'src/en/genesis/customCSS.css'; site = 'https://genesistudio.com'; - version = '1.0.7'; + version = '1.1.0'; imageRequestInit?: Plugin.ImageRequestInit | undefined = { headers: { @@ -39,7 +39,7 @@ class Genesis implements Plugin.PluginBase { { showLatestNovels, filters }: Plugin.PopularNovelsOptions, ): Promise { if (pageNo !== 1) return []; - let link = `${this.site}/api/search?`; + let link = `${this.site}/api/novels/search?`; if (showLatestNovels) { link += 'sort=Recent'; } else { @@ -120,20 +120,21 @@ class Genesis implements Plugin.PluginBase { // Change string here if the chapters are stored under a different key const chapterKey = 'chapters'; - if (typeof value === 'object' && value !== null && chapterKey in value) { - const chapterData = this.decodeData(data[value[chapterKey]]); - - // Object.values will give us an array of arrays (any[][]) - const chapterArrays: any[][] = Object.values(chapterData); - // Flatten and format the chapters - return chapterArrays.flatMap((chapters: any[]) => { - return chapters - .map((chapter: any) => this.formatChapter(chapter)) - .filter( - (chapter): chapter is Plugin.ChapterItem => chapter !== null, - ); - }); + if (typeof value === 'object' && value !== null && chapterKey in value) { + const chapterData = data[value[chapterKey]]; + const freeChapterData = chapterData.free; + const premiumChapterData = chapterData.premium; + + const allChapterData = [ + ...data[freeChapterData], + ...data[premiumChapterData], + ]; + + return allChapterData + .map((index: number) => data[index]) + .map((chapter: any) => this.formatChapter(chapter, data)) + .filter((chapter): chapter is Plugin.ChapterItem => chapter !== null); } } @@ -141,27 +142,24 @@ class Genesis implements Plugin.PluginBase { } // Helper function to format an individual chapter - formatChapter(chapter: any): Plugin.ChapterItem | null { - const { id, chapter_title, chapter_number, required_tier, date_created } = - chapter; - + formatChapter(chapter: any, data: any): Plugin.ChapterItem | null { // Ensure required fields are present and valid if ( - id && - chapter_title && - chapter_number >= 0 && - required_tier !== null && - date_created + data[chapter.id] && + data[chapter.chapter_title] && + data[chapter.chapter_number] >= 0 && + data[chapter.required_tier] !== null && + data[chapter.date_created] ) { - const number = parseInt(chapter_number, 10) || 0; - const requiredTier = parseInt(required_tier, 10) || 0; + const number = parseInt(data[chapter.chapter_number], 10) || 0; + const requiredTier = parseInt(data[chapter.required_tier], 10) || 0; // Only process chapters with a 'requiredTier' of 0 if (requiredTier === 0) { return { - name: `Chapter ${number}: ${chapter_title}`, - path: `/viewer/${id}`, - releaseTime: date_created, + name: `Chapter ${number} - ${data[chapter.chapter_title]}`, + path: `/viewer/${data[chapter.id]}`, + releaseTime: data[chapter.date_created], chapterNumber: number, }; } @@ -170,162 +168,219 @@ class Genesis implements Plugin.PluginBase { return null; } - decodeData(code: any) { - const offset = this.getOffsetIndex(code); - const params = this.getDecodeParams(code); - const constant = this.getConstant(code); - const data = this.getStringsArrayRaw(code); - - const getDataAt = (x: number) => data[x - offset]; - - //reshuffle data array - // eslint-disable-next-line no-constant-condition - while (true) { - try { - const some_number = this.applyDecodeParams(params, getDataAt); - if (some_number === constant) break; - else data.push(data.shift()); - } catch (err) { - data.push(data.shift()); - } - } - - return this.getChapterData(code, getDataAt); - } - - getOffsetIndex(code: string) { - // @ts-ignore - const string = /{(\w+)=\1-0x(?[0-9a-f]+);/.exec(code).groups.offset; - return parseInt(string, 16); - } - - /** - * @returns {string[]} - */ - getStringsArrayRaw(code: string) { - // @ts-ignore - let json = /function \w+\(\){var \w+=(?\['.+']);/.exec(code).groups - .array; - - //replace string single quotes with double quotes and add escaped chars - json = json.replace(/'(.+?)'([,\]])/g, (match, p1, p2) => { - return `"${p1.replace(/\\x([0-9a-z]{2})/g, (match: any, p1: string) => { - //hexadecimal unicode escape chars - return String.fromCharCode(parseInt(p1, 16)); - })}"${p2}`; - }); - - return JSON.parse(json); - } - - /** - * @returns {{offset: number, divider: number, negated: boolean}[][]} - */ - getDecodeParams(code: string) { - // @ts-ignore - const jsDecodeInt = /while\(!!\[]\){try{var \w+=(?.+?);/.exec(code) - .groups.code; - const decodeSections = jsDecodeInt.split('+'); - const params = []; - for (const section of decodeSections) { - params.push(this.decodeParamSection(section)); - } - return params; - } - - /** - * @param {string} section - * @returns {{offset: number, divider: number, negated: boolean}[]} - */ - decodeParamSection(section: string) { - const sections = section.split('*'); - const params = []; - for (const section of sections) { - // @ts-ignore - const offsetStr = /parseInt\(\w+\(0x(?[0-9a-f]+)\)\)/.exec( - section, - ).groups.offset; - const offset = parseInt(offsetStr, 16); - // @ts-ignore - const dividerStr = /\/0x(?[0-9a-f]+)/.exec(section).groups - .divider; - const divider = parseInt(dividerStr, 16); - const negated = section.includes('-'); - params.push({ offset, divider, negated }); - } - return params; - } - - getConstant(code: string) { - // @ts-ignore - const constantStr = /}}}\(\w+,0x(?[0-9a-f]+)\),/.exec(code).groups - .constant; - return parseInt(constantStr, 16); - } - - getChapterData( - code: string, - getDataAt: { (x: number): any; (arg0: number): any }, - ) { - let chapterDataStr = - // @ts-ignore - /\),\(function\(\){var \w+=\w+;return(?{.+?});/.exec(code).groups - .data; - - //replace hex with decimal - chapterDataStr = chapterDataStr.replace(/:0x([0-9a-f]+)/g, (match, p1) => { - const hex = parseInt(p1, 16); - return `: ${hex}`; - }); - - //replace ![] with false and !![] with true - chapterDataStr = chapterDataStr - .replace(/:!!\[]/g, ':true') - .replace(/:!\[]/g, ':false'); - - //replace string single quotes with double quotes and add escaped chars - chapterDataStr = chapterDataStr.replace( - /'(.+?)'([,\]}:])/g, - (match, p1, p2) => { - return `"${p1.replace(/\\x([0-9a-z]{2})/g, (match: any, p1: string) => { - //hexadecimal unicode escape chars - return String.fromCharCode(parseInt(p1, 16)); - })}"${p2}`; - }, - ); - - //parse the data getting methods - chapterDataStr = chapterDataStr.replace( - // @ts-ignore - /:\w+\(0x(?[0-9a-f]+)\)/g, - (match, p1) => { - const offset = parseInt(p1, 16); - return `:${JSON.stringify(getDataAt(offset))}`; - }, - ); - - return JSON.parse(chapterDataStr); - } - - /** - * @param {{offset: number, divider: number, negated: boolean}[][]} params - * @param {function(number): string} getDataAt - */ - applyDecodeParams( - params: { offset: number; divider: number; negated: boolean }[][], - getDataAt: { (x: number): any; (arg0: any): string }, - ) { - let res = 0; - for (const paramAdd of params) { - let resInner = 1; - for (const paramMul of paramAdd) { - resInner *= parseInt(getDataAt(paramMul.offset)) / paramMul.divider; - if (paramMul.negated) resInner *= -1; - } - res += resInner; - } - return res; - } + // // Helper function to extract and format chapters + // extractChapters(data: any): Plugin.ChapterItem[] { + // for (const key in data) { + // const value = data[key]; + // + // // Change string here if the chapters are stored under a different key + // const chapterKey = 'chapters'; + // if (typeof value === 'object' && value !== null && chapterKey in value) { + // const chapterData = this.decodeData(data[value[chapterKey]]); + // + // // Object.values will give us an array of arrays (any[][]) + // const chapterArrays: any[][] = Object.values(chapterData); + // + // // Flatten and format the chapters + // return chapterArrays.flatMap((chapters: any[]) => { + // return chapters + // .map((chapter: any) => this.formatChapter(chapter)) + // .filter( + // (chapter): chapter is Plugin.ChapterItem => chapter !== null, + // ); + // }); + // } + // } + // + // return []; + // } + // + // // Helper function to format an individual chapter + // formatChapter(chapter: any): Plugin.ChapterItem | null { + // const { id, chapter_title, chapter_number, required_tier, date_created } = + // chapter; + // + // // Ensure required fields are present and valid + // if ( + // id && + // chapter_title && + // chapter_number >= 0 && + // required_tier !== null && + // date_created + // ) { + // const number = parseInt(chapter_number, 10) || 0; + // const requiredTier = parseInt(required_tier, 10) || 0; + // + // // Only process chapters with a 'requiredTier' of 0 + // if (requiredTier === 0) { + // return { + // name: `Chapter ${number}: ${chapter_title}`, + // path: `/viewer/${id}`, + // releaseTime: date_created, + // chapterNumber: number, + // }; + // } + // } + // + // return null; + // } + // + // decodeData(code: any) { + // const offset = this.getOffsetIndex(code); + // const params = this.getDecodeParams(code); + // const constant = this.getConstant(code); + // const data = this.getStringsArrayRaw(code); + // + // const getDataAt = (x: number) => data[x - offset]; + // + // //reshuffle data array + // // eslint-disable-next-line no-constant-condition + // while (true) { + // try { + // const some_number = this.applyDecodeParams(params, getDataAt); + // if (some_number === constant) break; + // else data.push(data.shift()); + // } catch (err) { + // data.push(data.shift()); + // } + // } + // + // return this.getChapterData(code, getDataAt); + // } + // + // getOffsetIndex(code: string) { + // // @ts-ignore + // const string = /{(\w+)=\1-0x(?[0-9a-f]+);/.exec(code).groups.offset; + // return parseInt(string, 16); + // } + // + // /** + // * @returns {string[]} + // */ + // getStringsArrayRaw(code: string) { + // // @ts-ignore + // let json = /function \w+\(\){var \w+=(?\['.+']);/.exec(code).groups + // .array; + // + // //replace string single quotes with double quotes and add escaped chars + // json = json.replace(/'(.+?)'([,\]])/g, (match, p1, p2) => { + // return `"${p1.replace(/\\x([0-9a-z]{2})/g, (match: any, p1: string) => { + // //hexadecimal unicode escape chars + // return String.fromCharCode(parseInt(p1, 16)); + // })}"${p2}`; + // }); + // + // return JSON.parse(json); + // } + // + // /** + // * @returns {{offset: number, divider: number, negated: boolean}[][]} + // */ + // getDecodeParams(code: string) { + // // @ts-ignore + // const jsDecodeInt = /while\(!!\[]\){try{var \w+=(?.+?);/.exec(code) + // .groups.code; + // const decodeSections = jsDecodeInt.split('+'); + // const params = []; + // for (const section of decodeSections) { + // params.push(this.decodeParamSection(section)); + // } + // return params; + // } + // + // /** + // * @param {string} section + // * @returns {{offset: number, divider: number, negated: boolean}[]} + // */ + // decodeParamSection(section: string) { + // const sections = section.split('*'); + // const params = []; + // for (const section of sections) { + // // @ts-ignore + // const offsetStr = /parseInt\(\w+\(0x(?[0-9a-f]+)\)\)/.exec( + // section, + // ).groups.offset; + // const offset = parseInt(offsetStr, 16); + // // @ts-ignore + // const dividerStr = /\/0x(?[0-9a-f]+)/.exec(section).groups + // .divider; + // const divider = parseInt(dividerStr, 16); + // const negated = section.includes('-'); + // params.push({ offset, divider, negated }); + // } + // return params; + // } + // + // getConstant(code: string) { + // // @ts-ignore + // const constantStr = /}}}\(\w+,0x(?[0-9a-f]+)\),/.exec(code).groups + // .constant; + // return parseInt(constantStr, 16); + // } + // + // getChapterData( + // code: string, + // getDataAt: { (x: number): any; (arg0: number): any }, + // ) { + // let chapterDataStr = + // // @ts-ignore + // /\),\(function\(\){var \w+=\w+;return(?{.+?});/.exec(code).groups + // .data; + // + // //replace hex with decimal + // chapterDataStr = chapterDataStr.replace(/:0x([0-9a-f]+)/g, (match, p1) => { + // const hex = parseInt(p1, 16); + // return `: ${hex}`; + // }); + // + // //replace ![] with false and !![] with true + // chapterDataStr = chapterDataStr + // .replace(/:!!\[]/g, ':true') + // .replace(/:!\[]/g, ':false'); + // + // //replace string single quotes with double quotes and add escaped chars + // chapterDataStr = chapterDataStr.replace( + // /'(.+?)'([,\]}:])/g, + // (match, p1, p2) => { + // return `"${p1.replace(/\\x([0-9a-z]{2})/g, (match: any, p1: string) => { + // //hexadecimal unicode escape chars + // return String.fromCharCode(parseInt(p1, 16)); + // })}"${p2}`; + // }, + // ); + // + // //parse the data getting methods + // chapterDataStr = chapterDataStr.replace( + // // @ts-ignore + // /:\w+\(0x(?[0-9a-f]+)\)/g, + // (match, p1) => { + // const offset = parseInt(p1, 16); + // return `:${JSON.stringify(getDataAt(offset))}`; + // }, + // ); + // + // return JSON.parse(chapterDataStr); + // } + // + // /** + // * @param {{offset: number, divider: number, negated: boolean}[][]} params + // * @param {function(number): string} getDataAt + // */ + // applyDecodeParams( + // params: { offset: number; divider: number; negated: boolean }[][], + // getDataAt: { (x: number): any; (arg0: any): string }, + // ) { + // let res = 0; + // for (const paramAdd of params) { + // let resInner = 1; + // for (const paramMul of paramAdd) { + // resInner *= parseInt(getDataAt(paramMul.offset)) / paramMul.divider; + // if (paramMul.negated) resInner *= -1; + // } + // res += resInner; + // } + // return res; + // } async parseChapter(chapterPath: string): Promise { const url = `${this.site}${chapterPath}/__data.json?x-sveltekit-invalidated=001`; @@ -347,7 +402,7 @@ class Genesis implements Plugin.PluginBase { pageNo: number, ): Promise { if (pageNo !== 1) return []; - const url = `${this.site}/api/search?serialization=All&sort=Popular&title=${searchTerm}`; + const url = `${this.site}/api/novels/search?serialization=All&sort=Popular&title=${searchTerm}`; const json = await fetchApi(url).then(r => r.json()); return this.parseNovels(json); } From ba19747078ae0730e3eb4e52d0405c567964fa67 Mon Sep 17 00:00:00 2001 From: Batorian Date: Fri, 28 Feb 2025 18:46:13 +0100 Subject: [PATCH 2/6] genesis: fix --- src/plugins/english/genesis.ts | 141 +++++++++++++++++++++++---------- 1 file changed, 98 insertions(+), 43 deletions(-) diff --git a/src/plugins/english/genesis.ts b/src/plugins/english/genesis.ts index 730724702..5abd3125c 100644 --- a/src/plugins/english/genesis.ts +++ b/src/plugins/english/genesis.ts @@ -52,6 +52,13 @@ class Genesis implements Plugin.PluginBase { return this.parseNovels(json); } + // Helper function to extract novel data from nodes + extractData(nodes: any[]): any { + return nodes + .filter((node: { type: string }) => node.type === 'data') + .map((node: { data: any }) => node.data)[0]; + } + async parseNovel(novelPath: string): Promise { const url = `${this.site}${novelPath}/__data.json?x-sveltekit-invalidated=001`; @@ -60,7 +67,7 @@ class Genesis implements Plugin.PluginBase { const nodes = json.nodes; // Extract the main novel data from the nodes - const data = this.extractNovelData(nodes); + const data = this.extractData(nodes); // Initialize the novel object with default values const novel: Plugin.SourceNovel = { @@ -82,13 +89,6 @@ class Genesis implements Plugin.PluginBase { return novel; } - // Helper function to extract novel data from nodes - extractNovelData(nodes: any[]): any { - return nodes - .filter((node: { type: string }) => node.type === 'data') - .map((node: { data: any }) => node.data)[0]; - } - // Helper function to populate novel metadata populateNovelMetadata(novel: Plugin.SourceNovel, data: any): void { for (const key in data) { @@ -115,52 +115,73 @@ class Genesis implements Plugin.PluginBase { // Helper function to extract and format chapters extractChapters(data: any): Plugin.ChapterItem[] { + const chapterKey = 'chapters'; + const chapters: Plugin.ChapterItem[] = []; + + // Iterate over each property in data to find chapter containers for (const key in data) { const value = data[key]; - // Change string here if the chapters are stored under a different key - const chapterKey = 'chapters'; + // Look for an object with a 'chapters' key + if (value && typeof value === 'object' && chapterKey in value) { + const chaptersIndexKey = value[chapterKey]; + const chapterData = data[chaptersIndexKey]; + if (!chapterData || typeof chapterData !== 'object') continue; - if (typeof value === 'object' && value !== null && chapterKey in value) { - const chapterData = data[value[chapterKey]]; - const freeChapterData = chapterData.free; - const premiumChapterData = chapterData.premium; + // Dynamically get chapter indices from every category (free, premium, etc.) + let allChapterIndices: number[] = []; + for (const category of Object.keys(chapterData)) { + const chapterIndices = data[chapterData[category]]; + if (Array.isArray(chapterIndices)) { + allChapterIndices = allChapterIndices.concat(chapterIndices); + } + } - const allChapterData = [ - ...data[freeChapterData], - ...data[premiumChapterData], - ]; - - return allChapterData + // Format each chapter and add only valid ones + const formattedChapters = allChapterIndices .map((index: number) => data[index]) .map((chapter: any) => this.formatChapter(chapter, data)) .filter((chapter): chapter is Plugin.ChapterItem => chapter !== null); + + chapters.push(...formattedChapters); } } - return []; + return chapters; } // Helper function to format an individual chapter formatChapter(chapter: any, data: any): Plugin.ChapterItem | null { - // Ensure required fields are present and valid + const { id, chapter_title, chapter_number, required_tier, date_created } = + chapter; + + // Destructure from data using computed property names based on chapter keys + const { + [id]: chapterId, + [chapter_title]: chapterTitle, + [chapter_number]: chapterNumberVal, + [required_tier]: requiredTierVal, + [date_created]: dateCreated, + } = data; + + // Validate required fields if ( - data[chapter.id] && - data[chapter.chapter_title] && - data[chapter.chapter_number] >= 0 && - data[chapter.required_tier] !== null && - data[chapter.date_created] + chapterId && + chapterTitle && + chapterNumberVal >= 0 && + requiredTierVal !== null && + dateCreated ) { - const number = parseInt(data[chapter.chapter_number], 10) || 0; - const requiredTier = parseInt(data[chapter.required_tier], 10) || 0; + const chapterNumber = parseInt(String(chapterNumberVal), 10) || 0; + const requiredTier = parseInt(String(requiredTierVal), 10) || 0; - // Only process chapters with a 'requiredTier' of 0 + // Only process chapters that do not require a premium tier if (requiredTier === 0) { return { - name: `Chapter ${number} - ${data[chapter.chapter_title]}`, - path: `/viewer/${data[chapter.id]}`, - releaseTime: data[chapter.date_created], - chapterNumber: number, + name: `Chapter ${chapterNumber} - ${chapterTitle}`, + path: `/viewer/${chapterId}`, + releaseTime: dateCreated, + chapterNumber: chapterNumber, }; } } @@ -384,17 +405,51 @@ class Genesis implements Plugin.PluginBase { async parseChapter(chapterPath: string): Promise { const url = `${this.site}${chapterPath}/__data.json?x-sveltekit-invalidated=001`; + + // Fetch the novel's data in JSON format const json = await fetchApi(url).then(r => r.json()); const nodes = json.nodes; - const data = nodes - .filter((node: { type: string }) => node.type === 'data') - .map((node: { data: any }) => node.data)[0]; - const content = data[data[0].gs] ?? data[19]; - const notes = data[data[0].notes]; - const footnotes = data[data[0].footnotes]; - return ( - content + (notes ? `

Notes

${notes}` : '') + (footnotes ?? '') - ); + + // Extract the main novel data from the nodes + const data = this.extractData(nodes); + + const contentKey = 'content'; + const notesKey = 'notes'; + const footnotesKey = 'footnotes'; + + // Iterate over each property in data to find chapter containers + for (const key in data) { + const mapping = data[key]; + + // Look for an object with a 'chapters' key + if ( + mapping && + typeof mapping === 'object' && + contentKey in mapping && + notesKey in mapping && + footnotesKey in mapping + ) { + // Use the found mapping object to determine the actual keys. + const contentMappingKey = mapping[contentKey]; + const notesMappingKey = mapping[notesKey]; + const footnotesMappingKey = mapping[footnotesKey]; + + // Retrieve the chapter's content, notes, and footnotes using the mapping. + // Provide a fallback for content if needed. + const content = data[contentMappingKey] ?? data[19]; + const notes = data[notesMappingKey]; + const footnotes = data[footnotesMappingKey]; + + return ( + content + + (notes ? `Notes${notes}` : '') + + (footnotes ? `Footnotes${footnotes}` : '') + ); + } + } + + // If no mapping object was found, return an empty string or handle appropriately. + return ''; } async searchNovels( From d868f6d90f44bdf96cb5790b46ce26e1bc5894fd Mon Sep 17 00:00:00 2001 From: Batorian Date: Fri, 28 Feb 2025 18:50:17 +0100 Subject: [PATCH 3/6] genesis: fix popularNovels --- src/plugins/english/genesis.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/english/genesis.ts b/src/plugins/english/genesis.ts index 5abd3125c..74e807d3b 100644 --- a/src/plugins/english/genesis.ts +++ b/src/plugins/english/genesis.ts @@ -41,7 +41,7 @@ class Genesis implements Plugin.PluginBase { if (pageNo !== 1) return []; let link = `${this.site}/api/novels/search?`; if (showLatestNovels) { - link += 'sort=Recent'; + link += 'serialization=All&sort=Recent'; } else { if (filters!.genres.value) { link += filters!.genres.value; From c5a673dba260a0fec8fa81dce4edecb045c27922 Mon Sep 17 00:00:00 2001 From: Batorian Date: Fri, 28 Feb 2025 19:04:39 +0100 Subject: [PATCH 4/6] genesis: add line breaks --- package.json | 2 +- src/plugins/english/genesis.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index 6330496cf..3d39a4a74 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "lnreader-plugins", - "version": "3.0.0", + "version": "3.0.1", "description": "Plugins repo for LNReader", "main": "index.js", "type": "module", diff --git a/src/plugins/english/genesis.ts b/src/plugins/english/genesis.ts index 74e807d3b..aa08e702e 100644 --- a/src/plugins/english/genesis.ts +++ b/src/plugins/english/genesis.ts @@ -442,8 +442,8 @@ class Genesis implements Plugin.PluginBase { return ( content + - (notes ? `Notes${notes}` : '') + - (footnotes ? `Footnotes${footnotes}` : '') + (notes ? `Notes
${notes}` : '') + + (footnotes ? `Footnotes
${footnotes}` : '') ); } } From d8d6f431acd256fb209b542ea89256d99a0ed5cd Mon Sep 17 00:00:00 2001 From: Batorian Date: Fri, 28 Feb 2025 19:07:16 +0100 Subject: [PATCH 5/6] genesis: revert version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 3d39a4a74..6330496cf 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "lnreader-plugins", - "version": "3.0.1", + "version": "3.0.0", "description": "Plugins repo for LNReader", "main": "index.js", "type": "module", From c4e81a601ab7796aa4edc07044f9c98c0d093e5e Mon Sep 17 00:00:00 2001 From: Batorian Date: Sat, 1 Mar 2025 03:26:23 +0100 Subject: [PATCH 6/6] genesis: fix popular novels --- src/plugins/english/genesis.ts | 58 +++++++++++++++++++--------------- 1 file changed, 33 insertions(+), 25 deletions(-) diff --git a/src/plugins/english/genesis.ts b/src/plugins/english/genesis.ts index aa08e702e..286e8d333 100644 --- a/src/plugins/english/genesis.ts +++ b/src/plugins/english/genesis.ts @@ -36,17 +36,25 @@ class Genesis implements Plugin.PluginBase { async popularNovels( pageNo: number, - { showLatestNovels, filters }: Plugin.PopularNovelsOptions, - ): Promise { + { + showLatestNovels, + filters, + }: Plugin.PopularNovelsOptions, + ): Promise { if (pageNo !== 1) return []; let link = `${this.site}/api/novels/search?`; if (showLatestNovels) { link += 'serialization=All&sort=Recent'; } else { - if (filters!.genres.value) { - link += filters!.genres.value; + if (filters?.genres.value.length) { + link += 'genres=' + filters.genres.value.join('&genres=') + '&'; + } + if (filters?.storyStatus.value) { + link += 'serialization=' + `${filters.storyStatus.value}` + '&'; + } + if (filters?.sort.value) { + link += 'sort=' + `${filters.sort.value}`; } - link += `&${filters!.storyStatus.value}&${filters!.sort.value}`; } const json = await fetchApi(link).then(r => r.json()); return this.parseNovels(json); @@ -465,21 +473,21 @@ class Genesis implements Plugin.PluginBase { filters = { sort: { label: 'Sort Results By', - value: 'sort=Popular', + value: 'Popular', options: [ - { label: 'Popular', value: 'sort=Popular' }, - { label: 'Recent', value: 'sort=Recent' }, - { label: 'Views', value: 'sort=Views' }, + { label: 'Popular', value: 'Popular' }, + { label: 'Recent', value: 'Recent' }, + { label: 'Views', value: 'Views' }, ], type: FilterTypes.Picker, }, storyStatus: { label: 'Status', - value: 'serialization=All', + value: 'All', options: [ - { label: 'All', value: 'serialization=All' }, - { label: 'Ongoing', value: 'serialization=Ongoing' }, - { label: 'Completed', value: 'serialization=Completed' }, + { label: 'All', value: 'All' }, + { label: 'Ongoing', value: 'Ongoing' }, + { label: 'Completed', value: 'Completed' }, ], type: FilterTypes.Picker, }, @@ -487,18 +495,18 @@ class Genesis implements Plugin.PluginBase { label: 'Genres', value: [], options: [ - { label: 'Action', value: 'genres=Action' }, - { label: 'Comedy', value: 'genres=Comedy' }, - { label: 'Drama', value: 'genres=Drama' }, - { label: 'Fantasy', value: 'genres=Fantasy' }, - { label: 'Harem', value: 'genres=Harem' }, - { label: 'Martial Arts', value: 'genres=Martial+Arts' }, - { label: 'Modern', value: 'genres=Modern' }, - { label: 'Mystery', value: 'genres=Mystery' }, - { label: 'Psychological', value: 'genres=Psychological' }, - { label: 'Romance', value: 'genres=Romance' }, - { label: 'Slice of life', value: 'genres=Slice+of+Life' }, - { label: 'Tragedy', value: 'genres=Tragedy' }, + { label: 'Action', value: 'Action' }, + { label: 'Comedy', value: 'Comedy' }, + { label: 'Drama', value: 'Drama' }, + { label: 'Fantasy', value: 'Fantasy' }, + { label: 'Harem', value: 'Harem' }, + { label: 'Martial Arts', value: 'Martial Arts' }, + { label: 'Modern', value: 'Modern' }, + { label: 'Mystery', value: 'Mystery' }, + { label: 'Psychological', value: 'Psychological' }, + { label: 'Romance', value: 'Romance' }, + { label: 'Slice of life', value: 'Slice of Life' }, + { label: 'Tragedy', value: 'Tragedy' }, ], type: FilterTypes.CheckboxGroup, },