make chapters manually inited

master
Drake 1 year ago
parent f97020d326
commit 357097ab7d

@ -4,26 +4,16 @@ export default class Chapter {
#session: { #session: {
get: (path: string) => Promise<Response>; get: (path: string) => Promise<Response>;
}; };
isInited = false;
#document!: HTMLDocument; #document!: HTMLDocument;
#DOMParser: DOMParser; #DOMParser: DOMParser;
#id: ID; id: ID;
#workID: ID; workID: ID;
#name!: string; name!: string;
#html!: string; html!: string;
#text!: string; text!: string;
#summary!: string; summary!: string;
#startNote!: string; startNote!: string;
#endNote!: string; endNote!: string;
earlyName?: Promise<string>;
id!: Promise<ID>;
workID!: Promise<ID>;
name!: Promise<string>;
html!: Promise<string>;
text!: Promise<string>;
summary!: Promise<string>;
startNote!: Promise<string>;
endNote!: Promise<string>;
constructor( constructor(
workId: ID, workId: ID,
@ -36,45 +26,15 @@ export default class Chapter {
extraInfo: Record<string, any>, extraInfo: Record<string, any>,
) { ) {
this.#session = session; this.#session = session;
this.#workID = workId; this.workID = workId;
this.#id = id; this.id = id;
this.#DOMParser = DOMParser; this.#DOMParser = DOMParser;
this.earlyName = extraInfo.name; this.name = extraInfo.name;
return new Proxy(this, {
get: async (target, prop) => {
if (prop === "earlyName") {
return this.earlyName;
}
if (!this.isInited) {
await target.init();
target.isInited = true;
}
switch (prop) {
case "id":
return target.#id;
case "workID":
return target.#workID;
case "name":
return target.#name;
case "html":
return target.#html;
case "text":
return target.#text;
case "summary":
return target.#summary;
case "startNote":
return target.#startNote;
case "endNote":
return target.#endNote;
}
},
});
} }
async init() { async init() {
const res = await this.#session.get( const res = await this.#session.get(
`/works/${this.#workID}/chapters/${this.#id}?view_adult=true`, `/works/${this.workID}/chapters/${this.id}?view_adult=true`,
); );
this.#document = this.#DOMParser.parseFromString( this.#document = this.#DOMParser.parseFromString(
await res.text(), await res.text(),
@ -93,7 +53,7 @@ export default class Chapter {
} }
populateMetadata() { populateMetadata() {
this.#name = this.#document.querySelector("h3.title")?.innerText this.name = this.#document.querySelector("h3.title")?.innerText
.replace( .replace(
/Chapter \d+: /, /Chapter \d+: /,
"", "",
@ -101,7 +61,7 @@ export default class Chapter {
} }
populateSummary() { populateSummary() {
this.#summary = this.#document.querySelector("#summary > .userstuff") this.summary = this.#document.querySelector("#summary > .userstuff")
?.innerText.trim() as string; ?.innerText.trim() as string;
} }
@ -109,14 +69,14 @@ export default class Chapter {
const notesList = Array.from( const notesList = Array.from(
this.#document.querySelectorAll(".notes > .userstuff"), this.#document.querySelectorAll(".notes > .userstuff"),
).map((n) => (n as Element).innerHTML); ).map((n) => (n as Element).innerHTML);
this.#startNote = notesList[0]?.trim()?.replace(/<\/{0,1}p>/g, "\n") this.startNote = notesList[0]?.trim()?.replace(/<\/{0,1}p>/g, "\n")
?.trim(); ?.trim();
this.#endNote = notesList[1]?.trim()?.replace(/<\/{0,1}p>/g, "\n") this.endNote = notesList[1]?.trim()?.replace(/<\/{0,1}p>/g, "\n")
?.trim(); ?.trim();
} }
async populateText() { async populateText() {
this.#text = ""; this.text = "";
const elements = this.#document.querySelectorAll( const elements = this.#document.querySelectorAll(
"div.userstuff[role='article'] > p", "div.userstuff[role='article'] > p",
@ -125,25 +85,25 @@ export default class Chapter {
for (let i = 0; i < elements.length; i++) { for (let i = 0; i < elements.length; i++) {
const element = elements[i] as Element; const element = elements[i] as Element;
this.#text += element.innerText + "\n"; this.text += element.innerText + "\n";
} }
try { try {
this.#text = this.#text.trim(); this.text = this.text.trim();
this.#html = (this.#document.querySelector( this.html = (this.#document.querySelector(
"div.userstuff[role='article']", "div.userstuff[role='article']",
) as Element).innerHTML; ) as Element).innerHTML;
} catch { } catch {
//assume single chapter work //assume single chapter work
const res = await this.#session.get( const res = await this.#session.get(
`/works/${this.#workID}?view_adult=true`, `/works/${this.workID}?view_adult=true`,
); );
this.#document = this.#DOMParser.parseFromString( this.#document = this.#DOMParser.parseFromString(
await res.text(), await res.text(),
"text/html", "text/html",
) as HTMLDocument; ) as HTMLDocument;
this.#html = (this.#document.querySelector( this.html = (this.#document.querySelector(
"[role='article'] > div.userstuff", "[role='article'] > div.userstuff",
) as Element).innerHTML; ) as Element).innerHTML;
@ -154,8 +114,8 @@ export default class Chapter {
for (let i = 0; i < elements.length; i++) { for (let i = 0; i < elements.length; i++) {
const element = elements[i] as Element; const element = elements[i] as Element;
this.#text += element.innerText + "\n"; this.text += element.innerText + "\n";
this.#html += element.innerHTML; this.html += element.innerHTML;
} }
} }
} }

