+ Random Pic, still need fix
All checks were successful
Update Website / update (push) Successful in 4s

This commit is contained in:
Kagura 2024-11-24 21:17:41 +08:00
parent e374c05671
commit 49c607db4a
3 changed files with 171 additions and 1 deletions

View file

@ -2,7 +2,7 @@ import React from 'react';
import { Link } from 'react-router-dom'; import { Link } from 'react-router-dom';
const NameList = () => { const NameList = () => {
const names = ['TicTacToe','TodoList','FoodOrderer']; const names = ['TicTacToe','TodoList','FoodOrderer','RandomAnimeGirl'];
return ( return (
<div className="min-h-screen bg-gray-100 flex justify-center items-center p-4"> <div className="min-h-screen bg-gray-100 flex justify-center items-center p-4">

168
src/RandomAnimeGirl.tsx Normal file
View file

@ -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<ApiResponse> {
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<Blob | null> {
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<React.SetStateAction<string>>) {
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 (
<div className="flex flex-col items-center justify-center min-h-screen bg-gray-100">
<h1 className="text-3xl font-bold mb-6">Random Image Viewer</h1>
<img
id="image"
src={imageSrc}
alt="Random"
className="w-full max-w-lg rounded shadow-lg border border-gray-300"
/>
<button
onClick={() => handleGetImage(null, setImageSrc)}
className="mt-6 px-6 py-3 text-white bg-blue-500 hover:bg-blue-600 rounded-lg shadow-md transition"
>
Show Random Image
</button>
</div>
)
}
export default RandomAnimeGirl

View file

@ -7,6 +7,7 @@ import TodoList from "./TodoList";
import NameList from "./App"; import NameList from "./App";
import FoodOrderer from "./FoodOrderer"; import FoodOrderer from "./FoodOrderer";
import { BrowserRouter, Routes, Route } from "react-router-dom"; import { BrowserRouter, Routes, Route } from "react-router-dom";
import RandomAnimeGirl from "./RandomAnimeGirl";
const root = createRoot(document.getElementById("root")); const root = createRoot(document.getElementById("root"));
root.render( root.render(
@ -22,6 +23,7 @@ root.render(
<Route path="/TicTacToe" element={<TicTacToe />} /> <Route path="/TicTacToe" element={<TicTacToe />} />
<Route path="/TodoList" element={<TodoList />} /> <Route path="/TodoList" element={<TodoList />} />
<Route path="/FoodOrderer" element={<FoodOrderer />} /> <Route path="/FoodOrderer" element={<FoodOrderer />} />
<Route path="/RandomAnimeGirl" element={<RandomAnimeGirl />} />
</Routes> </Routes>
</BrowserRouter> </BrowserRouter>
</StrictMode> </StrictMode>