1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
|
import { PhotoIcon } from "@heroicons/react/24/outline";
import { useRouter } from "next/router";
import React, { useEffect } from "react";
import { toast } from "sonner";
type SearchByImageProps = {
searchPalette?: boolean;
setIsOpen?: (isOpen: boolean) => void;
setData?: any; // Replace 'any' with the actual data type
setMedia?: (media: any) => void; // Replace 'any' with the actual media type
};
export default function SearchByImage({
searchPalette = false,
setIsOpen,
setData = () => {},
setMedia = () => {},
}: SearchByImageProps) {
const router = useRouter();
async function findImage(formData: FormData) {
const response = new Promise((resolve, reject) => {
fetch("https://api.trace.moe/search?anilistInfo", {
method: "POST",
body: formData,
})
.then((resp) => {
resolve(resp.json());
})
.catch((error) => {
reject(error);
});
});
toast.promise(response, {
loading: "Finding episodes...",
success: `Episodes found!`,
error: "Error",
});
response
.then((data: any) => {
if (data && data?.result?.length > 0) {
const id = data.result[0].anilist.id;
const datas = data.result.filter(
(i: any) => i.anilist.isAdult === false
);
if (setData) setData(datas);
if (searchPalette) router.push(`/en/anime/${id}`);
if (setIsOpen) setIsOpen(false);
if (setMedia) setMedia({});
}
})
.catch((error) => {
console.error("Error:", error);
});
}
const handleImageSelect = async (e: any) => {
const selectedImage = e.target.files[0];
if (selectedImage) {
const formData = new FormData();
formData.append("image", selectedImage);
try {
await findImage(formData);
} catch (error) {
console.error("An error occurred:", error);
}
}
};
useEffect(() => {
// Add a global event listener for the paste event
const handlePaste = async (e: any) => {
// e.preventDefault();
const items = e.clipboardData.items;
for (let i = 0; i < items.length; i++) {
if (items[i].type.indexOf("image") !== -1) {
const blob = items[i].getAsFile();
// Create a FormData object and append the pasted image
const formData = new FormData();
formData.append("image", blob);
try {
// Send the pasted image to your API for processing
await findImage(formData);
} catch (error) {
console.error("An error occurred:", error);
}
break; // Stop after finding the first image
}
}
};
// Add the event listener to the document
document.addEventListener("paste", handlePaste);
// Clean up the event listener when the component unmounts
return () => {
document.removeEventListener("paste", handlePaste);
};
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
return (
<div>
<label
className={`${
searchPalette ? "w-9 h-9" : "py-2 px-2"
} bg-secondary rounded flex justify-center items-center cursor-pointer hover:bg-opacity-75 transition-all duration-100 group`}
>
<PhotoIcon className="w-6 h-6" />
<input
type="file"
name="image"
onChange={handleImageSelect}
className="hidden"
/>
</label>
</div>
);
}
export interface TraceMoeDataTypes {
frameCount: number;
error: string;
result: TraceMoeResultTypes[];
}
export interface TraceMoeResultTypes {
anilist: Anilist;
filename: string;
episode: any;
from: number;
to: number;
similarity: number;
video: string;
image: string;
hovered?: boolean;
}
interface Anilist {
id: number;
idMal: number;
title: Title;
synonyms: string[];
isAdult: boolean;
}
interface Title {
native: string;
romaji: string;
english: any;
}
|