web: add giphy provider for gif search
All checks were successful
CI / test (push) Successful in 21s
All checks were successful
CI / test (push) Successful in 21s
This commit is contained in:
@@ -3,3 +3,4 @@ VITE_WS_URL=ws://localhost:8000/api/v1/realtime/ws
|
||||
VITE_GIF_PROVIDER=
|
||||
VITE_TENOR_API_KEY=
|
||||
VITE_TENOR_CLIENT_KEY=benya_messenger_web
|
||||
VITE_GIPHY_API_KEY=
|
||||
|
||||
@@ -34,7 +34,10 @@ const GIF_FAVORITES_KEY = "bm_gif_favorites_v1";
|
||||
const GIF_PROVIDER = (import.meta.env.VITE_GIF_PROVIDER ?? "").toLowerCase();
|
||||
const TENOR_API_KEY = (import.meta.env.VITE_TENOR_API_KEY ?? "").trim();
|
||||
const TENOR_CLIENT_KEY = (import.meta.env.VITE_TENOR_CLIENT_KEY ?? "benya_messenger_web").trim();
|
||||
const GIF_SEARCH_ENABLED = GIF_PROVIDER === "tenor" && TENOR_API_KEY.length > 0;
|
||||
const GIPHY_API_KEY = (import.meta.env.VITE_GIPHY_API_KEY ?? "").trim();
|
||||
const GIF_SEARCH_ENABLED =
|
||||
(GIF_PROVIDER === "tenor" && TENOR_API_KEY.length > 0) ||
|
||||
(GIF_PROVIDER === "giphy" && GIPHY_API_KEY.length > 0);
|
||||
|
||||
function loadFavorites(key: string): Set<string> {
|
||||
try {
|
||||
@@ -124,6 +127,67 @@ export function MessageComposer() {
|
||||
(activeChat.type !== "channel" || activeChat.my_role === "owner" || activeChat.my_role === "admin" || activeChat.is_saved)
|
||||
);
|
||||
|
||||
async function searchGifs(term: string): Promise<Array<{ name: string; url: string }>> {
|
||||
if (GIF_PROVIDER === "tenor") {
|
||||
const params = new URLSearchParams({
|
||||
q: term,
|
||||
key: TENOR_API_KEY,
|
||||
client_key: TENOR_CLIENT_KEY,
|
||||
limit: "24",
|
||||
media_filter: "gif",
|
||||
contentfilter: "medium",
|
||||
});
|
||||
const response = await fetch(`https://tenor.googleapis.com/v2/search?${params.toString()}`);
|
||||
if (!response.ok) {
|
||||
throw new Error("tenor search failed");
|
||||
}
|
||||
const data = (await response.json()) as {
|
||||
results?: Array<{ content_description?: string; media_formats?: { gif?: { url?: string } } }>;
|
||||
};
|
||||
return (
|
||||
data.results
|
||||
?.map((item) => ({
|
||||
name: item.content_description || "GIF",
|
||||
url: item.media_formats?.gif?.url || "",
|
||||
}))
|
||||
.filter((item) => item.url.length > 0) ?? []
|
||||
);
|
||||
}
|
||||
|
||||
if (GIF_PROVIDER === "giphy") {
|
||||
const params = new URLSearchParams({
|
||||
api_key: GIPHY_API_KEY,
|
||||
q: term,
|
||||
limit: "24",
|
||||
rating: "pg-13",
|
||||
lang: "en",
|
||||
});
|
||||
const response = await fetch(`https://api.giphy.com/v1/gifs/search?${params.toString()}`);
|
||||
if (!response.ok) {
|
||||
throw new Error("giphy search failed");
|
||||
}
|
||||
const data = (await response.json()) as {
|
||||
data?: Array<{
|
||||
title?: string;
|
||||
images?: {
|
||||
fixed_height?: { url?: string };
|
||||
original?: { url?: string };
|
||||
};
|
||||
}>;
|
||||
};
|
||||
return (
|
||||
data.data
|
||||
?.map((item) => ({
|
||||
name: item.title || "GIF",
|
||||
url: item.images?.fixed_height?.url || item.images?.original?.url || "",
|
||||
}))
|
||||
.filter((item) => item.url.length > 0) ?? []
|
||||
);
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
recordingStateRef.current = recordingState;
|
||||
}, [recordingState]);
|
||||
@@ -339,32 +403,8 @@ export function MessageComposer() {
|
||||
setGifSearchError(null);
|
||||
void (async () => {
|
||||
try {
|
||||
const params = new URLSearchParams({
|
||||
q: term,
|
||||
key: TENOR_API_KEY,
|
||||
client_key: TENOR_CLIENT_KEY,
|
||||
limit: "24",
|
||||
media_filter: "gif",
|
||||
contentfilter: "medium",
|
||||
});
|
||||
const response = await fetch(`https://tenor.googleapis.com/v2/search?${params.toString()}`);
|
||||
if (!response.ok) {
|
||||
if (response.status === 400) {
|
||||
throw new Error("GIF provider rejected the request. Configure your own API key.");
|
||||
}
|
||||
throw new Error("gif search failed");
|
||||
}
|
||||
const data = (await response.json()) as {
|
||||
results?: Array<{ content_description?: string; media_formats?: { gif?: { url?: string } } }>;
|
||||
};
|
||||
const rows = await searchGifs(term);
|
||||
if (cancelled) return;
|
||||
const rows =
|
||||
data.results
|
||||
?.map((item) => ({
|
||||
name: item.content_description || "GIF",
|
||||
url: item.media_formats?.gif?.url || "",
|
||||
}))
|
||||
.filter((item) => item.url.length > 0) ?? [];
|
||||
setGifResults(rows);
|
||||
} catch {
|
||||
if (!cancelled) {
|
||||
|
||||
Reference in New Issue
Block a user