From 49c607db4a3d0dc4a4c9684778389f4a60efcdfe Mon Sep 17 00:00:00 2001 From: Kagura Date: Sun, 24 Nov 2024 21:17:41 +0800 Subject: [PATCH] + Random Pic, still need fix --- src/App.js | 2 +- src/RandomAnimeGirl.tsx | 168 ++++++++++++++++++++++++++++++++++++++++ src/index.js | 2 + 3 files changed, 171 insertions(+), 1 deletion(-) create mode 100644 src/RandomAnimeGirl.tsx diff --git a/src/App.js b/src/App.js index b9b4111..8e7e277 100644 --- a/src/App.js +++ b/src/App.js @@ -2,7 +2,7 @@ import React from 'react'; import { Link } from 'react-router-dom'; const NameList = () => { - const names = ['TicTacToe','TodoList','FoodOrderer']; + const names = ['TicTacToe','TodoList','FoodOrderer','RandomAnimeGirl']; return (
diff --git a/src/RandomAnimeGirl.tsx b/src/RandomAnimeGirl.tsx new file mode 100644 index 0000000..60403fb --- /dev/null +++ b/src/RandomAnimeGirl.tsx @@ -0,0 +1,168 @@ +import React, { useState } from "react"; +import { blob } from "stream/consumers"; +import { Url } from "url"; + +interface ApiResponse { + success: boolean; + status: number; + key?: string; + count?: number; + id?: string; + colors?: { + main: string; + palette: string[]; + }; + image?: { + original: { + url: string; + extension: string; + }; + compressed: { + url: string; + extension: string; + }; + }; + metadata?: { + original: { + width: number; + height: number; + size: number; + extension: string; + }; + compressed: { + width: number; + height: number; + size: number; + extension: string; + }; + }; + category?: string; + tags?: string[]; + rating?: "safe" | "questionable"; + anime?: { + title: string | null; + character: string | null; + }; + source?: { + url: string | null; + direct: string | null; + }; + attribution?: { + artist: { + username: string | null; + profile: string | null; + }; + copyright: string | null; + }; +} + + + +class Api { + constructor() { } + static validEndpoints: string[] = ['catgirl', 'foxgirl', 'wolf-girl', 'animal-ears', 'tail', 'tail-with-ribbon', 'cuteness-is-justice', 'blue-archive', 'girl', 'young-girl', 'maid', 'maid-uniform', 'vtuber', 'w-sitting', 'lying-down', 'hands-forming-a-heart', 'wink', 'valentine', 'headphonesthigh-high-socks', 'knee-high-socks', 'white-tights', 'black-tights', 'heterochromia', 'uniform', 'sailor-uniform', 'hoodie', 'ribbon', 'white-hair', 'blue-hair', 'long-hair', 'blonde', 'blue-eyes', 'purple-eyes'] + static baseUrl: string = "https://api.nekosia.cat/api/v1/images/" + + async getFromEndpoint(endpoint: string): Promise { + if (endpoint! in Api.validEndpoints) { + return { success: false, status: -1 } + } + + try { + const response = await fetch(Api.baseUrl + endpoint) + if (!response.ok) { + throw new Error(`HTTP error! Status: ${response.status}`) + } + + const data: ApiResponse = await response.json() + return data + } catch (error) { + console.error("Error fetching API:", error); + throw error; // Re-throw the error for caller to handle + } + + } +} + +async function getImage(data: ApiResponse): Promise { + if (data.source == undefined || data.source.direct == null) { + return null + } + const url = data.source.direct.replace('i.pximg.net', 'p.lolicon.cyou') + let result: Blob | null = null + + const response = await fetch(url, { method: "GET" }) + + if (response.status != 200) { + if (response.status == 404 && data.image != undefined) { // 尝试使用备用的 + const backup = await fetch(data.image.original.url, { method: "GET" }) + if (backup.status == 200) { + result = await backup.blob() + } + } + } else { + result = await response.blob() + } + + return result // null 就是获取失败了 +} + +function getImageUrl(data: ApiResponse): string | null { + if (data.source == undefined || data.source.direct == null) { + return null + } + const url = data.source.direct.replace('i.pximg.net', 'p.lolicon.cyou') + return url +} + + +function handleGetImage(type: string | null, setter: React.Dispatch>) { + let endpoint = `${type}` + if (type === null) { + const randomIndex = Math.floor(Math.random() * Api.validEndpoints.length); + endpoint = Api.validEndpoints[randomIndex] + } + let api = new Api(); + + (async () => { + try { + const result = await api.getFromEndpoint(endpoint) + const image = null + // const image = await getImage(result) + if (image != null) { + setter(URL.createObjectURL(image)); + } else { + const imageUrl = getImageUrl(result) + if (imageUrl != null) { + setter(imageUrl) + } + } + } catch (error) { + throw error + } + })(); +} + + +const RandomAnimeGirl = () => { + const [imageSrc, setImageSrc] = useState("https://p.lolicon.cyou/img-original/img/2023/09/06/19/20/27/111496024_p0.png") + return ( +
+

Random Image Viewer

+ Random + +
+ ) +} + +export default RandomAnimeGirl \ No newline at end of file diff --git a/src/index.js b/src/index.js index f6111e7..38fcba2 100644 --- a/src/index.js +++ b/src/index.js @@ -7,6 +7,7 @@ import TodoList from "./TodoList"; import NameList from "./App"; import FoodOrderer from "./FoodOrderer"; import { BrowserRouter, Routes, Route } from "react-router-dom"; +import RandomAnimeGirl from "./RandomAnimeGirl"; const root = createRoot(document.getElementById("root")); root.render( @@ -22,6 +23,7 @@ root.render( } /> } /> } /> + } />