From 495cd2050b574d8ac6bb52ce5176534abde3f0ee Mon Sep 17 00:00:00 2001 From: Batorian Date: Mon, 15 Jul 2024 15:52:15 +0200 Subject: [PATCH 01/21] novel-updates: automatic list update --- src/plugins/english/novelupdates.ts | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/plugins/english/novelupdates.ts b/src/plugins/english/novelupdates.ts index 427c474fd..14d0448b1 100644 --- a/src/plugins/english/novelupdates.ts +++ b/src/plugins/english/novelupdates.ts @@ -7,7 +7,7 @@ import { Plugin } from '@typings/plugin'; class NovelUpdates implements Plugin.PluginBase { id = 'novelupdates'; name = 'Novel Updates'; - version = '0.7.1'; + version = '0.8.0'; icon = 'src/en/novelupdates/icon.png'; customCSS = 'src/en/novelupdates/customCSS.css'; site = 'https://www.novelupdates.com/'; @@ -159,10 +159,11 @@ class NovelUpdates implements Plugin.PluginBase { chapterName = chapterName.replace(/\b\w/g, l => l.toUpperCase()).trim(); const chapterUrl = 'https:' + loadedCheerio(el).find('a').first().next().attr('href'); + const chapterId = chapterUrl.split('/').filter(Boolean).pop(); chapter.push({ name: chapterName, - path: chapterUrl.replace(this.site, ''), + path: `${chapterUrl.replace(this.site, '')},${chapterId},${novelId}`, }); }); @@ -582,6 +583,13 @@ class NovelUpdates implements Plugin.PluginBase { let chapterContent = ''; let chapterText = ''; + const novelId = chapterPath.split(',')[2]; + const chapterId = chapterPath.split(',')[1]; + chapterPath = chapterPath.split(',')[0]; + + await fetchApi( + `${this.site}readinglist_update.php?rid=${chapterId}&sid=${novelId}&checked=yes`, + ); const result = await fetchApi(this.site + chapterPath); const body = await result.text(); const url = result.url; From bf3bce2b1f7f572489758de36f10d92973194874 Mon Sep 17 00:00:00 2001 From: Batorian Date: Mon, 15 Jul 2024 16:47:18 +0200 Subject: [PATCH 02/21] novel-updates: only mark read when chapter available --- src/plugins/english/novelupdates.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/plugins/english/novelupdates.ts b/src/plugins/english/novelupdates.ts index 14d0448b1..75e6d6aaa 100644 --- a/src/plugins/english/novelupdates.ts +++ b/src/plugins/english/novelupdates.ts @@ -587,9 +587,6 @@ class NovelUpdates implements Plugin.PluginBase { const chapterId = chapterPath.split(',')[1]; chapterPath = chapterPath.split(',')[0]; - await fetchApi( - `${this.site}readinglist_update.php?rid=${chapterId}&sid=${novelId}&checked=yes`, - ); const result = await fetchApi(this.site + chapterPath); const body = await result.text(); const url = result.url; @@ -802,6 +799,10 @@ class NovelUpdates implements Plugin.PluginBase { ); } + await fetchApi( + `${this.site}readinglist_update.php?rid=${chapterId}&sid=${novelId}&checked=yes`, + ); + return chapterText; } From 3edf70df0da9439370b0c20316bbd0069f527a32 Mon Sep 17 00:00:00 2001 From: Batorian Date: Fri, 19 Jul 2024 15:35:24 +0200 Subject: [PATCH 03/21] progress-tracking: initial commit --- package.json | 2 +- src/plugins/english/novelupdates.ts | 6 ++++-- src/types/plugin.ts | 2 ++ 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index 3af1956ef..5c8de8d13 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/novelupdates.ts b/src/plugins/english/novelupdates.ts index 75e6d6aaa..dbdf7f3f1 100644 --- a/src/plugins/english/novelupdates.ts +++ b/src/plugins/english/novelupdates.ts @@ -7,7 +7,7 @@ import { Plugin } from '@typings/plugin'; class NovelUpdates implements Plugin.PluginBase { id = 'novelupdates'; name = 'Novel Updates'; - version = '0.8.0'; + version = '0.8.1'; icon = 'src/en/novelupdates/icon.png'; customCSS = 'src/en/novelupdates/customCSS.css'; site = 'https://www.novelupdates.com/'; @@ -163,7 +163,9 @@ class NovelUpdates implements Plugin.PluginBase { chapter.push({ name: chapterName, - path: `${chapterUrl.replace(this.site, '')},${chapterId},${novelId}`, + path: chapterUrl.replace(this.site, ''), + sourceNovelId: novelId, + sourceChapterId: chapterId, }); }); diff --git a/src/types/plugin.ts b/src/types/plugin.ts index 8f0a5478d..fef5f4073 100644 --- a/src/types/plugin.ts +++ b/src/types/plugin.ts @@ -17,6 +17,8 @@ export namespace Plugin { * For novel without pages only */ page?: string; + sourceNovelId?: string; + sourceChapterId?: string; } export interface NovelItem { name: string; From 9932c125e4daf51bfe719c0a6a1fe64fe5519c9a Mon Sep 17 00:00:00 2001 From: Batorian Date: Fri, 19 Jul 2024 17:00:34 +0200 Subject: [PATCH 04/21] progress-tracking: introduce trackProgress --- src/plugins/english/novelupdates.ts | 51 ++++++++++++++++++++--------- src/types/plugin.ts | 3 +- 2 files changed, 37 insertions(+), 17 deletions(-) diff --git a/src/plugins/english/novelupdates.ts b/src/plugins/english/novelupdates.ts index dbdf7f3f1..514d51786 100644 --- a/src/plugins/english/novelupdates.ts +++ b/src/plugins/english/novelupdates.ts @@ -7,7 +7,7 @@ import { Plugin } from '@typings/plugin'; class NovelUpdates implements Plugin.PluginBase { id = 'novelupdates'; name = 'Novel Updates'; - version = '0.8.1'; + version = '0.9.0'; icon = 'src/en/novelupdates/icon.png'; customCSS = 'src/en/novelupdates/customCSS.css'; site = 'https://www.novelupdates.com/'; @@ -98,8 +98,14 @@ class NovelUpdates implements Plugin.PluginBase { let loadedCheerio = parseHTML(body); + // Extract shortlink and update path if available + const shortlink = loadedCheerio('link[rel="shortlink"]').attr('href'); + const updatedPath = shortlink + ? shortlink.replace(this.site, '') + : novelPath; + const novel: Plugin.SourceNovel = { - path: novelPath, + path: updatedPath, name: loadedCheerio('.seriestitlenu').text() || 'Untitled', cover: loadedCheerio('.wpb_wrapper img').attr('src'), chapters: [], @@ -158,14 +164,17 @@ class NovelUpdates implements Plugin.PluginBase { } chapterName = chapterName.replace(/\b\w/g, l => l.toUpperCase()).trim(); const chapterUrl = - 'https:' + loadedCheerio(el).find('a').first().next().attr('href'); - const chapterId = chapterUrl.split('/').filter(Boolean).pop(); + 'https:' + + loadedCheerio(el) + .find('a') + .first() + .next() + .attr('href') + ?.replace(this.site, ''); chapter.push({ name: chapterName, - path: chapterUrl.replace(this.site, ''), - sourceNovelId: novelId, - sourceChapterId: chapterId, + path: chapterUrl, }); }); @@ -585,10 +594,6 @@ class NovelUpdates implements Plugin.PluginBase { let chapterContent = ''; let chapterText = ''; - const novelId = chapterPath.split(',')[2]; - const chapterId = chapterPath.split(',')[1]; - chapterPath = chapterPath.split(',')[0]; - const result = await fetchApi(this.site + chapterPath); const body = await result.text(); const url = result.url; @@ -801,13 +806,29 @@ class NovelUpdates implements Plugin.PluginBase { ); } - await fetchApi( - `${this.site}readinglist_update.php?rid=${chapterId}&sid=${novelId}&checked=yes`, - ); - return chapterText; } + async trackProgress(novelPath: string, chapterPath: string): Promise { + // Extract the novelId from the novelPath + const novelIdMatch = novelPath.match(/\?p=(\d+)/); + const novelId = novelIdMatch ? novelIdMatch[1] : null; + + // Extract the chapterId from the chapterPath + const chapterIdMatch = chapterPath.match(/\/(\d+)\//); + const chapterId = chapterIdMatch ? chapterIdMatch[1] : null; + + if (novelId && chapterId) { + await fetchApi( + `${this.site}readinglist_update.php?rid=${chapterId}&sid=${novelId}&checked=yes`, + ); + } else { + throw new Error( + `Invalid novelPath (${novelPath}) or chapterPath (${chapterPath}).`, + ); + } + } + async searchNovels( searchTerm: string, page: number, diff --git a/src/types/plugin.ts b/src/types/plugin.ts index fef5f4073..e4098c3a8 100644 --- a/src/types/plugin.ts +++ b/src/types/plugin.ts @@ -17,8 +17,6 @@ export namespace Plugin { * For novel without pages only */ page?: string; - sourceNovelId?: string; - sourceChapterId?: string; } export interface NovelItem { name: string; @@ -87,6 +85,7 @@ export namespace Plugin { */ parseNovel(novelPath: string): Promise; parseChapter(chapterPath: string): Promise; + trackProgress?(novelPath: string, chapterPath: string): Promise; searchNovels(searchTerm: string, pageNo: number): Promise; resolveUrl?(path: string, isNovel?: boolean): string; } From 54f3427ba656da1de4326c70e07b5f1011c7a65a Mon Sep 17 00:00:00 2001 From: Batorian Date: Fri, 19 Jul 2024 17:17:05 +0200 Subject: [PATCH 05/21] progress-tracking: fix? --- src/plugins/english/novelupdates.ts | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/plugins/english/novelupdates.ts b/src/plugins/english/novelupdates.ts index 514d51786..376c75458 100644 --- a/src/plugins/english/novelupdates.ts +++ b/src/plugins/english/novelupdates.ts @@ -92,9 +92,9 @@ class NovelUpdates implements Plugin.PluginBase { } async parseNovel(novelPath: string): Promise { - const url = this.site + novelPath; - const result = await fetchApi(url); - const body = await result.text(); + let url = this.site + novelPath; + let result = await fetchApi(url); + let body = await result.text(); let loadedCheerio = parseHTML(body); @@ -104,6 +104,12 @@ class NovelUpdates implements Plugin.PluginBase { ? shortlink.replace(this.site, '') : novelPath; + url = this.site + updatedPath; + result = await fetchApi(url); + body = await result.text(); + + loadedCheerio = parseHTML(body); + const novel: Plugin.SourceNovel = { path: updatedPath, name: loadedCheerio('.seriestitlenu').text() || 'Untitled', From 507eb4bd46f96fc0b13fbe48b252bd9ac8e6418a Mon Sep 17 00:00:00 2001 From: Batorian Date: Fri, 19 Jul 2024 17:46:09 +0200 Subject: [PATCH 06/21] progress-tracking: test --- src/plugins/english/novelupdates.ts | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/src/plugins/english/novelupdates.ts b/src/plugins/english/novelupdates.ts index 376c75458..d6415b450 100644 --- a/src/plugins/english/novelupdates.ts +++ b/src/plugins/english/novelupdates.ts @@ -7,7 +7,7 @@ import { Plugin } from '@typings/plugin'; class NovelUpdates implements Plugin.PluginBase { id = 'novelupdates'; name = 'Novel Updates'; - version = '0.9.0'; + version = '0.9.1'; icon = 'src/en/novelupdates/icon.png'; customCSS = 'src/en/novelupdates/customCSS.css'; site = 'https://www.novelupdates.com/'; @@ -85,16 +85,18 @@ class NovelUpdates implements Plugin.PluginBase { link += '&pg=' + page; - const body = await fetchApi(link).then(result => result.text()); + const result = await fetchApi(link); + const body = await result.text(); const loadedCheerio = parseHTML(body); + return this.parseNovels(loadedCheerio); } async parseNovel(novelPath: string): Promise { - let url = this.site + novelPath; - let result = await fetchApi(url); - let body = await result.text(); + const url = this.site + novelPath; + const result = await fetchApi(url); + const body = await result.text(); let loadedCheerio = parseHTML(body); @@ -104,15 +106,9 @@ class NovelUpdates implements Plugin.PluginBase { ? shortlink.replace(this.site, '') : novelPath; - url = this.site + updatedPath; - result = await fetchApi(url); - body = await result.text(); - - loadedCheerio = parseHTML(body); - const novel: Plugin.SourceNovel = { - path: updatedPath, - name: loadedCheerio('.seriestitlenu').text() || 'Untitled', + path: novelPath, + name: loadedCheerio('.seriestitlenu').text() + updatedPath || 'Untitled', cover: loadedCheerio('.wpb_wrapper img').attr('src'), chapters: [], }; From 90965ef15054b9b8d90c25bf1150bc863753dd55 Mon Sep 17 00:00:00 2001 From: Batorian Date: Fri, 19 Jul 2024 17:59:43 +0200 Subject: [PATCH 07/21] progress-tracking: test --- src/plugins/english/novelupdates.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/plugins/english/novelupdates.ts b/src/plugins/english/novelupdates.ts index d6415b450..2a62c57ee 100644 --- a/src/plugins/english/novelupdates.ts +++ b/src/plugins/english/novelupdates.ts @@ -7,7 +7,7 @@ import { Plugin } from '@typings/plugin'; class NovelUpdates implements Plugin.PluginBase { id = 'novelupdates'; name = 'Novel Updates'; - version = '0.9.1'; + version = '0.9.0'; icon = 'src/en/novelupdates/icon.png'; customCSS = 'src/en/novelupdates/customCSS.css'; site = 'https://www.novelupdates.com/'; @@ -107,8 +107,8 @@ class NovelUpdates implements Plugin.PluginBase { : novelPath; const novel: Plugin.SourceNovel = { - path: novelPath, - name: loadedCheerio('.seriestitlenu').text() + updatedPath || 'Untitled', + path: updatedPath, + name: loadedCheerio('.seriestitlenu').text() || 'Untitled', cover: loadedCheerio('.wpb_wrapper img').attr('src'), chapters: [], }; From 30464076234765c3905d589f5b8a53f7728590e4 Mon Sep 17 00:00:00 2001 From: Batorian Date: Fri, 19 Jul 2024 18:20:54 +0200 Subject: [PATCH 08/21] progress-tracking: test --- src/plugins/english/novelupdates.ts | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/src/plugins/english/novelupdates.ts b/src/plugins/english/novelupdates.ts index 2a62c57ee..a851cca62 100644 --- a/src/plugins/english/novelupdates.ts +++ b/src/plugins/english/novelupdates.ts @@ -100,14 +100,8 @@ class NovelUpdates implements Plugin.PluginBase { let loadedCheerio = parseHTML(body); - // Extract shortlink and update path if available - const shortlink = loadedCheerio('link[rel="shortlink"]').attr('href'); - const updatedPath = shortlink - ? shortlink.replace(this.site, '') - : novelPath; - const novel: Plugin.SourceNovel = { - path: updatedPath, + path: novelPath, name: loadedCheerio('.seriestitlenu').text() || 'Untitled', cover: loadedCheerio('.wpb_wrapper img').attr('src'), chapters: [], @@ -812,8 +806,18 @@ class NovelUpdates implements Plugin.PluginBase { } async trackProgress(novelPath: string, chapterPath: string): Promise { + const url = this.site + novelPath; + const result = await fetchApi(url); + const body = await result.text(); + + let loadedCheerio = parseHTML(body); + + // Extract shortlink and update path if available + const shortlink = loadedCheerio('link[rel="shortlink"]').attr('href'); + const updatedNovelPath = shortlink?.replace(this.site, ''); + // Extract the novelId from the novelPath - const novelIdMatch = novelPath.match(/\?p=(\d+)/); + const novelIdMatch = updatedNovelPath?.match(/\?p=(\d+)/); const novelId = novelIdMatch ? novelIdMatch[1] : null; // Extract the chapterId from the chapterPath From 3a7e1c60ea0306416a4ee84e018d79d527ffa2bf Mon Sep 17 00:00:00 2001 From: Batorian Date: Fri, 19 Jul 2024 18:48:26 +0200 Subject: [PATCH 09/21] progress-tracking: scribble hub update --- src/plugins/english/scribblehub.ts | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/src/plugins/english/scribblehub.ts b/src/plugins/english/scribblehub.ts index d0d2c42a2..e6f35a78e 100644 --- a/src/plugins/english/scribblehub.ts +++ b/src/plugins/english/scribblehub.ts @@ -9,7 +9,7 @@ class ScribbleHubPlugin implements Plugin.PluginBase { name = 'Scribble Hub'; icon = 'src/en/scribblehub/icon.png'; site = 'https://www.scribblehub.com/'; - version = '1.0.1'; + version = '1.1.0'; parseNovels(loadedCheerio: CheerioAPI) { const novels: Plugin.NovelItem[] = []; @@ -176,6 +176,34 @@ class ScribbleHubPlugin implements Plugin.PluginBase { return chapterText; } + async trackProgress(novelPath: string, chapterPath: string): Promise { + // Extract the novelId from the novelPath + const novelIdMatch = novelPath?.match(/\?p=(\d+)/); + const novelId = novelIdMatch ? novelIdMatch[1] : null; + + // Extract the chapterId from the chapterPath + const chapterIdMatch = chapterPath.match(/\/(\d+)\//); + const chapterId = chapterIdMatch ? chapterIdMatch[1] : null; + + const link = `${this.site}wp-admin/admin-ajax.php`; + + if (novelId && chapterId) { + const formData = new FormData(); + formData.append('action', 'wi_addchangerl'); + formData.append('strCID', chapterId); + formData.append('strSID', novelId); + + await fetchApi(link, { + method: 'POST', + body: formData, + }); + } else { + throw new Error( + `Invalid novelPath (${novelPath}) or chapterPath (${chapterPath}).`, + ); + } + } + async searchNovels(searchTerm: string): Promise { const url = `${this.site}?s=${searchTerm}&post_type=fictionposts`; const result = await fetchApi(url); From 9b7aee8cb20f09ff98784b72bbd9ac0b6b5adf67 Mon Sep 17 00:00:00 2001 From: Batorian Date: Fri, 19 Jul 2024 18:54:26 +0200 Subject: [PATCH 10/21] progress-tracking: fix regex --- src/plugins/english/scribblehub.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/plugins/english/scribblehub.ts b/src/plugins/english/scribblehub.ts index e6f35a78e..a70106631 100644 --- a/src/plugins/english/scribblehub.ts +++ b/src/plugins/english/scribblehub.ts @@ -178,11 +178,11 @@ class ScribbleHubPlugin implements Plugin.PluginBase { async trackProgress(novelPath: string, chapterPath: string): Promise { // Extract the novelId from the novelPath - const novelIdMatch = novelPath?.match(/\?p=(\d+)/); + const novelIdMatch = novelPath.match(/series\/(\d+)\//); const novelId = novelIdMatch ? novelIdMatch[1] : null; // Extract the chapterId from the chapterPath - const chapterIdMatch = chapterPath.match(/\/(\d+)\//); + const chapterIdMatch = chapterPath.match(/chapter\/(\d+)\//); const chapterId = chapterIdMatch ? chapterIdMatch[1] : null; const link = `${this.site}wp-admin/admin-ajax.php`; From 0cefbf1a7e7d6a9222e22b9f2727c0c1e9d8bf59 Mon Sep 17 00:00:00 2001 From: Batorian Date: Fri, 19 Jul 2024 19:22:27 +0200 Subject: [PATCH 11/21] progress-tracking: revert version --- package.json | 2 +- src/plugins/english/novelupdates.ts | 12 +++--------- 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/package.json b/package.json index 5c8de8d13..3af1956ef 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", diff --git a/src/plugins/english/novelupdates.ts b/src/plugins/english/novelupdates.ts index a851cca62..a2727036b 100644 --- a/src/plugins/english/novelupdates.ts +++ b/src/plugins/english/novelupdates.ts @@ -7,7 +7,7 @@ import { Plugin } from '@typings/plugin'; class NovelUpdates implements Plugin.PluginBase { id = 'novelupdates'; name = 'Novel Updates'; - version = '0.9.0'; + version = '0.8.0'; icon = 'src/en/novelupdates/icon.png'; customCSS = 'src/en/novelupdates/customCSS.css'; site = 'https://www.novelupdates.com/'; @@ -160,17 +160,11 @@ class NovelUpdates implements Plugin.PluginBase { } chapterName = chapterName.replace(/\b\w/g, l => l.toUpperCase()).trim(); const chapterUrl = - 'https:' + - loadedCheerio(el) - .find('a') - .first() - .next() - .attr('href') - ?.replace(this.site, ''); + 'https:' + loadedCheerio(el).find('a').first().next().attr('href'); chapter.push({ name: chapterName, - path: chapterUrl, + path: chapterUrl.replace(this.site, ''), }); }); From 350509efc4649ddfd9ef48217273a29766f4b8ac Mon Sep 17 00:00:00 2001 From: Batorian Date: Sun, 21 Jul 2024 19:48:16 +0200 Subject: [PATCH 12/21] progress-tracking: remove lint --- src/plugins/english/novelupdates.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/plugins/english/novelupdates.ts b/src/plugins/english/novelupdates.ts index 9c2ec70ac..943f3545c 100644 --- a/src/plugins/english/novelupdates.ts +++ b/src/plugins/english/novelupdates.ts @@ -1,4 +1,3 @@ -/* eslint-disable no-case-declarations */ import { CheerioAPI, load as parseHTML } from 'cheerio'; import { fetchApi } from '@libs/fetch'; import { Filters, FilterTypes } from '@libs/filterInputs'; From c0c682b01182a3f75203bc2883f9caa82a5f628a Mon Sep 17 00:00:00 2001 From: Batorian Date: Fri, 7 Mar 2025 02:02:07 +0100 Subject: [PATCH 13/21] progress-tracking: update --- src/plugins/english/novelupdates.ts | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/plugins/english/novelupdates.ts b/src/plugins/english/novelupdates.ts index 1a7e8d1a4..944a17366 100644 --- a/src/plugins/english/novelupdates.ts +++ b/src/plugins/english/novelupdates.ts @@ -2,6 +2,7 @@ import { CheerioAPI, load as parseHTML } from 'cheerio'; import { fetchApi } from '@libs/fetch'; import { Filters, FilterTypes } from '@libs/filterInputs'; import { Plugin } from '@typings/plugin'; +import { storage } from '@libs/storage'; class NovelUpdates implements Plugin.PluginBase { id = 'novelupdates'; @@ -10,6 +11,11 @@ class NovelUpdates implements Plugin.PluginBase { icon = 'src/en/novelupdates/icon.png'; customCSS = 'src/en/novelupdates/customCSS.css'; site = 'https://www.novelupdates.com/'; + imageRequestInit?: Plugin.ImageRequestInit | undefined = { + headers: { + 'referrer': this.site, + }, + }; parseNovels(loadedCheerio: CheerioAPI) { const novels: Plugin.NovelItem[] = []; @@ -995,7 +1001,7 @@ class NovelUpdates implements Plugin.PluginBase { const result = await fetchApi(url); const body = await result.text(); - let loadedCheerio = parseHTML(body); + const loadedCheerio = parseHTML(body); // Extract shortlink and update path if available const shortlink = loadedCheerio('link[rel="shortlink"]').attr('href'); @@ -1177,6 +1183,13 @@ class NovelUpdates implements Plugin.PluginBase { type: FilterTypes.CheckboxGroup, }, } satisfies Filters; + + pluginSettings = { + trackChapters: { + value: '', + label: 'Track chapters read status', + }, + }; } export default new NovelUpdates(); From 288acd814dff727de6252f6bf00b7ff5ade75d1e Mon Sep 17 00:00:00 2001 From: Batorian Date: Fri, 7 Mar 2025 04:03:07 +0100 Subject: [PATCH 14/21] progress-tracking: update --- src/plugins/english/novelupdates.ts | 55 ++++++++++++++--------------- src/types/plugin.ts | 5 ++- 2 files changed, 30 insertions(+), 30 deletions(-) diff --git a/src/plugins/english/novelupdates.ts b/src/plugins/english/novelupdates.ts index 944a17366..c49650a31 100644 --- a/src/plugins/english/novelupdates.ts +++ b/src/plugins/english/novelupdates.ts @@ -2,7 +2,6 @@ import { CheerioAPI, load as parseHTML } from 'cheerio'; import { fetchApi } from '@libs/fetch'; import { Filters, FilterTypes } from '@libs/filterInputs'; import { Plugin } from '@typings/plugin'; -import { storage } from '@libs/storage'; class NovelUpdates implements Plugin.PluginBase { id = 'novelupdates'; @@ -11,11 +10,6 @@ class NovelUpdates implements Plugin.PluginBase { icon = 'src/en/novelupdates/icon.png'; customCSS = 'src/en/novelupdates/customCSS.css'; site = 'https://www.novelupdates.com/'; - imageRequestInit?: Plugin.ImageRequestInit | undefined = { - headers: { - 'referrer': this.site, - }, - }; parseNovels(loadedCheerio: CheerioAPI) { const novels: Plugin.NovelItem[] = []; @@ -996,32 +990,34 @@ class NovelUpdates implements Plugin.PluginBase { return chapterText; } - async trackProgress(novelPath: string, chapterPath: string): Promise { - const url = this.site + novelPath; - const result = await fetchApi(url); - const body = await result.text(); - - const loadedCheerio = parseHTML(body); - - // Extract shortlink and update path if available - const shortlink = loadedCheerio('link[rel="shortlink"]').attr('href'); - const updatedNovelPath = shortlink?.replace(this.site, ''); - - // Extract the novelId from the novelPath - const novelIdMatch = updatedNovelPath?.match(/\?p=(\d+)/); - const novelId = novelIdMatch ? novelIdMatch[1] : null; - - // Extract the chapterId from the chapterPath - const chapterIdMatch = chapterPath.match(/\/(\d+)\//); - const chapterId = chapterIdMatch ? chapterIdMatch[1] : null; + async syncChapterProgress( + novel: Plugin.SourceNovel, + chapter: Plugin.ChapterItem, + ): Promise { + try { + // Get HTML content + const result = await fetchApi(this.site + novel.path); + const loadedCheerio = parseHTML(await result.text()); + + // Extract IDs + const shortlink = loadedCheerio('link[rel="shortlink"]').attr('href'); + const novelId = shortlink?.match(/\?p=(\d+)/)?.[1]; + const chapterId = chapter.path.match(/\/(\d+)\//)?.[1]; + + if (!novelId || !chapterId) { + throw new Error( + `Invalid novel path (${novel.path}) or chapter path (${chapter.path})`, + ); + } - if (novelId && chapterId) { + // Update reading progress await fetchApi( `${this.site}readinglist_update.php?rid=${chapterId}&sid=${novelId}&checked=yes`, ); - } else { + return true; + } catch (error) { throw new Error( - `Invalid novelPath (${novelPath}) or chapterPath (${chapterPath}).`, + `Failed to sync chapter progress: ${error instanceof Error ? error.message : 'Unknown error'}`, ); } } @@ -1185,9 +1181,10 @@ class NovelUpdates implements Plugin.PluginBase { } satisfies Filters; pluginSettings = { - trackChapters: { + syncChapterProgress: { value: '', - label: 'Track chapters read status', + label: 'Sync chapter progress with plugin site', + type: 'Switch', }, }; } diff --git a/src/types/plugin.ts b/src/types/plugin.ts index 8c68cb84b..a938b6b83 100644 --- a/src/types/plugin.ts +++ b/src/types/plugin.ts @@ -85,7 +85,10 @@ export namespace Plugin { */ parseNovel(novelPath: string): Promise; parseChapter(chapterPath: string): Promise; - trackProgress?(novelPath: string, chapterPath: string): Promise; + syncChapterProgress?( + novel: Plugin.SourceNovel, + chapter: Plugin.ChapterItem, + ): Promise; searchNovels(searchTerm: string, pageNo: number): Promise; resolveUrl?(path: string, isNovel?: boolean): string; }; From 50a08f7db6b7009753c403958873036e03538a98 Mon Sep 17 00:00:00 2001 From: Batorian Date: Mon, 17 Mar 2025 19:23:16 +0100 Subject: [PATCH 15/21] chapter-sync: update --- src/plugins/english/novelupdates.ts | 7 +++++-- src/types/plugin.ts | 6 ++++-- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/plugins/english/novelupdates.ts b/src/plugins/english/novelupdates.ts index c49650a31..acc5498f4 100644 --- a/src/plugins/english/novelupdates.ts +++ b/src/plugins/english/novelupdates.ts @@ -2,6 +2,7 @@ import { CheerioAPI, load as parseHTML } from 'cheerio'; import { fetchApi } from '@libs/fetch'; import { Filters, FilterTypes } from '@libs/filterInputs'; import { Plugin } from '@typings/plugin'; +import { storage } from '@libs/storage'; class NovelUpdates implements Plugin.PluginBase { id = 'novelupdates'; @@ -11,6 +12,8 @@ class NovelUpdates implements Plugin.PluginBase { customCSS = 'src/en/novelupdates/customCSS.css'; site = 'https://www.novelupdates.com/'; + syncChapter = storage.get('syncChapter'); + parseNovels(loadedCheerio: CheerioAPI) { const novels: Plugin.NovelItem[] = []; @@ -990,7 +993,7 @@ class NovelUpdates implements Plugin.PluginBase { return chapterText; } - async syncChapterProgress( + async syncChapterStatus( novel: Plugin.SourceNovel, chapter: Plugin.ChapterItem, ): Promise { @@ -1181,7 +1184,7 @@ class NovelUpdates implements Plugin.PluginBase { } satisfies Filters; pluginSettings = { - syncChapterProgress: { + syncChapter: { value: '', label: 'Sync chapter progress with plugin site', type: 'Switch', diff --git a/src/types/plugin.ts b/src/types/plugin.ts index a938b6b83..7be4720ca 100644 --- a/src/types/plugin.ts +++ b/src/types/plugin.ts @@ -72,8 +72,10 @@ export namespace Plugin { imageRequestInit?: ImageRequestInit; filters?: Filters; version: string; - //flag indicates whether access to LocalStorage, SesesionStorage is required. + // Flag indicates whether access to LocalStorage, SesesionStorage is required. webStorageUtilized?: boolean; + // Flag indicates whether chapter status is synced. + syncChapter?: boolean; popularNovels( pageNo: number, options: PopularNovelsOptions, @@ -85,7 +87,7 @@ export namespace Plugin { */ parseNovel(novelPath: string): Promise; parseChapter(chapterPath: string): Promise; - syncChapterProgress?( + syncChapterStatus?( novel: Plugin.SourceNovel, chapter: Plugin.ChapterItem, ): Promise; From f982769555858daf4d87f4e3c542646e56b73737 Mon Sep 17 00:00:00 2001 From: Batorian Date: Mon, 17 Mar 2025 20:25:27 +0100 Subject: [PATCH 16/21] chapter-sync: update test version --- package.json | 4 ++-- src/plugins/english/novelupdates.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index a302bfe88..ba9271d5a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "lnreader-plugins", - "version": "3.0.0", + "version": "3.1.0", "description": "Plugins repo for LNReader", "main": "index.js", "type": "module", @@ -67,4 +67,4 @@ "lint-staged": { "**/*.{js,ts,jsx,tsx}": "prettier --write" } -} \ No newline at end of file +} diff --git a/src/plugins/english/novelupdates.ts b/src/plugins/english/novelupdates.ts index acc5498f4..96f894e46 100644 --- a/src/plugins/english/novelupdates.ts +++ b/src/plugins/english/novelupdates.ts @@ -7,7 +7,7 @@ import { storage } from '@libs/storage'; class NovelUpdates implements Plugin.PluginBase { id = 'novelupdates'; name = 'Novel Updates'; - version = '0.8.0'; + version = '1.8.0'; icon = 'src/en/novelupdates/icon.png'; customCSS = 'src/en/novelupdates/customCSS.css'; site = 'https://www.novelupdates.com/'; From 1c12a1bceb3f468bcab367829acf5db1d2c1a052 Mon Sep 17 00:00:00 2001 From: Batorian Date: Mon, 17 Mar 2025 22:15:51 +0100 Subject: [PATCH 17/21] chapter-sync: update --- src/plugins/english/novelupdates.ts | 16 ++++++---------- src/types/plugin.ts | 4 ++-- 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/src/plugins/english/novelupdates.ts b/src/plugins/english/novelupdates.ts index 96f894e46..ad7f70566 100644 --- a/src/plugins/english/novelupdates.ts +++ b/src/plugins/english/novelupdates.ts @@ -994,23 +994,21 @@ class NovelUpdates implements Plugin.PluginBase { } async syncChapterStatus( - novel: Plugin.SourceNovel, - chapter: Plugin.ChapterItem, + novelPath: string, + chapterPath: string, ): Promise { try { // Get HTML content - const result = await fetchApi(this.site + novel.path); + const result = await fetchApi(this.site + novelPath); const loadedCheerio = parseHTML(await result.text()); // Extract IDs const shortlink = loadedCheerio('link[rel="shortlink"]').attr('href'); const novelId = shortlink?.match(/\?p=(\d+)/)?.[1]; - const chapterId = chapter.path.match(/\/(\d+)\//)?.[1]; + const chapterId = chapterPath.match(/\/(\d+)\//)?.[1]; if (!novelId || !chapterId) { - throw new Error( - `Invalid novel path (${novel.path}) or chapter path (${chapter.path})`, - ); + return false; } // Update reading progress @@ -1019,9 +1017,7 @@ class NovelUpdates implements Plugin.PluginBase { ); return true; } catch (error) { - throw new Error( - `Failed to sync chapter progress: ${error instanceof Error ? error.message : 'Unknown error'}`, - ); + return false; } } diff --git a/src/types/plugin.ts b/src/types/plugin.ts index 7be4720ca..8ee06675c 100644 --- a/src/types/plugin.ts +++ b/src/types/plugin.ts @@ -88,8 +88,8 @@ export namespace Plugin { parseNovel(novelPath: string): Promise; parseChapter(chapterPath: string): Promise; syncChapterStatus?( - novel: Plugin.SourceNovel, - chapter: Plugin.ChapterItem, + novelPath: string, + chapterPath: string, ): Promise; searchNovels(searchTerm: string, pageNo: number): Promise; resolveUrl?(path: string, isNovel?: boolean): string; From 1c67c8834f0ff1b456a7ae730fe01cb7b632b48c Mon Sep 17 00:00:00 2001 From: Batorian Date: Wed, 19 Mar 2025 15:32:07 +0100 Subject: [PATCH 18/21] chapter-sync: update --- src/plugins/english/novelupdates.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/english/novelupdates.ts b/src/plugins/english/novelupdates.ts index ad7f70566..10daaeffd 100644 --- a/src/plugins/english/novelupdates.ts +++ b/src/plugins/english/novelupdates.ts @@ -1011,7 +1011,7 @@ class NovelUpdates implements Plugin.PluginBase { return false; } - // Update reading progress + // Chapter sync await fetchApi( `${this.site}readinglist_update.php?rid=${chapterId}&sid=${novelId}&checked=yes`, ); From 5a5000c4eebbc3b599dd716d52d37e3c7d1b32a4 Mon Sep 17 00:00:00 2001 From: Batorian Date: Mon, 24 Mar 2025 04:15:51 +0100 Subject: [PATCH 19/21] chapter-sync: update --- package.json | 2 +- src/plugins/english/novelupdates.ts | 14 +++++----- src/plugins/english/scribblehub.ts | 43 +++++++++++++++++++---------- 3 files changed, 36 insertions(+), 23 deletions(-) diff --git a/package.json b/package.json index ba9271d5a..49b17efb9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "lnreader-plugins", - "version": "3.1.0", + "version": "3.0.0", "description": "Plugins repo for LNReader", "main": "index.js", "type": "module", diff --git a/src/plugins/english/novelupdates.ts b/src/plugins/english/novelupdates.ts index ae454344a..1a0388c09 100644 --- a/src/plugins/english/novelupdates.ts +++ b/src/plugins/english/novelupdates.ts @@ -909,21 +909,21 @@ class NovelUpdates implements Plugin.PluginBase { try { // Get HTML content const result = await fetchApi(this.site + novelPath); - const loadedCheerio = parseHTML(await result.text()); + const body = await result.text(); + const loadedCheerio = parseHTML(body); // Extract IDs const shortlink = loadedCheerio('link[rel="shortlink"]').attr('href'); const novelId = shortlink?.match(/\?p=(\d+)/)?.[1]; const chapterId = chapterPath.match(/\/(\d+)\//)?.[1]; - if (!novelId || !chapterId) { - return false; - } + // Validation + if (!novelId || !chapterId) return false; // Chapter sync - await fetchApi( - `${this.site}readinglist_update.php?rid=${chapterId}&sid=${novelId}&checked=yes`, - ); + const syncUrl = `${this.site}readinglist_update.php?rid=${chapterId}&sid=${novelId}&checked=yes`; + await fetchApi(syncUrl); + return true; } catch (error) { return false; diff --git a/src/plugins/english/scribblehub.ts b/src/plugins/english/scribblehub.ts index e4b9dc039..a1d1398c1 100644 --- a/src/plugins/english/scribblehub.ts +++ b/src/plugins/english/scribblehub.ts @@ -3,6 +3,7 @@ import { fetchApi } from '@libs/fetch'; import { FilterTypes, Filters } from '@libs/filterInputs'; import { Plugin } from '@typings/plugin'; import dayjs from 'dayjs'; +import { storage } from '@libs/storage'; class ScribbleHubPlugin implements Plugin.PluginBase { id = 'scribblehub'; @@ -11,6 +12,8 @@ class ScribbleHubPlugin implements Plugin.PluginBase { site = 'https://www.scribblehub.com/'; version = '1.1.0'; + syncChapter = storage.get('syncChapter'); + parseNovels(loadedCheerio: CheerioAPI) { const novels: Plugin.NovelItem[] = []; @@ -176,31 +179,33 @@ class ScribbleHubPlugin implements Plugin.PluginBase { return chapterText; } - async trackProgress(novelPath: string, chapterPath: string): Promise { - // Extract the novelId from the novelPath - const novelIdMatch = novelPath.match(/series\/(\d+)\//); - const novelId = novelIdMatch ? novelIdMatch[1] : null; - - // Extract the chapterId from the chapterPath - const chapterIdMatch = chapterPath.match(/chapter\/(\d+)\//); - const chapterId = chapterIdMatch ? chapterIdMatch[1] : null; + async syncChapterStatus( + novelPath: string, + chapterPath: string, + ): Promise { + try { + // Extract IDs from paths + const novelId = novelPath.match(/series\/(\d+)\//)?.[1]; + const chapterId = chapterPath.match(/chapter\/(\d+)\//)?.[1]; - const link = `${this.site}wp-admin/admin-ajax.php`; + // Validation + if (!novelId || !chapterId) return false; - if (novelId && chapterId) { const formData = new FormData(); formData.append('action', 'wi_addchangerl'); formData.append('strCID', chapterId); formData.append('strSID', novelId); - await fetchApi(link, { + // Chapter sync + const syncUrl = `${this.site}wp-admin/admin-ajax.php`; + await fetchApi(syncUrl, { method: 'POST', body: formData, }); - } else { - throw new Error( - `Invalid novelPath (${novelPath}) or chapterPath (${chapterPath}).`, - ); + + return true; + } catch (error) { + return false; } } @@ -326,6 +331,14 @@ class ScribbleHubPlugin implements Plugin.PluginBase { type: FilterTypes.ExcludableCheckboxGroup, }, } satisfies Filters; + + pluginSettings = { + syncChapter: { + value: '', + label: 'Sync chapter progress with plugin site', + type: 'Switch', + }, + }; } export default new ScribbleHubPlugin(); From b08ff6a5fd7e5ae6b1b43ae89c7ca9820d41fb3c Mon Sep 17 00:00:00 2001 From: Batorian Date: Mon, 24 Mar 2025 19:21:16 +0100 Subject: [PATCH 20/21] chapter-sync: update --- src/plugins/english/novelupdates.ts | 7 ++++--- src/plugins/english/scribblehub.ts | 7 ++++--- src/types/plugin.ts | 4 ++-- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/plugins/english/novelupdates.ts b/src/plugins/english/novelupdates.ts index 1a0388c09..c5d8493f4 100644 --- a/src/plugins/english/novelupdates.ts +++ b/src/plugins/english/novelupdates.ts @@ -3,6 +3,7 @@ import { fetchApi } from '@libs/fetch'; import { Filters, FilterTypes } from '@libs/filterInputs'; import { Plugin } from '@typings/plugin'; import { storage } from '@libs/storage'; +import ChapterItem = Plugin.ChapterItem; class NovelUpdates implements Plugin.PluginBase { id = 'novelupdates'; @@ -902,9 +903,9 @@ class NovelUpdates implements Plugin.PluginBase { return chapterCheerio.html()!; } - async syncChapterStatus( + async handleChapterEvent( novelPath: string, - chapterPath: string, + chapter: ChapterItem, ): Promise { try { // Get HTML content @@ -915,7 +916,7 @@ class NovelUpdates implements Plugin.PluginBase { // Extract IDs const shortlink = loadedCheerio('link[rel="shortlink"]').attr('href'); const novelId = shortlink?.match(/\?p=(\d+)/)?.[1]; - const chapterId = chapterPath.match(/\/(\d+)\//)?.[1]; + const chapterId = chapter.path.match(/\/(\d+)\//)?.[1]; // Validation if (!novelId || !chapterId) return false; diff --git a/src/plugins/english/scribblehub.ts b/src/plugins/english/scribblehub.ts index a1d1398c1..9b73ededa 100644 --- a/src/plugins/english/scribblehub.ts +++ b/src/plugins/english/scribblehub.ts @@ -4,6 +4,7 @@ import { FilterTypes, Filters } from '@libs/filterInputs'; import { Plugin } from '@typings/plugin'; import dayjs from 'dayjs'; import { storage } from '@libs/storage'; +import ChapterItem = Plugin.ChapterItem; class ScribbleHubPlugin implements Plugin.PluginBase { id = 'scribblehub'; @@ -179,14 +180,14 @@ class ScribbleHubPlugin implements Plugin.PluginBase { return chapterText; } - async syncChapterStatus( + async handleChapterEvent( novelPath: string, - chapterPath: string, + chapter: ChapterItem, ): Promise { try { // Extract IDs from paths const novelId = novelPath.match(/series\/(\d+)\//)?.[1]; - const chapterId = chapterPath.match(/chapter\/(\d+)\//)?.[1]; + const chapterId = chapter.path.match(/chapter\/(\d+)\//)?.[1]; // Validation if (!novelId || !chapterId) return false; diff --git a/src/types/plugin.ts b/src/types/plugin.ts index 28dff77d1..fa3ebcce2 100644 --- a/src/types/plugin.ts +++ b/src/types/plugin.ts @@ -89,9 +89,9 @@ export namespace Plugin { */ parseNovel(novelPath: string): Promise; parseChapter(chapterPath: string): Promise; - syncChapterStatus?( + handleChapterEvent?( novelPath: string, - chapterPath: string, + chapter: ChapterItem, ): Promise; searchNovels(searchTerm: string, pageNo: number): Promise; resolveUrl?(path: string, isNovel?: boolean): string; From c803979cd47c81268d28d83565de8c504319f25a Mon Sep 17 00:00:00 2001 From: Batorian Date: Tue, 25 Mar 2025 19:54:32 +0100 Subject: [PATCH 21/21] chapter-sync: update --- src/plugins/english/novelupdates.ts | 3 +-- src/plugins/english/scribblehub.ts | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/plugins/english/novelupdates.ts b/src/plugins/english/novelupdates.ts index c5d8493f4..120201270 100644 --- a/src/plugins/english/novelupdates.ts +++ b/src/plugins/english/novelupdates.ts @@ -3,7 +3,6 @@ import { fetchApi } from '@libs/fetch'; import { Filters, FilterTypes } from '@libs/filterInputs'; import { Plugin } from '@typings/plugin'; import { storage } from '@libs/storage'; -import ChapterItem = Plugin.ChapterItem; class NovelUpdates implements Plugin.PluginBase { id = 'novelupdates'; @@ -905,7 +904,7 @@ class NovelUpdates implements Plugin.PluginBase { async handleChapterEvent( novelPath: string, - chapter: ChapterItem, + chapter: Plugin.ChapterItem, ): Promise { try { // Get HTML content diff --git a/src/plugins/english/scribblehub.ts b/src/plugins/english/scribblehub.ts index 9b73ededa..c4941f2d1 100644 --- a/src/plugins/english/scribblehub.ts +++ b/src/plugins/english/scribblehub.ts @@ -4,7 +4,6 @@ import { FilterTypes, Filters } from '@libs/filterInputs'; import { Plugin } from '@typings/plugin'; import dayjs from 'dayjs'; import { storage } from '@libs/storage'; -import ChapterItem = Plugin.ChapterItem; class ScribbleHubPlugin implements Plugin.PluginBase { id = 'scribblehub'; @@ -182,7 +181,7 @@ class ScribbleHubPlugin implements Plugin.PluginBase { async handleChapterEvent( novelPath: string, - chapter: ChapterItem, + chapter: Plugin.ChapterItem, ): Promise { try { // Extract IDs from paths