ztoolx commited on
Commit
26f3ad0
·
verified ·
1 Parent(s): dd6454c
Files changed (1) hide show
  1. server.js +110 -0
server.js ADDED
@@ -0,0 +1,110 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ const express = require('express');
2
+ const cors = require('cors');
3
+ const { YoutubeTranscript } = require('youtube-transcript');
4
+
5
+ const app = express();
6
+ const PORT = 7860;
7
+
8
+ // Enable CORS for your Vercel frontend
9
+ app.use(cors());
10
+ app.use(express.json());
11
+
12
+ // ========================================================
13
+ // KEEP-ALIVE ENDPOINT
14
+ // ========================================================
15
+ app.get('/api/health', (req, res) => {
16
+ res.json({ status: 'ok', message: 'Transcript API is running!' });
17
+ });
18
+
19
+ // ========================================================
20
+ // TRANSCRIPT API
21
+ // ========================================================
22
+ app.post('/api/transcript', async (req, res) => {
23
+ try {
24
+ const { url } = req.body;
25
+
26
+ const videoIdMatch = url.match(
27
+ /(?:youtube\.com\/(?:[^\/]+\/.+\/|(?:v|e(?:mbed)?)\/|.*[?&]v=)|youtu\.be\/)([^"&?\/\s]{11})/
28
+ );
29
+ if (!videoIdMatch) {
30
+ return res.status(400).json({ error: "Invalid YouTube URL" });
31
+ }
32
+ const videoId = videoIdMatch[1];
33
+
34
+ let transcriptData;
35
+ let retries = 3;
36
+ let lastError;
37
+
38
+ while (retries > 0) {
39
+ try {
40
+ transcriptData = await YoutubeTranscript.fetchTranscript(videoId);
41
+ break; // success
42
+ } catch (err) {
43
+ lastError = err;
44
+ retries--;
45
+ if (retries > 0) {
46
+ await new Promise((resolve) => setTimeout(resolve, 2000));
47
+ }
48
+ }
49
+ }
50
+
51
+ if (!transcriptData) {
52
+ throw lastError;
53
+ }
54
+
55
+ const fullText = transcriptData
56
+ .map((t) => t.text)
57
+ .join(" ")
58
+ .replace(/'|"/g, "'");
59
+
60
+ res.json({ text: fullText });
61
+ } catch (error) {
62
+ console.error("Transcript Error:", error.message);
63
+ res.status(500).json({
64
+ error: "Could not fetch transcript. The video might not have captions enabled, or the request timed out."
65
+ });
66
+ }
67
+ });
68
+
69
+ // ========================================================
70
+ // TRANSLATE API
71
+ // ========================================================
72
+ app.post('/api/translate', async (req, res) => {
73
+ try {
74
+ const { text, targetLang } = req.body;
75
+
76
+ if (!text || !targetLang) {
77
+ return res.status(400).json({ error: "Missing text or target language" });
78
+ }
79
+
80
+ const url = `https://translate.googleapis.com/translate_a/single?client=gtx&sl=auto&tl=${targetLang}&dt=t`;
81
+
82
+ const fetchRes = await fetch(url, {
83
+ method: "POST",
84
+ headers: {
85
+ "Content-Type": "application/x-www-form-urlencoded",
86
+ "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
87
+ },
88
+ body: `q=${encodeURIComponent(text)}`,
89
+ });
90
+
91
+ if (!fetchRes.ok) {
92
+ const errText = await fetchRes.text();
93
+ console.error("Google API Error:", errText);
94
+ throw new Error(`Translation service responded with status ${fetchRes.status}`);
95
+ }
96
+
97
+ const data = await fetchRes.json();
98
+ const translated = data[0].map((item) => item[0]).join("");
99
+
100
+ res.json({ translatedText: translated });
101
+ } catch (error) {
102
+ console.error("Translation API Error:", error.message);
103
+ res.status(500).json({ error: "Failed to translate text. " + error.message });
104
+ }
105
+ });
106
+
107
+ // Start server
108
+ app.listen(PORT, '0.0.0.0', () => {
109
+ console.log(`Server running on http://0.0.0.0:${PORT}`);
110
+ });