From 2c2d1d4dfd94a038be955f075f746f88e16b9bb2 Mon Sep 17 00:00:00 2001 From: Dredd1987 <102831270+Dredd1987@users.noreply.github.com> Date: Tue, 20 Aug 2024 05:46:58 +0300 Subject: [PATCH] feat: Add Sunovels (#1145) * Add files via upload * 2nd * another change with image * another change with image * another change with image * another change with image * another change with image * another change with image * another change with image * another change with image * another change with image * another change with image * another change with image * another change with image * another change with image * another change with image * another change with image * another change with image * another change with image * another change with image * another change with image * another change with image * another change with image * another change with image * clean up * clean up * fix handling single chapter stories * fix handling single chapter stories * fix handling single chapter stories * fix handling single chapter stories * fix handling single chapter stories * fix handling single chapter stories * fix handling single chapter stories * fix handling single chapter stories * fix handling single chapter stories * fix handling single chapter stories * fix handling single chapter stories * fix handling single chapter stories * fix handling single chapter stories * fix handling single chapter stories * fix handling single chapter stories * fix handling single chapter stories * fix handling single chapter stories * fix handling single chapter stories * fix handling single chapter stories * fix handling single chapter stories and minor cleanup * fix handling single chapter stories and minor cleanup * New source test * New source test * fix bugs * fix bugs * fix bugs * bugs fix * New arabic source rewayat.club * New arabic source rewayat.club * New arabic source rewayat.club * New arabic source rewayat.club * chapter release dates improvment for ao3 * edits * add chapter dates to ao3 * add chapter dates to ao3 * improve RewayatClub * new source sunovels * new source sunovels * fix images in source sunovels * fix images in source sunovels * fix filters in source sunovels * fix filters in source sunovels * fix filters in source sunovels * fix filters in source sunovels * fix filters in source sunovels * fix filters in source sunovels * fix filters in source sunovels * Update src/plugins/arabic/sunovels.ts Co-authored-by: K1ngfish3r * Update src/plugins/arabic/sunovels.ts Co-authored-by: K1ngfish3r --------- Co-authored-by: K1ngfish3r --- public/static/src/ar/sunovels/icon.png | Bin 0 -> 11079 bytes src/plugins/arabic/sunovels.ts | 306 +++++++++++++++++++++++++ 2 files changed, 306 insertions(+) create mode 100644 public/static/src/ar/sunovels/icon.png create mode 100644 src/plugins/arabic/sunovels.ts diff --git a/public/static/src/ar/sunovels/icon.png b/public/static/src/ar/sunovels/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..7f52667ae061e7b451d89434eb1ffef4895f8c4d GIT binary patch literal 11079 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 { + const regax = /\/uploads\/[^\s"]+/g; + const scriptText = loadedCheerio(ele).text(); + const imageUrlMatched = scriptText.match(regax); + if (imageUrlMatched) { + imageUrlList.push(...imageUrlMatched); + } + }); + let counter: number = 0; + loadedCheerio('.list-item').each((idx, ele) => { + loadedCheerio(ele) + .find('a') + .each((idx, ele) => { + const novelName = loadedCheerio(ele).find('h4').text().trim(); + const novelUrl = + loadedCheerio(ele).attr('href')?.trim().replace(/^\/*/, '') || ''; + let novelCover = defaultCover; + if (imageUrlList.length > 0) { + novelCover = this.site + imageUrlList[counter].slice(1); + } else { + const imageUrl = loadedCheerio(ele).find('img').attr('src'); + novelCover = this.site + imageUrl?.slice(1); + } + const novel = { + name: novelName, + cover: novelCover, + path: novelUrl, + }; + counter++; + novels.push(novel); + }); + }); + + return novels; + } + + async popularNovels( + page: number, + { showLatestNovels, filters }: Plugin.PopularNovelsOptions, + ): Promise { + const pageCorrected = page - 1; + let link = `${this.site}library?`; + + if (filters) { + if ( + Array.isArray(filters.categories.value) && + filters.categories.value.length > 0 + ) { + filters.categories.value.forEach((genre: string) => { + link += `&category=${genre}`; + }); + } + if (filters.status.value !== '') { + link += `&status=${filters.status.value}`; + } + } + link += `&page=${pageCorrected}`; + const body = await fetchApi(link).then(r => r.text()); + const loadedCheerio = parseHTML(body); + return this.parseNovels(loadedCheerio); + } + + async parseNovel( + novelUrl: string, + ): Promise { + const result = await fetchApi(new URL(novelUrl, this.site).toString()); + const body = await result.text(); + const loadedCheerio = parseHTML(body); + + const novel: Plugin.SourceNovel & { totalPages: number } = { + path: novelUrl, + name: loadedCheerio('div.main-head h3').text().trim() || 'Untitled', + author: loadedCheerio('.novel-author').text().trim(), + summary: loadedCheerio('section.info-section div.description p') + .text() + .trim(), + totalPages: 1, + chapters: [], + }; + const statusWords = new Set(['مكتمل', 'جديد', 'مستمر']); + const mainGenres = Array.from(loadedCheerio('div.categories li.tag')) + .map(el => loadedCheerio(el).text().trim()) + .join(','); + const statusGenre = Array.from( + loadedCheerio('div.header-stats span').eq(3).find('strong'), + ) + .map(el => loadedCheerio(el).text().trim()) + .filter(text => statusWords.has(text)); + novel.genres = `${statusGenre},${mainGenres}`; + const statusText = Array.from( + loadedCheerio('div.header-stats span').eq(3).find('strong'), + ) + .map(el => loadedCheerio(el).text().trim()) + .filter(text => statusWords.has(text)) + .join(); + novel.status = + { + 'جديد': 'Ongoing', + 'مكتمل': 'Completed', + 'مستمر': 'Ongoing', + }[statusText] || 'Unknown'; + const imageUrl = loadedCheerio('div.img-container figure.cover img').attr( + 'src', + ); + const imageUrlFull = this.site + imageUrl?.slice(1); + novel.cover = imageUrlFull; + const chapterNumberStr = loadedCheerio('div.header-stats span') + .first() + .text() + .replace(/[^\d]/g, ''); + const chapterNumber = parseInt(chapterNumberStr, 10); + const pageNumber = Math.ceil(chapterNumber / 50); + novel.totalPages = pageNumber; + + return novel; + } + parseChapters(data: { chapters: ChapterEntry[] }) { + const chapter: Plugin.ChapterItem[] = []; + data.chapters.map((item: ChapterEntry) => { + chapter.push({ + name: item.chapterName, + releaseTime: new Date(item.releaseTime).toISOString(), + path: item.chapterUrl, + chapterNumber: item.chapterNumber, + }); + }); + return chapter; + } + async parsePage(novelPath: string, page: string): Promise { + const numPage = parseInt(page, 10); + const pageCorrected = numPage - 1; + const pagePath = novelPath; + const firstUrl = this.site + pagePath; + const pageUrl = firstUrl + '?activeTab=chapters&page=' + pageCorrected; + const body = await fetchApi(pageUrl).then(r => r.text()); + const loadedCheerio = parseHTML(body); + let dataJson: { + pages_count: string; + chapters: ChapterEntry[]; + } = { pages_count: '', chapters: [] }; + const chaptersinfo: { + chapterName: string; + chapterUrl: string; + releaseTime: string; + chapterNumber: string | number; + }[] = []; + loadedCheerio('ul.chaptersList a').each((i, el) => { + const chapterName: string = loadedCheerio(el).attr('title') ?? ''; + const chapterUrl = loadedCheerio(el) + .attr('href') + ?.trim() + .replace(/^\/*/, ''); + const dateAttr = loadedCheerio(el) + .find('time.chapter-update') + .attr('datetime'); + const date = new Date(dateAttr); + const releaseTime = date.toISOString(); + const chapternumber = loadedCheerio(el) + .find('strong.chapter-title') + .text() + .replace(/[^\d٠-٩]/g, ''); + const chapterNumber = parseInt(chapternumber, 10); + chaptersinfo.push({ + chapterName: chapterName, + chapterUrl: chapterUrl || '', + releaseTime: releaseTime || '', + chapterNumber: chapterNumber || '', + }); + }); + const pagecount = loadedCheerio('ul.pagination a.active').text(); + dataJson.pages_count = pagecount; + + dataJson.chapters = chaptersinfo; + const chapters = this.parseChapters(dataJson); + return { + chapters, + }; + } + async parseChapter(chapterUrl: string): Promise { + const result = await fetchApi(new URL(chapterUrl, this.site).toString()); + const body = await result.text(); + const loadedCheerio = parseHTML(body); + let chapterText = ''; + loadedCheerio('div.chapter-content').each((idx, ele) => { + loadedCheerio(ele) + .find('p') + .not('.d-none') + .each((idx, textEle) => { + chapterText += + loadedCheerio(textEle) + .map((_, pEle) => loadedCheerio(pEle).text().trim()) + .get() + .join(' ') + ' '; + }); + }); + chapterText = chapterText.trim(); + return chapterText; + } + + async searchNovels( + searchTerm: string, + page: number, + ): Promise { + const searchUrl = `${this.site}search?page=${page}&title=${searchTerm}`; + + const result = await fetchApi(searchUrl); + const body = await result.text(); + const loadedCheerio = parseHTML(body); + return this.parseNovels(loadedCheerio); + } + + filters = { + categories: { + value: [], + label: 'التصنيفات', + options: [ + { label: 'Wuxia', value: 'Wuxia' }, + { label: 'Xianxia', value: 'Xianxia' }, + { label: 'XUANHUAN', value: 'XUANHUAN' }, + { label: 'أصلية', value: 'أصلية' }, // Original + { label: 'أكشن', value: 'أكشن' }, // Action + { label: 'إثارة', value: 'إثارة' }, // Thriller + { label: 'إنتقال الى عالم أخر', value: 'إنتقال+الى+عالم+أخر' }, // Isekai + { label: 'إيتشي', value: 'إيتشي' }, // Ecchi + { label: 'الخيال العلمي', value: 'الخيال+العلمي' }, // Science Fiction + { label: 'بوليسي', value: 'بوليسي' }, // Detective + { label: 'تاريخي', value: 'تاريخي' }, // Historical + { label: 'تقمص شخصيات', value: 'تقمص+شخصيات' }, // Roleplaying + { label: 'جريمة', value: 'جريمة' }, // Crime + { label: 'جوسى', value: 'جوسى' }, // Josei + { label: 'حريم', value: 'حريم' }, // Harem + { label: 'حياة مدرسية', value: 'حياة+مدرسية' }, // School Life + { label: 'خارقة للطبيعة', value: 'خارقة+للطبيعة' }, // Supernatural + { label: 'خيالي', value: 'خيالي' }, // Fantasy + { label: 'دراما', value: 'دراما' }, // Drama + { label: 'رعب', value: 'رعب' }, // Horror + { label: 'رومانسي', value: 'رومانسي' }, // Romance + { label: 'سحر', value: 'سحر' }, // Magic + { label: 'سينن', value: 'سينن' }, // Seinen + { label: 'شريحة من الحياة', value: 'شريحة+من+الحياة' }, // Slice of Life + { label: 'شونين', value: 'شونين' }, // Shounen + { label: 'غموض', value: 'غموض' }, // Mystery + { label: 'فنون القتال', value: 'فنون+القتال' }, // Martial Arts + { label: 'قوى خارقة', value: 'قوى+خارقة' }, // Super Powers + { label: 'كوميدى', value: 'كوميدى' }, // Comedy + { label: 'مأساوي', value: 'مأساوي' }, // Tragedy + { label: 'ما بعد الكارثة', value: 'ما+بعد+الكارثة' }, // Post-Apocalypse + { label: 'مغامرة', value: 'مغامرة' }, // Adventure + { label: 'ميكا', value: 'ميكا' }, // Mecha + { label: 'ناضج', value: 'ناضج' }, // Mature + { label: 'نفسي', value: 'نفسي' }, // Psychological + { label: 'فانتازيا', value: 'فانتازيا' }, // Fantasy + { label: 'رياضة', value: 'رياضة' }, // Sports + { label: 'ابراج', value: 'ابراج' }, // Astrology + { label: 'الالهة', value: 'الالهة' }, // Deities + { label: 'شياطين', value: 'شياطين' }, // Demons + { label: 'السفر عبر الزمن', value: 'السفر+عبر+الزمن' }, // Time Travel + { label: 'رواية صينية', value: 'رواية+صينية' }, // Chinese Novel + { label: 'رواية ويب', value: 'رواية+ويب' }, // Web Novel + { label: 'لايت نوفل', value: 'لايت+نوفل' }, // Light Novel + { label: 'كوري', value: 'كوري' }, // Korean + { label: '+18', value: '%2B18' }, // +18 + { label: 'إيسكاي', value: 'إيسكاي' }, // Isekai + { label: 'ياباني', value: 'ياباني' }, // Japanese + { label: 'مؤلفة', value: 'مؤلفة' }, // Authored + ], + type: FilterTypes.CheckboxGroup, + }, + status: { + value: '', + label: 'الحالة', + options: [ + { label: 'جميع الروايات', value: '' }, + { label: 'مكتمل', value: 'Completed' }, + { label: 'جديد', value: 'New' }, + { label: 'مستمر', value: 'Ongoing' }, + ], + type: FilterTypes.Picker, + }, + } satisfies Filters; +} + +export default new Sunovels(); + +interface ChapterEntry { + chapterName: string; + chapterUrl: string; + releaseTime: string; + chapterNumber: string | number; +}