@ -75,19 +75,6 @@ export default class Work {
} }
populateTags() { populateTags() {
/* this.#document.querySelectorAll("dd.fandom > ul.commas > li").map(
(t) => this.tags.push(t.text),
);
this.#document.querySelectorAll("dd.relationship > ul.commas > li").map(
(t) => this.tags.push(t.text),
);
this.#document.querySelectorAll("dd.character > ul.commas > li").map(
(t) => this.tags.push(t.text),
);
this.#document.querySelectorAll("dd.freeform > ul.commas > li").map(
(t) => this.tags.push(t.text),
); */
const elements = this.#document.querySelectorAll("dd > ul.commas > li"); const elements = this.#document.querySelectorAll("dd > ul.commas > li");
for (let i = 0; i < elements.length; i++) { for (let i = 0; i < elements.length; i++) {

@ -1,40 +1,56 @@
//FIXME: we need to test single-chapter works too (because those seem to be really inconsistent for some reason?) //FIXME: we need to test single-chapter works too (because those seem to be really inconsistent for some reason?)
import AO3 from "../mod.ts"; import AO3 from "../mod.ts";
import { assert } from "https://deno.land/std@0.167.0/testing/asserts.ts"; import {
assert,
AssertionError,
} from "https://deno.land/std@0.167.0/testing/asserts.ts";
export default function test(ao3: AO3) { export default function test(ao3: AO3) {
Deno.test("chapters", async (test) => { Deno.test("chapters", async (test) => {
const work = await ao3.getWork("43251729"); const work = await ao3.getWork("43251729");
await work.init(); await work.init();
assert(work.chapters.length > 0, "chapters array is not initialized"); await test.step("initialization", async () => {
await test.step("IDs", async () => {
assert( assert(
await work.chapters[0].id === "108714198", work.chapters.length > 0,
"chapters array is not initialized",
);
try {
await work.chapters[0].init();
await work.chapters[3].init();
} catch {
throw new AssertionError("failed to initialize chapter");
}
});
await test.step("IDs", () => {
assert(
work.chapters[0].id === "108714198",
"incorrect chapter ID", "incorrect chapter ID",
); );
assert( assert(
await work.chapters[0].workID === "43251729", work.chapters[0].workID === "43251729",
"incorrect work ID", "incorrect work ID",
); //why do we even store the work's ID publicly in a chapter? ); //why do we even store the work's ID publicly in a chapter?
}); });
await test.step("name", async () => { await test.step("name", () => {
assert( assert(
await work.chapters[0].name === "Welcome to the Studio", work.chapters[0].name === "Welcome to the Studio",
"incorrect/missing chapter names", "incorrect/missing chapter names",
); );
}); });
await test.step("content", async () => { await test.step("content", () => {
//FIXME: this should probably be tested better //FIXME: this should probably be tested better
assert( assert(
(await work.chapters[0].text).length > 0, (work.chapters[0].text).length > 0,
"text/content is completely missing", "text/content is completely missing",
); );
}); });
await test.step("notes and summary", async () => { await test.step("notes and summary", () => {
//FIXME: write a chapter of my fic (lol) that includes a summary and end note for testing //FIXME: write a chapter of my fic (lol) that includes a summary and end note for testing
assert( assert(
await work.chapters[3].startNote === work.chapters[3].startNote ===
`If you haven't noticed yet, most of these chapters are named after Bendy fansongs `If you haven't noticed yet, most of these chapters are named after Bendy fansongs
This is definitely because I'm trying to be smart and cool and make funny references, and definitely not because I'm uncreative :)`, This is definitely because I'm trying to be smart and cool and make funny references, and definitely not because I'm uncreative :)`,

@ -1,5 +1,4 @@
import AO3 from "../mod.ts"; import AO3 from "../mod.ts";
import type { Search } from "../mod.ts";
import { assert } from "https://deno.land/std@0.167.0/testing/asserts.ts"; import { assert } from "https://deno.land/std@0.167.0/testing/asserts.ts";
export default function test(ao3: AO3) { export default function test(ao3: AO3) {

Loading…
Cancel
Save