feat: enhance API functionality with new request handling and export methods

This commit is contained in:
fzzin
2025-03-30 04:18:28 +02:00
parent f55b5579ad
commit fe4e6690d4
4 changed files with 125 additions and 88 deletions

View File

@@ -1,6 +1,7 @@
//TODO Add optional extensions like limit at Posts with tags etc.
import * as xml_parser from "jsr:@melvdouc/xml-parser";
type ImageResponse = {
export type ImageResponse = {
preview_url: string;
sample_url: string;
file_url: string;
@@ -44,11 +45,11 @@ type TagResponse = {
// Define the API URL
const baseUrl = "https://api.rule34.xxx";
const postUrl = `${baseUrl}/index.php?page=dapi&s=post&q=index&json=1`;
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`;
async function requestJSON<T>(URL: string) {
export async function requestJSON<T>(URL: string) {
const response = await requestRaw(URL);
return <T> await response.json();
}
@@ -62,41 +63,20 @@ async function requestRaw(URL: string) {
}
return response;
}
//List
async function getPosts(n: number) {
return await requestJSON<ImageResponse[]>(`${postUrl}&limit=${n}`);
}
async function getPostWithID(id: number) {
return await requestJSON<ImageResponse[]>(
`${postUrl}&id=${encodeURIComponent(id)}`,
);
}
async function getPID() {
return await requestJSON<ImageResponse[]>(`${postUrl}&pid`);
}
async function getTags(tags: string[]) {
const list = tags.join("+");
return await requestJSON<ImageResponse[]>(
`${postUrl}&tags=${encodeURIComponent(list)}`,
);
}
// Comments
async function getPostComments(postID: number) {
export async function getPostComments(postID: number): Promise<CommentResponse[]> {
const response = await requestRaw(`${commentsUrl}&post_id=${postID}`);
return XMLtoGenericDatatypeParser(response, parseComment);
}
async function getTagByID(id: number) {
export async function getTagByID(id: number): Promise<TagResponse[]> {
const response = await requestRaw(`${tagUrl}&id=${id}`);
return XMLtoGenericDatatypeParser(response, parseTag);
}
async function getTagList(n: number) {
export async function getTagList(n: number): Promise<TagResponse[]> {
const response = await requestRaw(`${tagUrl}&limit=${n}`);
return XMLtoGenericDatatypeParser(response, parseTag);
}
@@ -150,19 +130,4 @@ async function XMLtoGenericDatatypeParser<T>(
}
}
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);
});
}

View File

@@ -1,44 +1,22 @@
import { Bot, Message } from "npm:discordeno@18.0.1";
import { dropRule5, dropRule, refresh } from "./api.ts";
import { drop, help, requestWorker } from "./plugin.ts";
import { logMessage } from "@root/logging.ts";
import { defaultString } from "@root/defaultString.ts";
export async function rule34MessageHandler(bot: Bot, message: Message) {
const command = message.content.split(" ").slice(1).join(" ");
switch (command) {
case `drop`:
logMessage(message);
if (
message.channelId === 754338073101205524n ||
message.guildId === undefined
) {
bot.helpers.sendMessage(message.channelId, {
content: defaultString(await dropRule()),
});
}
break;
case `drop 5`:
logMessage(message);
if (
message.channelId === 754338073101205524n ||
message.guildId === undefined
) {
bot.helpers.sendMessage(message.channelId, {
content: defaultString(await dropRule5()),
});
}
break;
case `refresh`:
logMessage(message);
if (
message.channelId === 754338073101205524n ||
message.guildId === undefined
) {
await refresh();
bot.helpers.sendMessage(message.channelId, {
content: "Refreshed",
});
}
break;
}
const command = message.content.trim().split(" ").slice(1).join(" ");
if (command.startsWith("[") && command.endsWith("]")) {
logMessage(message);
bot.helpers.sendMessage(message.channelId, {
content: defaultString(await requestWorker(command)),
});
} else if (command === "help") {
logMessage(message);
bot.helpers.sendMessage(message.channelId, {
content: defaultString(help()),
});
} else {
drop();
}
}

View File

@@ -0,0 +1,74 @@
import { assert } from "@std/assert/assert";
import {requestJSON, postUrl, ImageResponse} from "./api.ts"
const keys = ["limit" , "id" , "pid" , "tags"] as const
type PostKeys = typeof keys[number]
function isKey(key: string): key is PostKeys {
return keys.includes(key as any);
}
export async function drop() {
const response = await requestJSON<ImageResponse[]>(`${postUrl}&limit=1`)
if (response[0] === undefined) throw Error("Bro, get some sleep")
return response[0].file_url
}
export async function requestWorker(requestString: string){
const response = await requestJSON<ImageResponse[]>(generateRequestURL(requestString))
const stack: string[] = []
for (const img of response) {
stack.push(img.file_url)
}
return stack.join("\n")
}
//TODO: get help in form of a nice beautiful format
export function help() {
return "WIP"
}
export function requestParser(requestString: string) {
const res = requestString.match(/\[([\s*w+:\s*[\d+|\w+,]+)\]/g)
const map = new Map<PostKeys, string>()
if (res !== null) {
res[0]
.split(",")
.forEach(param => {
const match = param.match(/\s*(\w+)\s*:\s*([\w+,]+)/)
if (match !== null) {
if (match[1] === undefined || match[2] === undefined) throw Error("Unreachable")
if (!isKey(match[1])) throw Error(`Key: ${match[1]} is not a Key!`)
map.set(match[1], match[2])
} else {
throw Error(`match returned null in param = ${Deno.inspect(param)}`)
}
})
} else {
throw Error("Request String had some major issues chief")
}
return map
}
export function generateRequestURL(requestString: string) {
const postCpy = new URL(postUrl.toString())
postCpy.search = new URLSearchParams([...postCpy.searchParams, ...requestParser(requestString)]).toString()
return postCpy.toString()
}
Deno.test("Test Request Parser", () => {
assert(requestParser("[limit: 12,tags:bro+likes+bread]"), '{ "limit" => "12", "tags" => "bro+likes+bread" }')
})
Deno.test("Test URL Search Parameters", () => {
console.debug(generateRequestURL("[limit:3]"))
})
Deno.test("Test Drop", async() => {
console.debug(await drop())
})
Deno.test("Test Request Workder", async() => {
console.debug(await requestWorker("[limit: 12,tags:sfw]"))
})

View File

@@ -1,8 +1,28 @@
// import { assert } from "jsr:@std/assert";
// import { dropRule, refresh } from "@root/plugins/rule34/api.ts";
import { assert } from "jsr:@std/assert";
import * as api 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("Post Comment", async () => {
const response = await api.getPostComments(1213);
assert(response !== undefined)
});
Deno.test("Get Tag by ID", async () => {
const response = await api.getTagByID(1);
assert(response !== undefined)
});
Deno.test("Get Post Comments", async () => {
const response = await api.getPostComments(1);
assert(response !== undefined)
});
Deno.test("Get Tag by ID 1", async () => {
const response = await api.getTagByID(1);
assert(response !== undefined)
});
Deno.test("Get Tag List", async () => {
const response = await api.getTagList(6);
assert(response !== undefined)
});