feat: integrate xml-parser for API response handling and enhance data retrieval methods
This commit is contained in:
@@ -1,96 +1,168 @@
|
||||
import { assert } from "@std/assert/assert";
|
||||
import * as xml_parser from "jsr:@melvdouc/xml-parser";
|
||||
|
||||
type APIResponse = Array<{
|
||||
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 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 apiUrl =
|
||||
"https://api.rule34.xxx/index.php?page=dapi&s=post&q=index&json=1";
|
||||
const baseUrl = "https://api.rule34.xxx";
|
||||
const postUrl = `${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`;
|
||||
|
||||
// Make a GET request
|
||||
let baseResponse = await fetch(apiUrl, { headers: { "Accept": "application/json" } })
|
||||
.then(async (response) => {
|
||||
if (!response.ok) {
|
||||
throw new Error("Network response was not ok");
|
||||
}
|
||||
return <APIResponse> await response.json();
|
||||
});
|
||||
const hyperlinkarray: string[] = [];
|
||||
|
||||
// ---------------------------------
|
||||
// import * as stdHTML from "jsr:@std/html@1.0.2";
|
||||
// Deno.serve({ port: 6969 }, async (request) => {
|
||||
// const html = hyperlinkarray.map((x) => `<img src="${stdHTML.escape(x)}"/>`)
|
||||
// .join("\n");
|
||||
// return new Response(html, {
|
||||
// headers: { "Content-Type": "text/html;charset=utf-8" },
|
||||
// });
|
||||
// });
|
||||
// ---------------------------------
|
||||
|
||||
export async function refresh() {
|
||||
await fetch(apiUrl, { headers: { "Accept": "application/json" } })
|
||||
.then(async (response) => {
|
||||
if (!response.ok) {
|
||||
throw new Error("Network response was not ok");
|
||||
}
|
||||
baseResponse = <APIResponse> await response.json();
|
||||
for (const k of baseResponse) {
|
||||
if (!hyperlinkarray.includes(k.file_url)) {
|
||||
hyperlinkarray.push(k.file_url);
|
||||
}
|
||||
}
|
||||
});
|
||||
async function requestJSON<T>(URL: string) {
|
||||
const response = await requestRaw(URL);
|
||||
return <T> await response.json();
|
||||
}
|
||||
|
||||
for (const k of baseResponse) {
|
||||
hyperlinkarray.push(k.file_url);
|
||||
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;
|
||||
}
|
||||
|
||||
export async function dropRule() {
|
||||
if (hyperlinkarray.length === 0) {
|
||||
await refresh();
|
||||
return await dropRule();
|
||||
}
|
||||
return hyperlinkarray.pop()!;
|
||||
//List
|
||||
async function getPosts(n: number) {
|
||||
return await requestJSON<ImageResponse[]>(`${postUrl}&limit=${n}`);
|
||||
}
|
||||
|
||||
export async function dropRule5() {
|
||||
let tmp = "";
|
||||
for (let i = 0; i < 5; i++) {
|
||||
tmp += await dropRule() + "\n";
|
||||
}
|
||||
return tmp;
|
||||
async function getPostWithID(id: number) {
|
||||
return await requestJSON<ImageResponse[]>(
|
||||
`${postUrl}&id=${encodeURIComponent(id)}`,
|
||||
);
|
||||
}
|
||||
|
||||
async function getPID() {
|
||||
return await requestJSON<ImageResponse[]>(`${postUrl}&pid`);
|
||||
}
|
||||
|
||||
//test refresh here because local stack is not given to other functions
|
||||
Deno.test("Test Image-Stack refresh", async() => {
|
||||
await refresh()
|
||||
const previousStack = [...hyperlinkarray]
|
||||
await new Promise(r => setTimeout(r, 10000));
|
||||
await refresh()
|
||||
assert(previousStack.length <= hyperlinkarray.length, "Stack-size did not increase as expected!")
|
||||
})
|
||||
async function getTags(tags: string[]) {
|
||||
const list = tags.join("+");
|
||||
return await requestJSON<ImageResponse[]>(
|
||||
`${postUrl}&tags=${encodeURIComponent(list)}`,
|
||||
);
|
||||
}
|
||||
|
||||
// Comments
|
||||
async function getPostComments(postID: number) {
|
||||
const response = await requestRaw(`${commentsUrl}&post_id=${postID}`);
|
||||
return XMLtoGenericDatatypeParser(response, parseComment);
|
||||
}
|
||||
|
||||
async function getTagByID(id: number) {
|
||||
const response = await requestRaw(`${tagUrl}&id=${id}`);
|
||||
return XMLtoGenericDatatypeParser(response, parseTag);
|
||||
}
|
||||
|
||||
async function getTagList(n: number) {
|
||||
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;
|
||||
}
|
||||
|
||||
Deno.test("Post Comment", async () => {
|
||||
const response = await getPostComments(1213);
|
||||
console.debug(response);
|
||||
});
|
||||
|
||||
Deno.test("Get Tag by ID", async () => {
|
||||
const response = await getTagByID(1);
|
||||
console.debug(response);
|
||||
});
|
||||
|
||||
Deno.test("Get Tag List", async () => {
|
||||
const response = await getTagList(6);
|
||||
console.debug(response);
|
||||
});
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { assert } from "jsr:@std/assert";
|
||||
import { dropRule, refresh } from "@root/plugins/rule34/api.ts";
|
||||
// import { assert } from "jsr:@std/assert";
|
||||
// import { dropRule, refresh } from "@root/plugins/rule34/api.ts";
|
||||
|
||||
Deno.test("Test Drop", async () => {
|
||||
await refresh();
|
||||
const link = await dropRule();
|
||||
assert(link !== "", "Empty String was dropped!");
|
||||
});
|
||||
// Deno.test("Test Drop", async () => {
|
||||
// await refresh();
|
||||
// const link = await dropRule();
|
||||
// assert(link !== "", "Empty String was dropped!");
|
||||
// });
|
||||
|
||||
Reference in New Issue
Block a user