You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

121 lines
3.2 KiB

//NOTE: AO3's searching "api" is an absolute clusterfuck. i'm sorry.
import Work from "./Work.ts";
import asyncForEach from "../utils/asyncForeach.ts";
import type {
DOMParser,
} from "https://denopkg.dev/gh/Ruthenic/deno-dom@master/src/dom/dom-parser.ts";
import type {
Element,
} from "https://denopkg.dev/gh/Ruthenic/deno-dom@master/src/dom/element.ts";
import type {
HTMLDocument,
} from "https://denopkg.dev/gh/Ruthenic/deno-dom@master/src/dom/document.ts";
export const Ratings = {
unrated: 9,
generalAudiences: 10,
teenAudiences: 11,
mature: 12,
explicit: 13,
};
export const Warnings = {
creatorChoseNotToUseArchiveWarnings: 14,
noArchiveWarningsApply: 16,
graphicDepictionsOfViolence: 17,
majorCharacterDeath: 18,
noncon: 19,
underage: 20,
};
export interface SearchParameters {
/*
* the amount of works to fetch
*
*/
limit?: number;
any?: string;
title?: string;
author?: string;
single_chapter?: boolean;
word_count?: number;
language?: string;
fandoms?: string[];
freeform?: string[];
ratings?: number[];
warnings?: number[];
}
export default class Search {
#baseApiURL = "/works/search?commit=Search";
#opts: SearchParameters;
#session: {
get: (path: string) => Promise<Response>;
};
#document!: HTMLDocument;
#DOMParser: DOMParser;
results: Work[] = [];
#urlConstructor(pageNum = 1) {
let url = this.#baseApiURL;
url += `&page=${pageNum}
&work_search[query]=${this.#opts.any ?? ""}
&work_search[title]=${this.#opts.title ?? ""}
&work_search[creators]=${this.#opts.author ?? ""}
&${
this.#opts.freeform?.map((v) => `work_search[freeform_names]=${v}`)
.join("&")
}`;
console.log(url);
return url;
}
constructor(opts: SearchParameters, session: {
get: (path: string) => Promise<Response>;
}, DOMParser: DOMParser) {
this.#session = session;
this.#opts = opts;
this.#DOMParser = DOMParser;
}
async update(pageNum: number) {
this.results = [];
const url = this.#urlConstructor(pageNum);
const res = await this.#session.get(url);
this.#document = this.#DOMParser.parseFromString(
await res.text(),
"text/html",
) as HTMLDocument;
let i = 0;
const limit = this.#opts.limit ?? 20;
await asyncForEach(
Array.from(this.#document.querySelectorAll("[role='article']")),
async (e: Element) => {
if (i >= limit) {
return;
}
const workId = e.id.replace("work_", "");
console.log(workId);
const res = await this.#session.get(
`/works/${workId}?view_adult=true&view_full_work=true`,
);
const work = new Work(
workId,
await res.text(),
this.#session,
this.#DOMParser,
);
await work.init();
this.results.push(work);
i++;
},
);
}
}