Merge branch 'main' of https://gitea.fzzin.31718216.xyz/fzzinchemical/HotDog
This commit is contained in:
@@ -1,5 +1,6 @@
|
|||||||
//TODO Add optional extensions like limit at Posts with tags etc.
|
//TODO Add optional extensions like limit at Posts with tags etc.
|
||||||
import * as xml_parser from "jsr:@melvdouc/xml-parser";
|
import * as xml_parser from "jsr:@melvdouc/xml-parser";
|
||||||
|
import { requestRaw, requestJSON } from "@root/structures/apiRequest.ts";
|
||||||
|
|
||||||
export type ImageResponse = {
|
export type ImageResponse = {
|
||||||
preview_url: string;
|
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 tagUrl = `${baseUrl}/index.php?page=dapi&s=tag&q=index`;
|
||||||
const commentsUrl = `${baseUrl}/index.php?page=dapi&s=comment&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
|
// Comments
|
||||||
export async function getPostComments(postID: number): Promise<CommentResponse[]> {
|
export async function getPostComments(postID: number): Promise<CommentResponse[]> {
|
||||||
const response = await requestRaw(`${commentsUrl}&post_id=${postID}`);
|
const response = await requestRaw(`${commentsUrl}&post_id=${postID}`);
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
import { ImageResponse, postUrl, requestJSON } from "./api.ts";
|
import { assert } from "@std/assert/assert";
|
||||||
|
import { requestJSON } from "@root/structures/apiRequest.ts";
|
||||||
import { Embed, EmbedAuthor, EmbedImage } from "@root/structures/embeds.ts";
|
import { Embed, EmbedAuthor, EmbedImage } from "@root/structures/embeds.ts";
|
||||||
|
import { ImageResponse, postUrl } from "./api.ts";
|
||||||
|
|
||||||
const keys = ["limit", "id", "pid", "tags"] as const;
|
const keys = ["limit", "id", "pid", "tags"] as const;
|
||||||
type PostKeys = typeof keys[number];
|
type PostKeys = typeof keys[number];
|
||||||
|
|||||||
@@ -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 <APIResponse> 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 = <APIResponse> 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!",
|
|
||||||
);
|
|
||||||
});
|
|
||||||
72
src/plugins/yandere/api/api.ts
Normal file
72
src/plugins/yandere/api/api.ts
Normal file
@@ -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)]"))
|
||||||
|
})
|
||||||
118
src/plugins/yandere/api/post.ts
Normal file
118
src/plugins/yandere/api/post.ts
Normal file
@@ -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>(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<DiscordEmbed[]> {
|
||||||
|
const response: PostResponse = await requestJSON<PostResponse>(
|
||||||
|
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<T>(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<DiscordEmbed[]> {
|
||||||
|
// const urlCopy = copyObject<URL>(url);
|
||||||
|
//parse
|
||||||
|
if (search) {
|
||||||
|
return await returnDiscordEmbeds(parsePostListArgs(url, search));
|
||||||
|
} else {
|
||||||
|
return await returnDiscordEmbeds(url);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,69 +1,25 @@
|
|||||||
import { Bot, Message } from "npm:discordeno@18.0.1";
|
import { Bot, Embed, Message } from "npm:discordeno@18.0.1";
|
||||||
import { dropYandere, dropYandere5, getPage, refresh, setPage } from "./api.ts";
|
|
||||||
import { defaultString } from "@root/defaultString.ts";
|
import { defaultString } from "@root/defaultString.ts";
|
||||||
import { logMessage } from "@root/logging.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) {
|
export async function yandereMessageHandler(bot: Bot, message: Message) {
|
||||||
const command = message.content.split(" ").slice(1).join(" ");
|
const command = message.content.split(" ").slice(1).join(" ");
|
||||||
const args = message.content.split(" ").slice(1);
|
const args = command.match(/(\[\.+\])/g)
|
||||||
|
if (command === "drop") {
|
||||||
switch (command) {
|
const embed = await getPosts("[limit: 1]")
|
||||||
case `drop`:
|
bot.helpers.sendMessage(message.channelId, {
|
||||||
logMessage(message);
|
embeds: [embed as Embed]
|
||||||
if (
|
})
|
||||||
message.channelId === 754338073101205524n ||
|
} else if (command.startsWith("drop [") && command.endsWith("]")) {
|
||||||
message.guildId === undefined
|
logMessage(message);
|
||||||
) {
|
if (args === null) throw Error("args is null")
|
||||||
await refresh();
|
const generatedEmbeds = await getPosts(args[0]);
|
||||||
bot.helpers.sendMessage(message.channelId, {
|
for (const embed of generatedEmbeds) {
|
||||||
content: defaultString(await dropYandere()),
|
bot.helpers.sendMessage(message.channelId, {
|
||||||
});
|
embeds: [embed as Embed],
|
||||||
}
|
});
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
0
src/plugins/yandere/plugin.ts
Normal file
0
src/plugins/yandere/plugin.ts
Normal file
@@ -4,7 +4,7 @@ import {
|
|||||||
getPage,
|
getPage,
|
||||||
refresh,
|
refresh,
|
||||||
setPage,
|
setPage,
|
||||||
} from "@root/plugins/yandere/api.ts";
|
} from "./api/api.ts";
|
||||||
import { assertEquals } from "@std/assert/equals";
|
import { assertEquals } from "@std/assert/equals";
|
||||||
//tests
|
//tests
|
||||||
/*
|
/*
|
||||||
|
|||||||
14
src/structures/apiRequest.ts
Normal file
14
src/structures/apiRequest.ts
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
export async function requestJSON<T>(url: string) {
|
||||||
|
const response = await requestRaw(url);
|
||||||
|
return <T> 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;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user