shivam413 commited on
Commit
a746b66
·
verified ·
1 Parent(s): afc50e4

Update components/search/YoutubeSearch.tsx

Browse files
Files changed (1) hide show
  1. components/search/YoutubeSearch.tsx +75 -10
components/search/YoutubeSearch.tsx CHANGED
@@ -15,6 +15,65 @@ interface Props {
15
  socket: Socket<ServerToClientEvents, ClientToServerEvents> | null
16
  }
17
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
18
  const YoutubeSearch: FC<Props> = ({ socket }) => {
19
  const [q, setQ] = useState("")
20
  const [loading, setLoading] = useState(false)
@@ -26,16 +85,22 @@ const YoutubeSearch: FC<Props> = ({ socket }) => {
26
  if (!query) return
27
  setLoading(true)
28
  setError(null)
29
- try {
30
- const r = await fetch(`/api/search?q=${encodeURIComponent(query)}&limit=8`)
31
- const data = await r.json()
32
- if (!r.ok) throw new Error(data?.error || "Failed to search")
33
- setResults(data.results || [])
34
- } catch (e: any) {
35
- setError(e.message || "Failed to search")
36
- } finally {
37
- setLoading(false)
 
 
 
 
 
38
  }
 
39
  }
40
 
41
  return (
@@ -81,4 +146,4 @@ const YoutubeSearch: FC<Props> = ({ socket }) => {
81
  )
82
  }
83
 
84
- export default YoutubeSearch
 
15
  socket: Socket<ServerToClientEvents, ClientToServerEvents> | null
16
  }
17
 
18
+ async function fetchWithTimeout(input: RequestInfo | URL, init: RequestInit = {}, ms = 5000) {
19
+ const controller = new AbortController()
20
+ const t = setTimeout(() => controller.abort(), ms)
21
+ try {
22
+ const res = await fetch(input, { ...init, signal: controller.signal })
23
+ return res
24
+ } finally {
25
+ clearTimeout(t)
26
+ }
27
+ }
28
+
29
+ async function searchViaServer(q: string, limit = 8): Promise<Result[] | null> {
30
+ try {
31
+ const r = await fetchWithTimeout(`/api/search?q=${encodeURIComponent(q)}&limit=${limit}`, {}, 5000)
32
+ if (!r.ok) return null
33
+ const data = await r.json()
34
+ return Array.isArray(data?.results) ? data.results : null
35
+ } catch {
36
+ return null
37
+ }
38
+ }
39
+
40
+ async function searchViaPipedClient(q: string, limit = 8): Promise<Result[] | null> {
41
+ // Browser → public Piped instances to bypass server DNS issues
42
+ const instances = [
43
+ "https://pipedapi.kavin.rocks",
44
+ "https://piped.video",
45
+ "https://piped.mha.fi",
46
+ "https://piped-api.garudalinux.org",
47
+ ]
48
+ for (const base of instances) {
49
+ try {
50
+ const url = new URL("/search", base)
51
+ url.searchParams.set("q", q)
52
+ const r = await fetchWithTimeout(url.toString(), { cache: "no-store" }, 6000)
53
+ if (!r.ok) continue
54
+ const data = await r.json()
55
+ const items: any[] = Array.isArray(data?.items) ? data.items : []
56
+ const results = items
57
+ .filter((it) => it?.type?.toLowerCase() === "video" && it?.id && it?.title)
58
+ .slice(0, limit)
59
+ .map((it) => {
60
+ const id = it.id
61
+ return {
62
+ id,
63
+ title: it.title,
64
+ url: `https://www.youtube.com/watch?v=${id}`,
65
+ duration: typeof it.duration === "number" ? it.duration : undefined,
66
+ thumbnails: it.thumbnail ? [{ url: it.thumbnail }] : undefined,
67
+ } as Result
68
+ })
69
+ if (results.length) return results
70
+ } catch {
71
+ // try next instance
72
+ }
73
+ }
74
+ return null
75
+ }
76
+
77
  const YoutubeSearch: FC<Props> = ({ socket }) => {
78
  const [q, setQ] = useState("")
79
  const [loading, setLoading] = useState(false)
 
85
  if (!query) return
86
  setLoading(true)
87
  setError(null)
88
+ setResults([])
89
+
90
+ // 1) Try server endpoint (YT API key or Piped server-side)
91
+ let found: Result[] | null = await searchViaServer(query, 8)
92
+
93
+ // 2) Fallback: Browser → Piped directly (bypasses server DNS)
94
+ if (!found || found.length === 0) {
95
+ found = await searchViaPipedClient(query, 8)
96
+ }
97
+
98
+ if (!found || found.length === 0) {
99
+ setError("No results or all search methods failed.")
100
+ } else {
101
+ setResults(found)
102
  }
103
+ setLoading(false)
104
  }
105
 
106
  return (
 
146
  )
147
  }
148
 
149
+ export default YoutubeSearch