Plugin: Genesis studio (#1038)
* genesis: started implementation * genesis: wip * genesis: implemented parse novel * genesis: added icon * genesis: wip * genesis: added chapters * genesis: wip * genesis: updated chapter name * genesis: parse chapter * genesis: revert version * genesis: fixed pages and custom css * genesis: update * genesis: edit ta-center * genesis: remove line-height * genesis: old genesis deprecated
This commit is contained in:
@@ -0,0 +1,365 @@
|
||||
.red-box .red-text,
|
||||
.blue-box .blue-text,
|
||||
.gold-box .gold-text,
|
||||
.silver-box .silver-text {
|
||||
display:inline-flex;
|
||||
align-items:start;
|
||||
justify-content:start;
|
||||
text-align:left;
|
||||
flex-direction:column;
|
||||
margin-left:0;
|
||||
margin-bottom:0;
|
||||
margin-top:0
|
||||
}
|
||||
.red-box .red-text p,
|
||||
.blue-box .blue-text p,
|
||||
.gold-box .gold-text p,
|
||||
.silver-box .silver-text p {
|
||||
text-align:left
|
||||
}
|
||||
.ta-center {
|
||||
display:flex;
|
||||
text-align:center!important;
|
||||
align-items:center!important;
|
||||
justify-content:center!important;
|
||||
margin-left:auto;
|
||||
margin-right:auto
|
||||
}
|
||||
.ta-between {
|
||||
align-items:center!important
|
||||
}
|
||||
.blue-box,
|
||||
.red-box,
|
||||
.gold-box,
|
||||
.silver-box {
|
||||
overflow-wrap:break-word;
|
||||
word-wrap:break-word;
|
||||
word-break:break-word
|
||||
}
|
||||
.blue-box {
|
||||
display:flex;
|
||||
flex-direction:column;
|
||||
justify-content:center;
|
||||
min-width:250px;
|
||||
max-width:500px!important;
|
||||
box-sizing:content-box;
|
||||
width:auto;
|
||||
margin:15px auto;
|
||||
box-shadow:0 0 10px 1px #00219b;
|
||||
border-radius:5px;
|
||||
background-color:#000;
|
||||
padding:20px;
|
||||
font-size:25px;
|
||||
color:#fff;
|
||||
font-family: Oswald Variable, serif
|
||||
}
|
||||
.blue-box div {
|
||||
text-indent:0;
|
||||
max-width:500px!important
|
||||
}
|
||||
.blue-box p {
|
||||
text-align:center;
|
||||
text-indent:0;
|
||||
margin-bottom:.75rem;
|
||||
margin-top:.75rem;
|
||||
max-width:500px!important
|
||||
}
|
||||
.blue-title {
|
||||
display:flex;
|
||||
flex-direction:column;
|
||||
text-align:center;
|
||||
align-items:center;
|
||||
justify-content:center;
|
||||
padding-left:0;
|
||||
margin-left:0;
|
||||
color:#fff;
|
||||
font-weight:700;
|
||||
text-shadow:-1px 5px 13px #004fff,-1px 0 10px #002775;
|
||||
border-bottom:3px solid #fff;
|
||||
padding-bottom:15px;
|
||||
margin-bottom:15px;
|
||||
max-width:500px!important
|
||||
}
|
||||
.blue-text {
|
||||
display:flex;
|
||||
flex-direction:row;
|
||||
align-items:start;
|
||||
justify-content:center;
|
||||
text-shadow:-1px 5px 13px #004fff,-1px 0 10px #002775;
|
||||
font-weight:400;
|
||||
max-width:500px!important;
|
||||
font-family: Quattrocento, serif
|
||||
}
|
||||
.blue-text p {
|
||||
text-align:center;
|
||||
text-indent:0;
|
||||
margin-bottom:.25rem;
|
||||
margin-top:.25rem;
|
||||
max-width:500px!important
|
||||
}
|
||||
.red-box {
|
||||
display:flex;
|
||||
flex-direction:column;
|
||||
justify-content:center;
|
||||
min-width:250px;
|
||||
max-width:500px!important;
|
||||
padding:20px;
|
||||
box-sizing:content-box;
|
||||
width:auto;
|
||||
margin:15px auto;
|
||||
border:solid #750b00e3;
|
||||
box-shadow:0 0 20px 3px #750b0070;
|
||||
border-radius:5px;
|
||||
background-color:#000;
|
||||
font-size:25px;
|
||||
color:#fff;
|
||||
font-family: Oswald Variable, serif
|
||||
}
|
||||
.red-box div {
|
||||
text-indent:0;
|
||||
max-width:500px!important
|
||||
}
|
||||
.red-box p {
|
||||
text-align:center;
|
||||
text-indent:0;
|
||||
margin-bottom:.25rem;
|
||||
margin-top:.25rem;
|
||||
max-width:500px!important
|
||||
}
|
||||
.red-title {
|
||||
display:flex;
|
||||
flex-direction:column;
|
||||
text-align:center;
|
||||
align-items:center;
|
||||
justify-content:center;
|
||||
padding-left:0;
|
||||
margin-left:0;
|
||||
color:#ff4348;
|
||||
font-weight:700;
|
||||
text-shadow:-1px 5px 13px #ff230c,-1px 0px 10px #750b00;
|
||||
border-bottom:3px solid #fff;
|
||||
padding-bottom:15px;
|
||||
margin-bottom:15px;
|
||||
max-width:500px!important
|
||||
}
|
||||
.red-text {
|
||||
display:flex;
|
||||
flex-direction:row;
|
||||
align-items:center;
|
||||
justify-content:center;
|
||||
text-shadow:-1px 5px 13px #ff230c,-1px 0px 10px #750b00;
|
||||
font-weight:400;
|
||||
max-width:500px!important;
|
||||
margin-left:auto;
|
||||
margin-right:auto;
|
||||
font-family: Quattrocento, serif
|
||||
}
|
||||
.red-text p {
|
||||
text-align:center;
|
||||
text-indent:0;
|
||||
margin-bottom:.25rem;
|
||||
margin-top:.25rem;
|
||||
max-width:500px!important
|
||||
}
|
||||
.gold-box {
|
||||
display:flex;
|
||||
flex-direction:column;
|
||||
justify-content:center;
|
||||
min-width:250px;
|
||||
padding:20px;
|
||||
box-sizing:content-box;
|
||||
width:auto;
|
||||
margin:15px auto;
|
||||
border:solid #e0cc00;
|
||||
box-shadow:0 0 10px 1px #e0cc00;
|
||||
border-radius:5px;
|
||||
background-color:#000;
|
||||
font-size:25px;
|
||||
color:#fff;
|
||||
font-family: Oswald Variable, serif;
|
||||
max-width:500px!important
|
||||
}
|
||||
.gold-box div {
|
||||
text-indent:0;
|
||||
max-width:500px!important
|
||||
}
|
||||
.gold-box p {
|
||||
text-align:center;
|
||||
text-indent:0;
|
||||
margin-bottom:.75rem;
|
||||
margin-top:.75rem;
|
||||
max-width:500px!important
|
||||
}
|
||||
.gold-title {
|
||||
display:flex;
|
||||
flex-direction:column;
|
||||
text-align:center;
|
||||
align-items:center;
|
||||
justify-content:center;
|
||||
padding-left:0;
|
||||
margin-left:0;
|
||||
color:#fff;
|
||||
font-weight:700;
|
||||
text-shadow:-1px 5px 13px #e0cc00,-1px 0px 10px #544d00;
|
||||
border-bottom:3px solid #fff;
|
||||
padding-bottom:15px;
|
||||
margin-bottom:15px;
|
||||
max-width:500px!important
|
||||
}
|
||||
.gold-text {
|
||||
display:flex;
|
||||
flex-direction:row;
|
||||
align-items:center;
|
||||
justify-content:center;
|
||||
text-align:center;
|
||||
text-shadow:-1px 5px 13px #e0cc00,-1px 0 10px #e0cc00;
|
||||
row-gap:1.5rem;
|
||||
font-weight:400;
|
||||
max-width:500px!important;
|
||||
font-family: Quattrocento, serif
|
||||
}
|
||||
.gold-text p {
|
||||
text-align:center;
|
||||
text-indent:0;
|
||||
margin-bottom:.25rem;
|
||||
margin-top:.25rem;
|
||||
max-width:500px!important
|
||||
}
|
||||
.gold-letter {
|
||||
display:flex;
|
||||
flex-direction:column;
|
||||
align-items:center;
|
||||
justify-content:center;
|
||||
text-shadow:-1px 5px 13px #e0cc00,-1px 0 10px #e0cc00;
|
||||
row-gap:1.5rem;
|
||||
font-weight:700;
|
||||
font-family: Amita, serif;
|
||||
max-width:500px!important;
|
||||
margin-left:auto;
|
||||
margin-right:auto
|
||||
}
|
||||
.gold-letter p {
|
||||
text-align:center;
|
||||
text-indent:0;
|
||||
margin-bottom:.25rem;
|
||||
margin-top:.25rem;
|
||||
max-width:500px!important
|
||||
}
|
||||
.silver-box {
|
||||
display:flex;
|
||||
flex-direction:column;
|
||||
justify-content:center;
|
||||
min-width:250px;
|
||||
padding:20px;
|
||||
box-sizing:content-box;
|
||||
width:auto;
|
||||
margin:15px auto;
|
||||
border:solid #c2c2c2;
|
||||
box-shadow:0 0 10px 1px #737373;
|
||||
border-radius:5px;
|
||||
background-color:#000;
|
||||
font-size:25px;
|
||||
color:#fff;
|
||||
font-family: Oswald Variable, serif;
|
||||
max-width:500px!important
|
||||
}
|
||||
.silver-box div {
|
||||
text-indent:0;
|
||||
max-width:500px!important
|
||||
}
|
||||
.silver-box p {
|
||||
text-align:center;
|
||||
text-indent:0;
|
||||
margin-bottom:.75rem;
|
||||
margin-top:.75rem;
|
||||
max-width:500px!important
|
||||
}
|
||||
.silver-title {
|
||||
display:flex;
|
||||
flex-direction:column;
|
||||
text-align:center;
|
||||
align-items:center;
|
||||
justify-content:center;
|
||||
padding-left:0;
|
||||
margin-left:0;
|
||||
color:#fff;
|
||||
font-weight:700;
|
||||
text-shadow:-1px 5px 13px #b4b4b4,-1px 0 10px #737373;
|
||||
border-bottom:3px solid #fff;
|
||||
padding-bottom:15px;
|
||||
margin-bottom:15px;
|
||||
max-width:500px!important
|
||||
}
|
||||
.silver-text {
|
||||
display:flex;
|
||||
flex-direction:row;
|
||||
align-items:center;
|
||||
justify-content:center;
|
||||
text-shadow:-1px 5px 13px #b4b4b4,-1px 0 10px #737373;
|
||||
row-gap:1.5rem;
|
||||
font-weight:400;
|
||||
max-width:500px!important;
|
||||
margin: 2rem auto;
|
||||
font-family: Quattrocento, serif
|
||||
}
|
||||
.silver-text p {
|
||||
text-align:center;
|
||||
text-indent:0;
|
||||
margin-bottom:.25rem;
|
||||
margin-top:.25rem;
|
||||
max-width:500px!important
|
||||
}
|
||||
.silver-letter {
|
||||
display:flex;
|
||||
flex-direction:column;
|
||||
text-align:center;
|
||||
align-items:center;
|
||||
justify-content:center;
|
||||
text-shadow:-1px 5px 13px #b4b4b4,-1px 0 10px #737373;
|
||||
row-gap:1.5rem;
|
||||
font-weight:700;
|
||||
max-width:500px!important;
|
||||
margin: 2rem auto;
|
||||
font-family: MedievalSharp, serif
|
||||
}
|
||||
.silver-letter p {
|
||||
text-align:center;
|
||||
text-indent:0;
|
||||
margin-bottom:.25rem;
|
||||
margin-top:.25rem;
|
||||
max-width:500px!important
|
||||
}
|
||||
.blue-text,
|
||||
.gold-text,
|
||||
.silver-text,
|
||||
.red-text,
|
||||
.blue-box,
|
||||
.red-box,
|
||||
.gold-box,
|
||||
.silver-box,
|
||||
.red-title,
|
||||
.gold-title,
|
||||
.silver-title,
|
||||
.blue-title,
|
||||
.blue-text p,
|
||||
.gold-text p,
|
||||
.silver-text p,
|
||||
.red-text p {
|
||||
text-indent:0!important
|
||||
}
|
||||
div.red-text,
|
||||
div.gold-text,
|
||||
div.silver-text,
|
||||
div.blue-text {
|
||||
display:flex;
|
||||
flex-direction:column;
|
||||
margin-bottom:2.25rem;
|
||||
margin-top:2.25rem
|
||||
}
|
||||
.blue-box .blue-text p,
|
||||
.red-box .red-text p,
|
||||
.gold-box .gold-text p,
|
||||
.silver-box .silver-text p {
|
||||
display:flex;
|
||||
flex-direction:column
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 1.8 KiB |
@@ -93,7 +93,7 @@
|
||||
{
|
||||
"id": "genesistls",
|
||||
"sourceSite": "https://genesistls.com/",
|
||||
"sourceName": "GenesisTls",
|
||||
"sourceName": "GenesisTls (Deprecated)",
|
||||
"options": {
|
||||
"lang": "English",
|
||||
"reverseChapters": false,
|
||||
|
||||
@@ -0,0 +1,168 @@
|
||||
/* eslint-disable no-case-declarations */
|
||||
import { fetchApi } from '@libs/fetch';
|
||||
import { Filters, FilterTypes } from '@libs/filterInputs';
|
||||
import { Plugin } from '@typings/plugin';
|
||||
|
||||
class Genesis implements Plugin.PluginBase {
|
||||
id = 'genesistudio';
|
||||
name = 'Genesis';
|
||||
icon = 'src/en/genesis/icon.png';
|
||||
customCSS = 'src/en/genesis/customCSS.css';
|
||||
site = 'https://genesistudio.com';
|
||||
version = '1.0.0';
|
||||
imageRequestInit?: Plugin.ImageRequestInit | undefined = {
|
||||
headers: {
|
||||
'referrer': this.site,
|
||||
},
|
||||
};
|
||||
|
||||
async parseNovels(json: any[]): Promise<Plugin.NovelItem[]> {
|
||||
const assets = 'https://edit.genesistudio.com/assets/';
|
||||
const format = '?format=auto&quality=70&width=400&height=600';
|
||||
|
||||
return json.map((novel: any) => {
|
||||
return {
|
||||
name: novel.novel_title,
|
||||
path: `/novels/${novel.abbreviation}`,
|
||||
cover: `${assets}${novel.cover}${format}`,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
async popularNovels(
|
||||
pageNo: number,
|
||||
{
|
||||
showLatestNovels,
|
||||
filters,
|
||||
}: Plugin.PopularNovelsOptions<typeof this.filters>,
|
||||
): Promise<Plugin.NovelItem[]> {
|
||||
if (pageNo !== 1) return [];
|
||||
|
||||
let link = `https://genesistudio.com/api/search?`;
|
||||
if (showLatestNovels) {
|
||||
link += 'sort=Recent';
|
||||
} else {
|
||||
if (filters!.genres.value.length) {
|
||||
link += filters!.genres.value.join('&');
|
||||
}
|
||||
link += `&${filters!.storyStatus.value}&${filters!.sort.value}`;
|
||||
}
|
||||
|
||||
const json = await fetchApi(link).then(r => r.json());
|
||||
|
||||
return this.parseNovels(json);
|
||||
}
|
||||
|
||||
async parseNovel(novelPath: string): Promise<Plugin.SourceNovel> {
|
||||
const url = `${this.site}${novelPath}/__data.json?x-sveltekit-invalidated=001`;
|
||||
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 novelData = data[data[0].novel];
|
||||
|
||||
const assets = 'https://edit.genesistudio.com/assets/';
|
||||
const format = '?format=auto&quality=70&width=400&height=600';
|
||||
|
||||
const novel: Plugin.SourceNovel = {
|
||||
path: novelPath,
|
||||
name: data[novelData.novel_title],
|
||||
cover: `${assets}${data[novelData.cover]}${format}`,
|
||||
summary: data[novelData.synopsis],
|
||||
author: data[novelData.author],
|
||||
status: data[novelData.serialization],
|
||||
};
|
||||
|
||||
novel.genres = data[novelData.genres]
|
||||
.map((index: number) => data[index])
|
||||
.join(',');
|
||||
|
||||
const chapterData = data[data[0].chapters];
|
||||
const freeChapterData = chapterData.free;
|
||||
// const premiumChapterData = chapterData.premium;
|
||||
|
||||
novel.chapters = data[freeChapterData]
|
||||
.map((index: number) => data[index])
|
||||
.map((chapter: any) => {
|
||||
return {
|
||||
name: `Chapter ${data[chapter.chapter_number]}: ${data[chapter.chapter_title]}`,
|
||||
path: `/viewer/${data[chapter.id]}`,
|
||||
releaseTime: data[chapter.date_created],
|
||||
chapterNumber: data[chapter.chapter_number],
|
||||
};
|
||||
})
|
||||
.reverse();
|
||||
|
||||
return novel;
|
||||
}
|
||||
|
||||
async parseChapter(chapterPath: string): Promise<string> {
|
||||
const url = `${this.site}${chapterPath}/__data.json?x-sveltekit-invalidated=001`;
|
||||
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];
|
||||
|
||||
return data[data[0].content];
|
||||
}
|
||||
|
||||
async searchNovels(
|
||||
searchTerm: string,
|
||||
pageNo: number,
|
||||
): Promise<Plugin.NovelItem[]> {
|
||||
if (pageNo !== 1) return [];
|
||||
|
||||
const url = `${this.site}/api/search?serialization=All&sort=Popular&title=${searchTerm}`;
|
||||
const json = await fetchApi(url).then(r => r.json());
|
||||
|
||||
return this.parseNovels(json);
|
||||
}
|
||||
|
||||
filters = {
|
||||
sort: {
|
||||
label: 'Sort Results By',
|
||||
value: 'sort=Popular',
|
||||
options: [
|
||||
{ label: 'Popular', value: 'sort=Popular' },
|
||||
{ label: 'Recent', value: 'sort=Recent' },
|
||||
{ label: 'Views', value: 'sort=Views' },
|
||||
],
|
||||
type: FilterTypes.Picker,
|
||||
},
|
||||
storyStatus: {
|
||||
label: 'Status',
|
||||
value: 'serialization=All',
|
||||
options: [
|
||||
{ label: 'All', value: 'serialization=All' },
|
||||
{ label: 'Ongoing', value: 'serialization=Ongoing' },
|
||||
{ label: 'Completed', value: 'serialization=Completed' },
|
||||
],
|
||||
type: FilterTypes.Picker,
|
||||
},
|
||||
genres: {
|
||||
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' },
|
||||
],
|
||||
type: FilterTypes.CheckboxGroup,
|
||||
},
|
||||
} satisfies Filters;
|
||||
}
|
||||
|
||||
export default new Genesis();
|
||||
+1
-1
@@ -24,7 +24,7 @@ export namespace Plugin {
|
||||
cover?: string;
|
||||
}
|
||||
export interface SourceNovel extends NovelItem {
|
||||
/** Comma separated genre list */
|
||||
/** Comma separated genre list -> "action,fantasy,romance" */
|
||||
genres?: string;
|
||||
summary?: string;
|
||||
author?: string;
|
||||
|
||||
Reference in New Issue
Block a user