+ Random Pic, still need fix
All checks were successful
Update Website / update (push) Successful in 4s
All checks were successful
Update Website / update (push) Successful in 4s
This commit is contained in:
parent
e374c05671
commit
49c607db4a
3 changed files with 171 additions and 1 deletions
|
@ -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
168
src/RandomAnimeGirl.tsx
Normal 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
|
|
@ -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>
|
||||||
|
|
Loading…
Reference in a new issue