Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion plugins/multisrc/madara/sources.json
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,9 @@
"sourceSite": "https://www.foxaholic.com/",
"sourceName": "Foxaholic",
"options": {
"useNewChapterEndpoint": true
"useNewChapterEndpoint": true,
"resolveCoverDataUri": true,
"versionIncrements": 1
}
},
{
Expand Down
94 changes: 81 additions & 13 deletions plugins/multisrc/madara/template.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ type MadaraOptions = {
customJs?: string;
hasLocked?: boolean;
browserHeaders?: boolean;
resolveCoverDataUri?: boolean;
};

export type MadaraMetadata = {
Expand Down Expand Up @@ -139,6 +140,26 @@ export class MadaraPlugin implements Plugin.PluginBase {
return $;
}

extractCover(image: Cheerio<AnyNode>): string {
const candidates = [
image.attr('data-lazy-src'),
image.attr('data-src'),
image.attr('data-cfsrc'),
image.attr('data-srcset')?.split(' ')[0],
image.attr('data-lazy-srcset')?.split(' ')[0],
image.attr('srcset')?.split(' ')[0],
image.attr('src'),
];

for (const candidate of candidates) {
if (candidate && !candidate.includes('dflazy')) {
return candidate;
}
}

return defaultCover;
}

parseNovels(loadedCheerio: CheerioAPI): Plugin.NovelItem[] {
const novels: Plugin.NovelItem[] = [];

Expand All @@ -154,12 +175,10 @@ export class MadaraPlugin implements Plugin.PluginBase {
loadedCheerio(element).find('.post-title').find('a').attr('href') ||
'';
if (!novelName || !novelUrl) return;
const image = loadedCheerio(element).find('img');
const novelCover =
image.attr('data-src') ||
image.attr('src') ||
image.attr('data-lazy-srcset') ||
defaultCover;
const novelCover = this.extractCover(
loadedCheerio(element).find('img'),
);
Comment thread
7ui77 marked this conversation as resolved.

const novel: Plugin.NovelItem = {
name: novelName,
cover: novelCover,
Expand All @@ -172,6 +191,57 @@ export class MadaraPlugin implements Plugin.PluginBase {
return novels;
}

async resolveCoverAsDataUri(url: string): Promise<string> {
if (!url || !url.startsWith('http') || url.startsWith('data:')) return url;
let timeout: ReturnType<typeof setTimeout> | null = null;
try {
const controller =
typeof AbortController !== 'undefined' ? new AbortController() : null;
timeout = controller ? setTimeout(() => controller.abort(), 4000) : null;
const res = await fetchApi(url, {
headers: this.requestHeaders,
...(controller ? { signal: controller.signal } : {}),
});
if (!res.ok) return url;
const blob = await res.blob();
return await new Promise<string>(resolve => {
const FileReaderClass =
typeof FileReader !== 'undefined'
? FileReader
: (globalThis as any).FileReader;
if (!FileReaderClass) return resolve(url);
const fr = new FileReaderClass();
fr.onloadend = () => {
if (typeof fr.result === 'string') {
resolve(fr.result);
} else {
resolve(url);
}
};
fr.onerror = () => resolve(url);
fr.readAsDataURL(blob);
});
} catch {
return url;
} finally {
if (timeout) clearTimeout(timeout);
}
}

async resolveNovelsCovers(
novels: Plugin.NovelItem[],
): Promise<Plugin.NovelItem[]> {
if (!this.options?.resolveCoverDataUri) return novels;
await Promise.all(
novels.map(async novel => {
if (novel.cover && novel.cover.startsWith('http')) {
novel.cover = await this.resolveCoverAsDataUri(novel.cover);
}
}),
);
return novels;
}

async popularNovels(
pageNo: number,
{
Expand All @@ -189,7 +259,8 @@ export class MadaraPlugin implements Plugin.PluginBase {
else if (filters[key].value) url += `&${key}=${filters[key].value}`;
}
const loadedCheerio = await this.getCheerio(url, pageNo != 1);
return this.parseNovels(loadedCheerio);
const novels = this.parseNovels(loadedCheerio);
return await this.resolveNovelsCovers(novels);
}

async parseNovel(novelPath: string): Promise<Plugin.SourceNovel> {
Expand All @@ -205,11 +276,7 @@ export class MadaraPlugin implements Plugin.PluginBase {
'',
};

novel.cover =
loadedCheerio('.summary_image > a > img').attr('data-lazy-src') ||
loadedCheerio('.summary_image > a > img').attr('data-src') ||
loadedCheerio('.summary_image > a > img').attr('src') ||
defaultCover;
novel.cover = this.extractCover(loadedCheerio('.summary_image > a > img'));

loadedCheerio('.post-content_item, .post-content').each(function () {
const detailName = loadedCheerio(this).find('h5').text().trim();
Expand Down Expand Up @@ -446,7 +513,8 @@ export class MadaraPlugin implements Plugin.PluginBase {
encodeURIComponent(searchTerm) +
'&post_type=wp-manga';
const loadedCheerio = await this.getCheerio(url, true);
return this.parseNovels(loadedCheerio);
const novels = this.parseNovels(loadedCheerio);
return await this.resolveNovelsCovers(novels);
}

parseData = (date: string) => {
Expand Down
Loading