diff --git a/src/plugins/rule34/api.ts b/src/plugins/rule34/api.ts index 60ff63a..0538801 100755 --- a/src/plugins/rule34/api.ts +++ b/src/plugins/rule34/api.ts @@ -1,5 +1,6 @@ //TODO Add optional extensions like limit at Posts with tags etc. import * as xml_parser from "jsr:@melvdouc/xml-parser"; +import { requestRaw, requestJSON } from "@root/structures/apiRequest.ts"; export type ImageResponse = { preview_url: string; @@ -49,22 +50,6 @@ export const postUrl = new URL(`${baseUrl}/index.php?page=dapi&s=post&q=index&js 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(url: string) { - const response = await requestRaw(url); - return 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 { const response = await requestRaw(`${commentsUrl}&post_id=${postID}`); diff --git a/src/plugins/rule34/plugin.ts b/src/plugins/rule34/plugin.ts index ce1b614..2b74eba 100644 --- a/src/plugins/rule34/plugin.ts +++ b/src/plugins/rule34/plugin.ts @@ -1,6 +1,7 @@ import { assert } from "@std/assert/assert"; -import { ImageResponse, postUrl, requestJSON } from "./api.ts"; +import { requestJSON } from "@root/structures/apiRequest.ts"; import { Embed, EmbedAuthor, EmbedImage } from "@root/structures/embeds.ts"; +import { ImageResponse, postUrl } from "./api.ts"; const keys = ["limit", "id", "pid", "tags"] as const; type PostKeys = typeof keys[number]; diff --git a/src/plugins/yandere/api.ts b/src/plugins/yandere/api.ts deleted file mode 100755 index 12f3215..0000000 --- a/src/plugins/yandere/api.ts +++ /dev/null @@ -1,128 +0,0 @@ -import { assert } from "@std/assert/assert"; - -const apiUrl = "https://yande.re/post.json?api_version=2"; - -type APIResponse = { - posts: { - id: number; - tags: string; - created_at: string; - creator_id: number; - approver_id: number; - author: string; - change: number; - source: string; - score: number; - md5: string; - file_size: number; - file_ext: string; - file_url: string; - is_shown_in_index: boolean; - preview_url: string; - preview_width: number; - preview_height: number; - actual_preview_width: number; - actual_preview_height: number; - sample_url: string; - sample_width: number; - sample_height: number; - sample_file_size: number; - jpeg_url: string; - jpeg_width: number; - jpeg_height: number; - rating: string; - is_rating_locked: boolean; - has_children: boolean; - parent_id: number; - status: string; - is_pending: boolean; - width: number; - height: number; - is_held: boolean; - frames_pending_string: string; - frames_pending: []; - frames_string: string; - frames: []; - is_note_locked: boolean; - last_noted_at: string; - last_commented_at: string; - }[]; -}; - -let page = 1; - -let baseRequest = await fetch(apiUrl, { - headers: { "Accept": "application/json" }, -}) - .then(async (response) => { - if (!response.ok) { - throw new Error("Network response was not ok"); - } - return await response.json(); - }); - -const hyperlinkarray: string[] = []; -for (const k of baseRequest.posts) { - hyperlinkarray.push(k.file_url); -} - -export async function setPage(newpage: number) { - page = newpage; - hyperlinkarray.length = 0; - await refresh(); -} - -export function getPage() { - return page; -} - -//duplicate code, also found in rule34/api.ts -export async function refresh() { - await fetch(`${apiUrl}&page=${page}`, { - headers: { "Accept": "application/json" }, - }) - .then(async (response) => { - if (!response.ok) { - throw new Error("Network response was not ok"); - } - baseRequest = await response.json(); - for (const k of baseRequest.posts) { - if (!hyperlinkarray.includes(k.file_url)) { - hyperlinkarray.push(k.file_url); - } - } - }); -} - -export async function fetchNextPage() { - page += 1; - await refresh(); -} - -export async function dropYandere() { - if (hyperlinkarray.length === 0) { - await fetchNextPage(); - return await dropYandere(); - } - return hyperlinkarray.pop()!; -} - -export async function dropYandere5() { - let tmp = ""; - for (let i = 0; i < 5; i++) { - tmp += await dropYandere() + "\n"; - } - return tmp; -} - -//Test Stack resize when fetching new data -Deno.test("Refresh Stack", 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!", - ); -}); diff --git a/src/plugins/yandere/api/api.ts b/src/plugins/yandere/api/api.ts new file mode 100644 index 0000000..69400df --- /dev/null +++ b/src/plugins/yandere/api/api.ts @@ -0,0 +1,72 @@ +import { handlePostRequest } from "@root/plugins/yandere/api/post.ts"; +const baseURL = "https://yande.re"; + +const apikeys = [ + "post", + "tags", + "artist", + "comments", + "wiki", + "notes", + "users", + "forum", + "pools", +] as const; +type APIKeys = typeof apikeys[number]; +function prepareURLObjectForRequest(type: APIKeys) { + const tmp = new URL(baseURL); + tmp.searchParams.append("api_version", "3"); + switch (type) { + case "post": + tmp.pathname = "post.json"; + break; + case "tags": + tmp.pathname = "tag.json"; + break; + case "artist": + tmp.pathname = "artist.json"; + break; + case "comments": + tmp.pathname = "comment"; + break; + case "wiki": + tmp.pathname = "wiki.json"; + break; + case "notes": + tmp.pathname = "note.json"; + break; + case "users": + tmp.pathname = "user.json"; + break; + case "forum": + tmp.pathname = "forum.json"; + break; + case "pools": + tmp.pathname = "pool.json"; + break; + default: + throw Error("unknown "); + } + return tmp; +} + +export function getPosts(search? : string){ + const url = prepareURLObjectForRequest("post") + return handlePostRequest(url, search) +} + +Deno.test("Empty Post Request", async() => { + console.debug(await getPosts()) +}) + +Deno.test("Post Request with tag", async() => { + console.debug(await getPosts("[tags:love_live!_(series)]")) +}) + +Deno.test("Post Request with limit", async() => { + console.debug(await getPosts("[limit: 1)]")) +}) + +Deno.test("Post Request with page", async() => { + console.debug(await getPosts("[page: 30)]")) +}) \ No newline at end of file diff --git a/src/plugins/yandere/api/post.ts b/src/plugins/yandere/api/post.ts new file mode 100644 index 0000000..a671daa --- /dev/null +++ b/src/plugins/yandere/api/post.ts @@ -0,0 +1,118 @@ +import { requestJSON } from "@root/structures/apiRequest.ts"; +import { DiscordEmbed } from "npm:discordeno@18.0.1"; + +type PostResponse = { + id: number; + tags: string; + created_at: string; + creator_id: number; + approver_id: number; + author: string; + change: number; + source: string; + score: number; + md5: string; + file_size: number; + file_ext: string; + file_url: string; + is_shown_in_index: boolean; + preview_url: string; + preview_width: number; + preview_height: number; + actual_preview_width: number; + actual_preview_height: number; + sample_url: string; + sample_width: number; + sample_height: number; + sample_file_size: number; + jpeg_url: string; + jpeg_width: number; + jpeg_height: number; + rating: string; + is_rating_locked: boolean; + has_children: boolean; + parent_id: number; + status: string; + is_pending: boolean; + width: number; + height: number; + is_held: boolean; + frames_pending_string: string; + frames_pending: []; + frames_string: string; + frames: []; + is_note_locked: boolean; + last_noted_at: string; + last_commented_at: string; +}[]; + +const postSearchkeys = ["limit", "page", "tags"]; + +function parsePostListArgs(url: URL, args: string) { + // const urlCopy: URL = copyObject(url); + const argarr = args.replaceAll(/(\[|\ |\])/g, "").split(","); + for (const arg of argarr) { + const [k, v] = arg.split(":"); + if (url === undefined) throw Error("undefined Object: url!") + if (k === undefined || v === undefined) { + throw Error( + `undefined key or value in ${parsePostListArgs.name}, got k:${k}, v:${v}`, + ); + } + if (postSearchkeys.includes(k)) { + console.debug(k, v) + console.debug(JSON.stringify(url)) + url.searchParams.append(k, v); + } else { + throw Error( + `unknown parameter was given in ${parsePostListArgs.name}, got k:${k}, v:${v}`, + ); + } + } + return url; +} + +async function returnDiscordEmbeds( + url: URL, +): Promise { + const response: PostResponse = await requestJSON( + url.toString(), + ); + const embeds: DiscordEmbed[] = []; + for (const post of response) { + embeds.push( + { + url: post.source, + title: post.id.toString(), + author: { + name: post.author, + }, + image: { + url: post.file_url, + width: post.width, + height: post.height, + }, + }, + ); + } + return embeds; +} + +// function copyObject(obj: T) { +// const newObject: T = Object. + + +/** + * Post-Request Handler Function, that returns DiscordEmbeds. + * @param url URL Object + * @param search Search string formatted like the following: [tags: something, page: 1, limit: 666], some parameters can miss. + */ +export async function handlePostRequest(url: URL, search?: string): Promise { + // const urlCopy = copyObject(url); + //parse + if (search) { + return await returnDiscordEmbeds(parsePostListArgs(url, search)); + } else { + return await returnDiscordEmbeds(url); + } +} diff --git a/src/plugins/yandere/messages.ts b/src/plugins/yandere/messages.ts index 95407ca..dbd35d2 100644 --- a/src/plugins/yandere/messages.ts +++ b/src/plugins/yandere/messages.ts @@ -1,69 +1,25 @@ -import { Bot, Message } from "npm:discordeno@18.0.1"; -import { dropYandere, dropYandere5, getPage, refresh, setPage } from "./api.ts"; +import { Bot, Embed, Message } from "npm:discordeno@18.0.1"; import { defaultString } from "@root/defaultString.ts"; import { logMessage } from "@root/logging.ts"; +import { getPosts } from "@root/plugins/yandere/api/api.ts"; +import { debug } from "node:console"; export async function yandereMessageHandler(bot: Bot, message: Message) { const command = message.content.split(" ").slice(1).join(" "); - const args = message.content.split(" ").slice(1); - - switch (command) { - case `drop`: - logMessage(message); - if ( - message.channelId === 754338073101205524n || - message.guildId === undefined - ) { - await refresh(); - bot.helpers.sendMessage(message.channelId, { - content: defaultString(await dropYandere()), - }); - } - break; - case `drop 5`: - logMessage(message); - if ( - message.channelId === 754338073101205524n || - message.guildId === undefined - ) { - await refresh(); - bot.helpers.sendMessage(message.channelId, { - content: defaultString(await dropYandere5()), - }); - } - break; - case `page`: - logMessage(message); - if ( - message.channelId === 754338073101205524n || - message.guildId === undefined - ) { - if (args[0] === undefined) { - bot.helpers.sendMessage(message.channelId, { - content: "Please provide a page number", - }); - } else if (isNaN(parseInt(args[0]))) { - bot.helpers.sendMessage(message.channelId, { - content: "Please provide a valid number", - }); - } else { - await setPage(parseInt(args[0])); - bot.helpers.sendMessage(message.channelId, { - content: "Page set to " + args[0], - }); - } - } - break; - case `getpage`: - logMessage(message); - if ( - message.channelId === 754338073101205524n || - message.guildId === undefined - ) { - bot.helpers.sendMessage(message.channelId, { - content: "Page is " + getPage(), - }); - } - break; + const args = command.match(/(\[\.+\])/g) + if (command === "drop") { + const embed = await getPosts("[limit: 1]") + bot.helpers.sendMessage(message.channelId, { + embeds: [embed as Embed] + }) + } else if (command.startsWith("drop [") && command.endsWith("]")) { + logMessage(message); + if (args === null) throw Error("args is null") + const generatedEmbeds = await getPosts(args[0]); + for (const embed of generatedEmbeds) { + bot.helpers.sendMessage(message.channelId, { + embeds: [embed as Embed], + }); + } } -} +} \ No newline at end of file diff --git a/src/plugins/yandere/plugin.ts b/src/plugins/yandere/plugin.ts new file mode 100644 index 0000000..e69de29 diff --git a/src/plugins/yandere/test.ts b/src/plugins/yandere/test.ts index 9564495..2545218 100644 --- a/src/plugins/yandere/test.ts +++ b/src/plugins/yandere/test.ts @@ -4,7 +4,7 @@ import { getPage, refresh, setPage, -} from "@root/plugins/yandere/api.ts"; +} from "./api/api.ts"; import { assertEquals } from "@std/assert/equals"; //tests /* diff --git a/src/structures/apiRequest.ts b/src/structures/apiRequest.ts new file mode 100644 index 0000000..3b9a51e --- /dev/null +++ b/src/structures/apiRequest.ts @@ -0,0 +1,14 @@ +export async function requestJSON(url: string) { + const response = await requestRaw(url); + return await response.json(); +} + +export 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; +} \ No newline at end of file