Ricky01anjay commited on
Commit
252ee28
·
verified ·
1 Parent(s): 61c6453

Update server.js

Browse files
Files changed (1) hide show
  1. server.js +42 -45
server.js CHANGED
@@ -1,13 +1,12 @@
1
-
2
  const express = require('express');
3
  const io = require('socket.io-client');
4
  const axios = require('axios');
5
  const NodeCache = require('node-cache');
6
- const { v4: uuidv4 } = require('uuid');
7
 
8
  const app = express();
9
  const port = 7860;
10
- const jobCache = new NodeCache({ stdTTL: 3600 }); // Job disimpan selama 1 jam
11
 
12
  app.use(express.json());
13
  app.use(express.urlencoded({ extended: true }));
@@ -28,7 +27,7 @@ const HEADERS = {
28
  // --- LOGIC STABILIZER ---
29
  async function runStabilize(jobId, videoUrl) {
30
  try {
31
- jobCache.set(jobId, { status: 'Initializing', progress: 0 });
32
 
33
  const page = await axios.get(CONFIG.targetUrl, { headers: HEADERS });
34
  const html = page.data;
@@ -38,7 +37,7 @@ async function runStabilize(jobId, videoUrl) {
38
  setCookie.forEach(c => {
39
  const [kv] = c.split(';');
40
  const [k, v] = kv.split('=');
41
- cookieMap[k.trim()] = v.trim();
42
  });
43
 
44
  const uid = cookieMap['uid'];
@@ -46,25 +45,25 @@ async function runStabilize(jobId, videoUrl) {
46
  const g = html.match(/"g"\s*:\s*"([^"]+)"/)?.[1];
47
  const f = html.match(/"f"\s*:\s*"([^"]+)"/)?.[1] || "44ec01b4c5d979004ecf7d57eed8ba65";
48
 
49
- if (!uid || !i || !g) throw new Error("Gagal ekstraksi token website.");
50
 
51
  const cookieStr = Object.entries(cookieMap).map(([k, v]) => `${k}=${v}`).join('; ');
52
 
53
- jobCache.set(jobId, { status: 'Handshaking SSO', progress: 10 });
54
  const attachResponse = await axios.get('https://online-video-cutter.com/sso/attach/', {
55
  params: { callback: 'jQuery' + Math.floor(Math.random() * 10e15), _: Date.now() },
56
  headers: { ...HEADERS, 'cookie': cookieStr, 'x-requested-with': 'XMLHttpRequest' }
57
  });
58
 
59
  const verify = attachResponse.data.match(/"verify"\s*:\s*"([^"]+)"/)?.[1];
60
- if (!verify) throw new Error("Gagal SSO Handshake.");
61
 
62
  await axios.post('https://online-video-cutter.com/sso/verify/',
63
  new URLSearchParams({ verify }).toString(),
64
  { headers: { ...HEADERS, 'content-type': 'application/x-www-form-urlencoded; charset=UTF-8', 'cookie': cookieStr + `; sso_verify_onlinevideocuttercom=${verify}` } }
65
  );
66
 
67
- jobCache.set(jobId, { status: 'Connecting to Worker', progress: 20 });
68
  const socket = io(CONFIG.workerUrl, {
69
  path: '/socket.io/',
70
  transports: ['websocket'],
@@ -83,7 +82,7 @@ async function runStabilize(jobId, videoUrl) {
83
 
84
  socket.on('open_remote', (data) => {
85
  if (data.message_type === 'final_result' && data.tmp_filename) {
86
- jobCache.set(jobId, { status: 'Processing Video', progress: 40 });
87
  socket.emit('encode', {
88
  site_id: "vcutter", uid, operation_id: `${Date.now()}_enc`,
89
  action_type: "encode", tmp_filename: data.tmp_filename, v2: true,
@@ -107,7 +106,7 @@ async function runStabilize(jobId, videoUrl) {
107
  });
108
 
109
  socket.on('connect_error', (err) => {
110
- jobCache.set(jobId, { status: 'Error', error: 'Socket Connection Error' });
111
  });
112
 
113
  } catch (e) {
@@ -126,48 +125,44 @@ app.get('/', (req, res) => {
126
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
127
  <title>Video Stabilizer</title>
128
  <script src="https://cdn.tailwindcss.com"></script>
129
- <style>
130
- .loader { border-top-color: #3498db; animation: spin 1s linear infinite; }
131
- @keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } }
132
- </style>
133
  </head>
134
- <body class="bg-gray-900 text-white min-h-screen flex flex-col items-center p-6">
135
- <div class="w-full max-w-md bg-gray-800 p-6 rounded-2xl shadow-xl">
136
- <h1 class="text-2xl font-bold mb-2 text-center text-blue-400">Video Stabilizer</h1>
137
- <p class="text-xs text-gray-400 mb-6 text-center">Powered by Online-Video-Cutter API</p>
138
 
139
  <div class="space-y-4">
140
- <input type="text" id="videoUrl" placeholder="Paste Video URL (.mp4)"
141
- class="w-full p-3 rounded-lg bg-gray-700 border border-gray-600 focus:outline-none focus:border-blue-500">
142
  <button onclick="startJob()" id="btnStart"
143
- class="w-full bg-blue-600 hover:bg-blue-700 p-3 rounded-lg font-bold transition">
144
- Stabilkan Video
145
  </button>
146
  </div>
147
 
148
- <div id="statusContainer" class="hidden mt-8 border-t border-gray-700 pt-6">
149
- <div class="flex items-center justify-between mb-2">
150
- <span id="statusText" class="text-sm font-medium italic text-gray-300">Menyiapkan...</span>
151
- <span id="progressPercent" class="text-sm font-bold text-blue-400">0%</span>
152
  </div>
153
- <div class="w-full bg-gray-700 rounded-full h-2.5">
154
- <div id="progressBar" class="bg-blue-500 h-2.5 rounded-full transition-all duration-500" style="width: 0%"></div>
155
  </div>
156
- <div id="resultArea" class="mt-6 hidden text-center">
 
157
  <a id="downloadBtn" href="#" target="_blank"
158
- class="inline-block bg-green-600 hover:bg-green-700 text-white px-6 py-2 rounded-full font-bold">
159
- Download Video
160
  </a>
161
  </div>
162
  </div>
163
  </div>
164
 
165
  <script>
166
- let pollingInterval;
167
-
168
  async function startJob() {
169
  const url = document.getElementById('videoUrl').value;
170
- if(!url) return alert('Input URL dulu!');
171
 
172
  document.getElementById('btnStart').disabled = true;
173
  document.getElementById('statusContainer').classList.remove('hidden');
@@ -182,28 +177,30 @@ app.get('/', (req, res) => {
182
  const data = await res.json();
183
  if(data.jobId) pollStatus(data.jobId);
184
  } catch (err) {
185
- alert('Gagal memulai job');
186
  document.getElementById('btnStart').disabled = false;
187
  }
188
  }
189
 
190
  function pollStatus(jobId) {
191
- pollingInterval = setInterval(async () => {
192
  const res = await fetch('/api/status/' + jobId);
193
  const data = await res.json();
194
 
195
  document.getElementById('statusText').innerText = data.status;
196
- document.getElementById('progressPercent').innerText = (data.progress || 0) + '%';
197
- document.getElementById('progressBar').style.width = (data.progress || 0) + '%';
 
198
 
199
  if(data.status === 'Completed') {
200
- clearInterval(pollingInterval);
201
  document.getElementById('btnStart').disabled = false;
202
  document.getElementById('resultArea').classList.remove('hidden');
203
  document.getElementById('downloadBtn').href = data.result;
 
204
  } else if(data.status === 'Error') {
205
- clearInterval(pollingInterval);
206
- alert('Error: ' + data.error);
207
  document.getElementById('btnStart').disabled = false;
208
  }
209
  }, 2000);
@@ -216,7 +213,7 @@ app.get('/', (req, res) => {
216
 
217
  app.post('/api/stabilize', (req, res) => {
218
  const { url } = req.body;
219
- const jobId = uuidv4();
220
  runStabilize(jobId, url);
221
  res.json({ jobId });
222
  });
@@ -227,6 +224,6 @@ app.get('/api/status/:jobId', (req, res) => {
227
  res.json(job);
228
  });
229
 
230
- app.listen(port, () => {
231
- console.log(`Server running at http://localhost:${port}`);
232
  });
 
 
1
  const express = require('express');
2
  const io = require('socket.io-client');
3
  const axios = require('axios');
4
  const NodeCache = require('node-cache');
5
+ const { randomUUID } = require('crypto'); // Gunakan modul bawaan Node.js
6
 
7
  const app = express();
8
  const port = 7860;
9
+ const jobCache = new NodeCache({ stdTTL: 3600 });
10
 
11
  app.use(express.json());
12
  app.use(express.urlencoded({ extended: true }));
 
27
  // --- LOGIC STABILIZER ---
28
  async function runStabilize(jobId, videoUrl) {
29
  try {
30
+ jobCache.set(jobId, { status: 'Initializing', progress: 5 });
31
 
32
  const page = await axios.get(CONFIG.targetUrl, { headers: HEADERS });
33
  const html = page.data;
 
37
  setCookie.forEach(c => {
38
  const [kv] = c.split(';');
39
  const [k, v] = kv.split('=');
40
+ if (k && v) cookieMap[k.trim()] = v.trim();
41
  });
42
 
43
  const uid = cookieMap['uid'];
 
45
  const g = html.match(/"g"\s*:\s*"([^"]+)"/)?.[1];
46
  const f = html.match(/"f"\s*:\s*"([^"]+)"/)?.[1] || "44ec01b4c5d979004ecf7d57eed8ba65";
47
 
48
+ if (!uid || !i || !g) throw new Error("Gagal mengambil token website.");
49
 
50
  const cookieStr = Object.entries(cookieMap).map(([k, v]) => `${k}=${v}`).join('; ');
51
 
52
+ jobCache.set(jobId, { status: 'Handshaking', progress: 15 });
53
  const attachResponse = await axios.get('https://online-video-cutter.com/sso/attach/', {
54
  params: { callback: 'jQuery' + Math.floor(Math.random() * 10e15), _: Date.now() },
55
  headers: { ...HEADERS, 'cookie': cookieStr, 'x-requested-with': 'XMLHttpRequest' }
56
  });
57
 
58
  const verify = attachResponse.data.match(/"verify"\s*:\s*"([^"]+)"/)?.[1];
59
+ if (!verify) throw new Error("SSO Verify Token tidak ditemukan.");
60
 
61
  await axios.post('https://online-video-cutter.com/sso/verify/',
62
  new URLSearchParams({ verify }).toString(),
63
  { headers: { ...HEADERS, 'content-type': 'application/x-www-form-urlencoded; charset=UTF-8', 'cookie': cookieStr + `; sso_verify_onlinevideocuttercom=${verify}` } }
64
  );
65
 
66
+ jobCache.set(jobId, { status: 'Connecting', progress: 25 });
67
  const socket = io(CONFIG.workerUrl, {
68
  path: '/socket.io/',
69
  transports: ['websocket'],
 
82
 
83
  socket.on('open_remote', (data) => {
84
  if (data.message_type === 'final_result' && data.tmp_filename) {
85
+ jobCache.set(jobId, { status: 'Stabilizing Video...', progress: 50 });
86
  socket.emit('encode', {
87
  site_id: "vcutter", uid, operation_id: `${Date.now()}_enc`,
88
  action_type: "encode", tmp_filename: data.tmp_filename, v2: true,
 
106
  });
107
 
108
  socket.on('connect_error', (err) => {
109
+ jobCache.set(jobId, { status: 'Error', error: 'Connection to worker failed' });
110
  });
111
 
112
  } catch (e) {
 
125
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
126
  <title>Video Stabilizer</title>
127
  <script src="https://cdn.tailwindcss.com"></script>
 
 
 
 
128
  </head>
129
+ <body class="bg-slate-900 text-slate-100 min-h-screen flex flex-col items-center p-4">
130
+ <div class="w-full max-w-md bg-slate-800 p-6 rounded-3xl shadow-2xl mt-10">
131
+ <h1 class="text-3xl font-extrabold mb-1 text-center bg-gradient-to-r from-blue-400 to-emerald-400 bg-clip-text text-transparent">Stabilizer</h1>
132
+ <p class="text-xs text-slate-400 mb-8 text-center uppercase tracking-widest">Mobile Video Tools</p>
133
 
134
  <div class="space-y-4">
135
+ <input type="text" id="videoUrl" placeholder="Tempel Link Video (.mp4)"
136
+ class="w-full p-4 rounded-2xl bg-slate-700 border border-slate-600 focus:outline-none focus:ring-2 focus:ring-blue-500 transition-all">
137
  <button onclick="startJob()" id="btnStart"
138
+ class="w-full bg-blue-600 hover:bg-blue-500 p-4 rounded-2xl font-bold text-lg shadow-lg active:scale-95 transition-all">
139
+ Proses Video
140
  </button>
141
  </div>
142
 
143
+ <div id="statusContainer" class="hidden mt-10 p-4 bg-slate-900/50 rounded-2xl">
144
+ <div class="flex justify-between mb-3">
145
+ <span id="statusText" class="text-sm font-medium text-blue-300 tracking-wide">Menyiapkan...</span>
146
+ <span id="progressPercent" class="text-sm font-black text-blue-400">0%</span>
147
  </div>
148
+ <div class="w-full bg-slate-700 rounded-full h-3">
149
+ <div id="progressBar" class="bg-blue-500 h-3 rounded-full transition-all duration-700 ease-out" style="width: 0%"></div>
150
  </div>
151
+
152
+ <div id="resultArea" class="mt-8 hidden animate-bounce">
153
  <a id="downloadBtn" href="#" target="_blank"
154
+ class="flex items-center justify-center gap-2 bg-emerald-600 hover:bg-emerald-500 text-white p-4 rounded-2xl font-bold shadow-xl">
155
+ <span>Simpan Video</span>
156
  </a>
157
  </div>
158
  </div>
159
  </div>
160
 
161
  <script>
162
+ let polling;
 
163
  async function startJob() {
164
  const url = document.getElementById('videoUrl').value;
165
+ if(!url) return alert('Masukkan link video dulu!');
166
 
167
  document.getElementById('btnStart').disabled = true;
168
  document.getElementById('statusContainer').classList.remove('hidden');
 
177
  const data = await res.json();
178
  if(data.jobId) pollStatus(data.jobId);
179
  } catch (err) {
180
+ alert('Gagal menghubungi server');
181
  document.getElementById('btnStart').disabled = false;
182
  }
183
  }
184
 
185
  function pollStatus(jobId) {
186
+ polling = setInterval(async () => {
187
  const res = await fetch('/api/status/' + jobId);
188
  const data = await res.json();
189
 
190
  document.getElementById('statusText').innerText = data.status;
191
+ const prog = data.progress || 0;
192
+ document.getElementById('progressPercent').innerText = prog + '%';
193
+ document.getElementById('progressBar').style.width = prog + '%';
194
 
195
  if(data.status === 'Completed') {
196
+ clearInterval(polling);
197
  document.getElementById('btnStart').disabled = false;
198
  document.getElementById('resultArea').classList.remove('hidden');
199
  document.getElementById('downloadBtn').href = data.result;
200
+ document.getElementById('statusText').innerText = "Selesai!";
201
  } else if(data.status === 'Error') {
202
+ clearInterval(polling);
203
+ alert('Gagal: ' + data.error);
204
  document.getElementById('btnStart').disabled = false;
205
  }
206
  }, 2000);
 
213
 
214
  app.post('/api/stabilize', (req, res) => {
215
  const { url } = req.body;
216
+ const jobId = randomUUID(); // Menggunakan crypto bawaan
217
  runStabilize(jobId, url);
218
  res.json({ jobId });
219
  });
 
224
  res.json(job);
225
  });
226
 
227
+ app.listen(port, '0.0.0.0', () => {
228
+ console.log(`Server aktif di port ${port}`);
229
  });