133 lines
3.2 KiB
TypeScript
Executable File
133 lines
3.2 KiB
TypeScript
Executable File
//TODO Add optional extensions like limit at Posts with tags etc.
|
|
import * as xml_parser from "jsr:@melvdouc/xml-parser";
|
|
|
|
export type ImageResponse = {
|
|
preview_url: string;
|
|
sample_url: string;
|
|
file_url: string;
|
|
directory: number;
|
|
hash: string;
|
|
width: number;
|
|
height: number;
|
|
id: number;
|
|
image: string;
|
|
change: number;
|
|
owner: string;
|
|
parent_id: number;
|
|
rating: string;
|
|
sample: boolean;
|
|
sample_height: number;
|
|
sample_width: number;
|
|
score: number;
|
|
tags: string;
|
|
source: string;
|
|
status: string;
|
|
has_notes: boolean;
|
|
comment_count: number;
|
|
};
|
|
|
|
type CommentResponse = {
|
|
created_at: string;
|
|
post_id: number;
|
|
body: string;
|
|
creator: string;
|
|
id: number;
|
|
creator_id: number;
|
|
};
|
|
|
|
type TagResponse = {
|
|
type: number;
|
|
count: number;
|
|
name: string;
|
|
ambiguous: boolean;
|
|
id: number;
|
|
};
|
|
|
|
// Define the API URL
|
|
const baseUrl = "https://api.rule34.xxx";
|
|
export const postUrl = new URL(`${baseUrl}/index.php?page=dapi&s=post&q=index&json=1`);
|
|
const tagUrl = `${baseUrl}/index.php?page=dapi&s=tag&q=index`;
|
|
const commentsUrl = `${baseUrl}/index.php?page=dapi&s=comment&q=index`;
|
|
|
|
export async function requestJSON<T>(url: string) {
|
|
const response = await requestRaw(url);
|
|
return <T> await response.json();
|
|
}
|
|
|
|
async function requestRaw(url: string) {
|
|
const response = await fetch(url, {
|
|
headers: { "Accept": "application/json" },
|
|
});
|
|
if (!response.ok) {
|
|
throw new Error("Network response was not ok");
|
|
}
|
|
return response;
|
|
}
|
|
//List
|
|
|
|
// Comments
|
|
export async function getPostComments(postID: number): Promise<CommentResponse[]> {
|
|
const response = await requestRaw(`${commentsUrl}&post_id=${postID}`);
|
|
return XMLtoGenericDatatypeParser(response, parseComment);
|
|
}
|
|
|
|
export async function getTagByID(id: number): Promise<TagResponse[]> {
|
|
const response = await requestRaw(`${tagUrl}&id=${id}`);
|
|
return XMLtoGenericDatatypeParser(response, parseTag);
|
|
}
|
|
|
|
export async function getTagList(n: number): Promise<TagResponse[]> {
|
|
const response = await requestRaw(`${tagUrl}&limit=${n}`);
|
|
return XMLtoGenericDatatypeParser(response, parseTag);
|
|
}
|
|
|
|
function parseTag(attributes: Record<string, string>) {
|
|
return Object.fromEntries(
|
|
Object.entries(attributes).map(([k, v]) => {
|
|
if (k === "ambiguous") {
|
|
return [k, v === "true"];
|
|
} else if (k === "name") {
|
|
return [k, v];
|
|
} else {
|
|
return [k, convertStringtoNumber(v)];
|
|
}
|
|
}),
|
|
);
|
|
}
|
|
|
|
function parseComment(attributes: Record<string, string>) {
|
|
return Object.fromEntries(
|
|
Object.entries(attributes).map(([k, v]) => {
|
|
if (k === "id" || k === "creator_id" || k === "post_id") {
|
|
return [k, convertStringtoNumber(v)];
|
|
} else {
|
|
return [k, v];
|
|
}
|
|
}),
|
|
);
|
|
}
|
|
|
|
function convertStringtoNumber(str: string) {
|
|
return parseFloat(str);
|
|
}
|
|
|
|
async function XMLtoGenericDatatypeParser<T>(
|
|
response: Response,
|
|
callback: (attributes: Record<string, string>) => T,
|
|
) {
|
|
const parsedResponse = xml_parser.parse(await response.text());
|
|
const stack: T[] = [];
|
|
|
|
for (const v of parsedResponse) {
|
|
if (v.kind === "REGULAR_TAG_NODE") {
|
|
for (const entry of v.children) {
|
|
if (entry.kind === "ORPHAN_TAG_NODE") {
|
|
if (entry.attributes !== undefined) {
|
|
stack.push(callback(entry.attributes));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return stack;
|
|
} |