akborana4 commited on
Commit
8c64e05
·
verified ·
1 Parent(s): df2fb16

Update server/server.js

Browse files
Files changed (1) hide show
  1. server/server.js +54 -50
server/server.js CHANGED
@@ -91,11 +91,30 @@ function normalizeThumb(meta) {
91
  meta?.image_url,
92
  meta?.images?.[0],
93
  meta?.images?.medium,
94
- meta?.images?.cover
 
95
  ].filter(Boolean);
96
  return candidates[0] || null;
97
  }
98
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
99
  // ---------- API endpoints (JioSaavn proxy) ----------
100
  app.get('/api/result', async (req, res) => {
101
  try {
@@ -154,13 +173,7 @@ app.get('/api/ytsearch', async (req, res) => {
154
  if (!key) return res.status(501).json({ error: 'YouTube search unavailable: set YT_API_KEY env' });
155
  const q = req.query.q || '';
156
  const resp = await axios.get('https://www.googleapis.com/youtube/v3/search', {
157
- params: {
158
- key,
159
- q,
160
- part: 'snippet',
161
- type: 'video',
162
- maxResults: 10
163
- },
164
  timeout: 10000
165
  });
166
  const items = (resp.data.items || []).map(it => ({
@@ -211,7 +224,8 @@ io.on('connection', (socket) => {
211
  if (!room.name && roomName) room.name = String(roomName).trim().slice(0, 60) || null;
212
 
213
  const role = socket.id === room.hostId ? 'host' : 'member';
214
- room.users.set(socket.id, { name: String(name || 'Guest').slice(0, 40), role });
 
215
 
216
  socket.join(roomId);
217
  joinedRoom = roomId;
@@ -223,7 +237,7 @@ io.on('connection', (socket) => {
223
  roomName: room.name || room.id
224
  });
225
 
226
- io.to(roomId).emit('system', { text: `System: ${name || 'Guest'} has joined the chat` });
227
  broadcastMembers(roomId);
228
  });
229
 
@@ -248,15 +262,13 @@ io.on('connection', (socket) => {
248
  socket.to(roomId).emit('chat_message', { name, text, at: Date.now() });
249
  });
250
 
251
- // User /play request -> notify host/cohosts and room
252
  socket.on('song_request', ({ roomId, requester, query }) => {
253
  const room = rooms.get(roomId);
254
  if (!room) return;
255
  const payload = { requester, query, at: Date.now(), requestId: `${Date.now()}_${Math.random().toString(36).slice(2)}` };
256
  for (const [id, usr] of room.users.entries()) {
257
- if (id === room.hostId || usr.role === 'cohost') {
258
- io.to(id).emit('song_request', payload);
259
- }
260
  }
261
  io.to(roomId).emit('system', { text: `System: ${requester} requested /play ${query}` });
262
  });
@@ -266,34 +278,31 @@ io.on('connection', (socket) => {
266
  const room = rooms.get(roomId);
267
  if (!room) return;
268
  if (!requireHostOrCohost(room, socket.id)) return;
269
- if (action === 'accept' && track) {
270
- room.track = {
271
  url: track.url,
272
  title: track.title || track.url,
273
  meta: track.meta || {},
274
  kind: track.kind || 'audio',
275
  thumb: track.thumb || normalizeThumb(track.meta || {})
276
  };
277
- room.isPlaying = false;
278
- room.anchor = 0;
279
- room.anchorAt = Date.now();
280
- io.to(roomId).emit('set_track', { track: room.track });
281
- io.to(roomId).emit('pause', { anchor: 0, anchorAt: room.anchorAt });
282
- io.to(roomId).emit('system', { text: `System: Now playing ${room.track.title}` });
283
- } else if (action === 'queue' && track) {
284
- room.queue.push({
285
- url: track.url,
286
- title: track.title || track.url,
287
- meta: track.meta || {},
288
- kind: track.kind || 'audio',
289
- thumb: track.thumb || normalizeThumb(track.meta || {})
290
- });
291
- io.to(roomId).emit('queue_update', { queue: room.queue });
292
- io.to(roomId).emit('system', { text: `System: Queued ${track.title || track.url}` });
293
  }
294
  });
295
 
296
- // Host controls
297
  socket.on('set_track', ({ roomId, track }) => {
298
  const room = rooms.get(roomId);
299
  if (!room || !requireHostOrCohost(room, socket.id)) return;
@@ -333,7 +342,7 @@ io.on('connection', (socket) => {
333
  io.to(roomId).emit('seek', { anchor: room.anchor, anchorAt: room.anchorAt, isPlaying: room.isPlaying });
334
  });
335
 
336
- // Ended -> auto next from queue
337
  socket.on('ended', ({ roomId }) => {
338
  const room = rooms.get(roomId);
339
  if (!room || !requireHostOrCohost(room, socket.id)) return;
@@ -347,7 +356,7 @@ io.on('connection', (socket) => {
347
  io.to(roomId).emit('set_track', { track: room.track });
348
  io.to(roomId).emit('pause', { anchor: 0, anchorAt: room.anchorAt });
349
  io.to(roomId).emit('queue_update', { queue: room.queue });
350
- io.to(roomId).emit('system', { text: `System: Now playing ${room.track.title || room.track.url}` });
351
  } else {
352
  io.to(roomId).emit('system', { text: 'System: Queue ended' });
353
  }
@@ -360,32 +369,26 @@ io.on('connection', (socket) => {
360
  const actor = room.users.get(socket.id);
361
  if (!actor || !(socket.id === room.hostId || actor.role === 'cohost')) return;
362
 
363
- let targetEntry = null;
364
- for (const [id, u] of room.users.entries()) {
365
- if (u.name && u.name.toLowerCase() === targetName.toLowerCase()) {
366
- targetEntry = { id, u };
367
- break;
368
- }
369
- }
370
- if (!targetEntry) {
371
  io.to(socket.id).emit('system', { text: `System: User @${targetName} not found` });
372
  return;
373
  }
374
 
375
  if (cmd === 'kick') {
376
- const { id } = targetEntry;
377
  io.to(id).emit('system', { text: 'System: You were kicked by the host' });
378
  io.sockets.sockets.get(id)?.leave(roomId);
379
  room.users.delete(id);
380
- io.to(roomId).emit('system', { text: `System: ${targetEntry.u.name} was kicked` });
381
  broadcastMembers(roomId);
382
  } else if (cmd === 'promote') {
383
- targetEntry.u.role = 'cohost';
384
- io.to(roomId).emit('system', { text: `System: ${targetEntry.u.name} was promoted to co-host` });
385
  broadcastMembers(roomId);
386
  } else if (cmd === 'mute') {
387
- targetEntry.u.muted = true;
388
- io.to(roomId).emit('system', { text: `System: ${targetEntry.u.name} was muted` });
389
  broadcastMembers(roomId);
390
  }
391
  });
@@ -412,7 +415,8 @@ io.on('connection', (socket) => {
412
  io.to(joinedRoom).emit('host_changed', { hostId: room.hostId });
413
  }
414
  if (leftUser) {
415
- io.to(joinedRoom).emit('system', { text: `System: ${leftUser.name || 'User'} has left the chat` });
 
416
  }
417
  if (room.users.size === 0) {
418
  rooms.delete(joinedRoom);
 
91
  meta?.image_url,
92
  meta?.images?.[0],
93
  meta?.images?.medium,
94
+ meta?.images?.cover,
95
+ meta?.thumb
96
  ].filter(Boolean);
97
  return candidates[0] || null;
98
  }
99
 
100
+ function findUserByName(room, targetNameRaw) {
101
+ if (!targetNameRaw) return null;
102
+ const targetName = String(targetNameRaw).replace(/^@/, '').trim().toLowerCase();
103
+ // Prefer exact match, else startsWith, else includes
104
+ let candidate = null;
105
+ for (const [id, u] of room.users.entries()) {
106
+ const n = (u.name || '').toLowerCase();
107
+ if (n === targetName) return { id, u };
108
+ if (!candidate && n.startsWith(targetName)) candidate = { id, u };
109
+ }
110
+ if (candidate) return candidate;
111
+ for (const [id, u] of room.users.entries()) {
112
+ const n = (u.name || '').toLowerCase();
113
+ if (n.includes(targetName)) return { id, u };
114
+ }
115
+ return null;
116
+ }
117
+
118
  // ---------- API endpoints (JioSaavn proxy) ----------
119
  app.get('/api/result', async (req, res) => {
120
  try {
 
173
  if (!key) return res.status(501).json({ error: 'YouTube search unavailable: set YT_API_KEY env' });
174
  const q = req.query.q || '';
175
  const resp = await axios.get('https://www.googleapis.com/youtube/v3/search', {
176
+ params: { key, q, part: 'snippet', type: 'video', maxResults: 12 },
 
 
 
 
 
 
177
  timeout: 10000
178
  });
179
  const items = (resp.data.items || []).map(it => ({
 
224
  if (!room.name && roomName) room.name = String(roomName).trim().slice(0, 60) || null;
225
 
226
  const role = socket.id === room.hostId ? 'host' : 'member';
227
+ const cleanName = String(name || 'Guest').slice(0, 40);
228
+ room.users.set(socket.id, { name: cleanName, role });
229
 
230
  socket.join(roomId);
231
  joinedRoom = roomId;
 
237
  roomName: room.name || room.id
238
  });
239
 
240
+ io.to(roomId).emit('system', { text: `System: ${cleanName} has joined the chat` });
241
  broadcastMembers(roomId);
242
  });
243
 
 
262
  socket.to(roomId).emit('chat_message', { name, text, at: Date.now() });
263
  });
264
 
265
+ // /play request
266
  socket.on('song_request', ({ roomId, requester, query }) => {
267
  const room = rooms.get(roomId);
268
  if (!room) return;
269
  const payload = { requester, query, at: Date.now(), requestId: `${Date.now()}_${Math.random().toString(36).slice(2)}` };
270
  for (const [id, usr] of room.users.entries()) {
271
+ if (id === room.hostId || usr.role === 'cohost') io.to(id).emit('song_request', payload);
 
 
272
  }
273
  io.to(roomId).emit('system', { text: `System: ${requester} requested /play ${query}` });
274
  });
 
278
  const room = rooms.get(roomId);
279
  if (!room) return;
280
  if (!requireHostOrCohost(room, socket.id)) return;
281
+ if ((action === 'accept' || action === 'queue') && track) {
282
+ const t = {
283
  url: track.url,
284
  title: track.title || track.url,
285
  meta: track.meta || {},
286
  kind: track.kind || 'audio',
287
  thumb: track.thumb || normalizeThumb(track.meta || {})
288
  };
289
+ if (action === 'accept') {
290
+ room.track = t;
291
+ room.isPlaying = false;
292
+ room.anchor = 0;
293
+ room.anchorAt = Date.now();
294
+ io.to(roomId).emit('set_track', { track: room.track });
295
+ io.to(roomId).emit('pause', { anchor: 0, anchorAt: room.anchorAt });
296
+ io.to(roomId).emit('system', { text: `System: Now playing ${room.track.title}` });
297
+ } else {
298
+ room.queue.push(t);
299
+ io.to(roomId).emit('queue_update', { queue: room.queue });
300
+ io.to(roomId).emit('system', { text: `System: Queued ${t.title}` });
301
+ }
 
 
 
302
  }
303
  });
304
 
305
+ // Host/cohost controls
306
  socket.on('set_track', ({ roomId, track }) => {
307
  const room = rooms.get(roomId);
308
  if (!room || !requireHostOrCohost(room, socket.id)) return;
 
342
  io.to(roomId).emit('seek', { anchor: room.anchor, anchorAt: room.anchorAt, isPlaying: room.isPlaying });
343
  });
344
 
345
+ // Ended -> auto next
346
  socket.on('ended', ({ roomId }) => {
347
  const room = rooms.get(roomId);
348
  if (!room || !requireHostOrCohost(room, socket.id)) return;
 
356
  io.to(roomId).emit('set_track', { track: room.track });
357
  io.to(roomId).emit('pause', { anchor: 0, anchorAt: room.anchorAt });
358
  io.to(roomId).emit('queue_update', { queue: room.queue });
359
+ io.to(roomId).emit('system', { text: `System: Now playing ${room.track.title}` });
360
  } else {
361
  io.to(roomId).emit('system', { text: 'System: Queue ended' });
362
  }
 
369
  const actor = room.users.get(socket.id);
370
  if (!actor || !(socket.id === room.hostId || actor.role === 'cohost')) return;
371
 
372
+ const found = findUserByName(room, targetName);
373
+ if (!found) {
 
 
 
 
 
 
374
  io.to(socket.id).emit('system', { text: `System: User @${targetName} not found` });
375
  return;
376
  }
377
 
378
  if (cmd === 'kick') {
379
+ const { id } = found;
380
  io.to(id).emit('system', { text: 'System: You were kicked by the host' });
381
  io.sockets.sockets.get(id)?.leave(roomId);
382
  room.users.delete(id);
383
+ io.to(roomId).emit('system', { text: `System: ${found.u.name} was kicked` });
384
  broadcastMembers(roomId);
385
  } else if (cmd === 'promote') {
386
+ found.u.role = 'cohost';
387
+ io.to(roomId).emit('system', { text: `System: ${found.u.name} was promoted to co-host` });
388
  broadcastMembers(roomId);
389
  } else if (cmd === 'mute') {
390
+ found.u.muted = true;
391
+ io.to(roomId).emit('system', { text: `System: ${found.u.name} was muted` });
392
  broadcastMembers(roomId);
393
  }
394
  });
 
415
  io.to(joinedRoom).emit('host_changed', { hostId: room.hostId });
416
  }
417
  if (leftUser) {
418
+ const nm = leftUser.name || 'User';
419
+ io.to(joinedRoom).emit('system', { text: `System: ${nm} has left the chat` });
420
  }
421
  if (room.users.size === 0) {
422
  rooms.delete(joinedRoom);