Update pages/api/search.ts
Browse files- pages/api/search.ts +15 -6
pages/api/search.ts
CHANGED
|
@@ -8,6 +8,10 @@ type YtResult = {
|
|
| 8 |
thumbnails?: { url: string; width?: number; height?: number }[]
|
| 9 |
}
|
| 10 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 11 |
function limitInt(v: string | number | undefined, def = 8, min = 1, max = 20) {
|
| 12 |
const n = Number(v)
|
| 13 |
if (!Number.isFinite(n)) return def
|
|
@@ -30,7 +34,7 @@ async function searchYouTubeAPI(q: string, limit: number, key: string): Promise<
|
|
| 30 |
url.searchParams.set("q", q)
|
| 31 |
url.searchParams.set("key", key)
|
| 32 |
|
| 33 |
-
const r = await fetch(url.toString()
|
| 34 |
if (!r.ok) throw new Error(`ytapi_http_${r.status}`)
|
| 35 |
const data = await r.json()
|
| 36 |
const items: any[] = Array.isArray(data?.items) ? data.items : []
|
|
@@ -50,7 +54,7 @@ async function searchYouTubeAPI(q: string, limit: number, key: string): Promise<
|
|
| 50 |
}
|
| 51 |
|
| 52 |
async function searchPipedServer(q: string, limit: number): Promise<YtResult[]> {
|
| 53 |
-
// Try a few public instances
|
| 54 |
const instances = [
|
| 55 |
"https://pipedapi.kavin.rocks",
|
| 56 |
"https://piped.video",
|
|
@@ -61,7 +65,7 @@ async function searchPipedServer(q: string, limit: number): Promise<YtResult[]>
|
|
| 61 |
try {
|
| 62 |
const url = new URL("/search", base)
|
| 63 |
url.searchParams.set("q", q)
|
| 64 |
-
const r = await fetch(url.toString()
|
| 65 |
if (!r.ok) continue
|
| 66 |
const data = await r.json()
|
| 67 |
const items: any[] = Array.isArray(data?.items) ? data.items : []
|
|
@@ -87,9 +91,12 @@ async function searchPipedServer(q: string, limit: number): Promise<YtResult[]>
|
|
| 87 |
}
|
| 88 |
|
| 89 |
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
|
| 90 |
-
const
|
|
|
|
| 91 |
if (!q) return res.status(400).json({ error: "Missing q" })
|
| 92 |
-
|
|
|
|
|
|
|
| 93 |
|
| 94 |
// Edge cache (if available)
|
| 95 |
res.setHeader("Cache-Control", "s-maxage=300, stale-while-revalidate")
|
|
@@ -108,7 +115,9 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
|
|
| 108 |
const piped = await searchPipedServer(q, limit)
|
| 109 |
if (piped.length) return res.json({ results: piped, source: "piped" })
|
| 110 |
|
| 111 |
-
return res
|
|
|
|
|
|
|
| 112 |
} catch (err: any) {
|
| 113 |
console.error("search endpoint failed", err)
|
| 114 |
return res.status(500).json({
|
|
|
|
| 8 |
thumbnails?: { url: string; width?: number; height?: number }[]
|
| 9 |
}
|
| 10 |
|
| 11 |
+
function normalizeQueryParam(v: string | string[] | undefined): string | undefined {
|
| 12 |
+
return Array.isArray(v) ? v[0] : v
|
| 13 |
+
}
|
| 14 |
+
|
| 15 |
function limitInt(v: string | number | undefined, def = 8, min = 1, max = 20) {
|
| 16 |
const n = Number(v)
|
| 17 |
if (!Number.isFinite(n)) return def
|
|
|
|
| 34 |
url.searchParams.set("q", q)
|
| 35 |
url.searchParams.set("key", key)
|
| 36 |
|
| 37 |
+
const r = await fetch(url.toString())
|
| 38 |
if (!r.ok) throw new Error(`ytapi_http_${r.status}`)
|
| 39 |
const data = await r.json()
|
| 40 |
const items: any[] = Array.isArray(data?.items) ? data.items : []
|
|
|
|
| 54 |
}
|
| 55 |
|
| 56 |
async function searchPipedServer(q: string, limit: number): Promise<YtResult[]> {
|
| 57 |
+
// Try a few public instances
|
| 58 |
const instances = [
|
| 59 |
"https://pipedapi.kavin.rocks",
|
| 60 |
"https://piped.video",
|
|
|
|
| 65 |
try {
|
| 66 |
const url = new URL("/search", base)
|
| 67 |
url.searchParams.set("q", q)
|
| 68 |
+
const r = await fetch(url.toString())
|
| 69 |
if (!r.ok) continue
|
| 70 |
const data = await r.json()
|
| 71 |
const items: any[] = Array.isArray(data?.items) ? data.items : []
|
|
|
|
| 91 |
}
|
| 92 |
|
| 93 |
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
|
| 94 |
+
const qParam = normalizeQueryParam(req.query.q)
|
| 95 |
+
const q = (qParam || "").toString().trim()
|
| 96 |
if (!q) return res.status(400).json({ error: "Missing q" })
|
| 97 |
+
|
| 98 |
+
const limitParam = normalizeQueryParam(req.query.limit)
|
| 99 |
+
const limit = limitInt(limitParam, 8, 1, 20)
|
| 100 |
|
| 101 |
// Edge cache (if available)
|
| 102 |
res.setHeader("Cache-Control", "s-maxage=300, stale-while-revalidate")
|
|
|
|
| 115 |
const piped = await searchPipedServer(q, limit)
|
| 116 |
if (piped.length) return res.json({ results: piped, source: "piped" })
|
| 117 |
|
| 118 |
+
return res
|
| 119 |
+
.status(502)
|
| 120 |
+
.json({ error: "no_results", detail: "All server-side search methods failed or returned empty." })
|
| 121 |
} catch (err: any) {
|
| 122 |
console.error("search endpoint failed", err)
|
| 123 |
return res.status(500).json({
|