recycleactor commited on
Commit
b753301
·
verified ·
1 Parent(s): ca1c057

Upload 3 files

Browse files
Files changed (2) hide show
  1. package.json +4 -4
  2. server.js +54 -52
package.json CHANGED
@@ -7,11 +7,11 @@
7
  "start": "node server.js"
8
  },
9
  "dependencies": {
10
- "express": "^4.18.2",
11
- "torrent-stream": "^1.2.0",
12
  "cors": "^2.8.5",
13
- "pump": "^3.0.0",
14
  "mime-types": "^2.1.35",
15
- "webtorrent": "^2.1.32"
 
 
16
  }
17
  }
 
7
  "start": "node server.js"
8
  },
9
  "dependencies": {
 
 
10
  "cors": "^2.8.5",
11
+ "express": "^4.18.2",
12
  "mime-types": "^2.1.35",
13
+ "pump": "^3.0.0",
14
+ "torrent-stream": "^1.2.1",
15
+ "webtorrent": "^2.5.0"
16
  }
17
  }
server.js CHANGED
@@ -1,5 +1,5 @@
1
  const express = require('express');
2
- const torrentStream = require('torrent-stream');
3
  const cors = require('cors');
4
  const pump = require('pump');
5
  const mime = require('mime-types');
@@ -11,11 +11,21 @@ const app = express();
11
  app.use(cors());
12
 
13
  // В Hugging Face Spaces для хранения кэша можно использовать /tmp
14
- const tmpDir = '/tmp/torrent-stream';
15
  if (!fs.existsSync(tmpDir)){
16
  fs.mkdirSync(tmpDir, { recursive: true });
17
  }
18
 
 
 
 
 
 
 
 
 
 
 
19
  // Кэш активных торрентов
20
  const activeTorrents = new Map();
21
  const initializingTorrents = new Map();
@@ -69,15 +79,14 @@ function getTorrent(magnet) {
69
  }
70
  }
71
 
72
- // Добавляем популярные трекеры для ускорения поиска пиров, если их нет
 
 
 
73
  if (typeof torrentInput === 'string' && torrentInput.startsWith('magnet:')) {
74
  const trackers = [
75
  'udp://tracker.opentrackr.org:1337/announce',
76
- 'udp://open.demonii.com:1337/announce',
77
  'udp://tracker.openbittorrent.com:80',
78
- 'udp://tracker.coppersurfer.tk:6969',
79
- 'udp://tracker.leechers-paradise.org:6969',
80
- 'udp://exodus.desync.com:6969',
81
  'wss://tracker.btorrent.xyz',
82
  'wss://tracker.openwebtorrent.com'
83
  ];
@@ -89,12 +98,33 @@ function getTorrent(magnet) {
89
  });
90
  }
91
 
92
- let engine;
93
  try {
94
- engine = torrentStream(torrentInput, {
95
- connections: 400, // Увеличиваем лимит пиров для большей скорости
96
- uploads: 2, // Ограничиваем отдачу, чтобы не забивать исходящий канал сервера
97
- path: tmpDir
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
98
  });
99
  } catch (err) {
100
  console.error('Failed to parse torrent identifier:', err.message);
@@ -107,44 +137,16 @@ function getTorrent(magnet) {
107
 
108
  // Устанавливаем таймаут на получение метаданных (60 секунд)
109
  const timeout = setTimeout(() => {
110
- if (engine) {
111
- engine.destroy();
 
 
 
112
  }
113
- activeTorrents.delete(magnet); // Очищаем кэш при таймауте
 
114
  reject(new Error('Timeout: failed to fetch torrent metadata within 60s. No peers found. (Убедитесь, что торрент живой и имеет раздающих)'));
115
  }, 60000);
116
-
117
- if (engine) {
118
- engine.on('ready', () => {
119
- clearTimeout(timeout);
120
- console.log('Torrent ready:', engine.infoHash);
121
- activeTorrents.set(magnet, engine);
122
- resolve(engine);
123
-
124
- // Таймер неактивности (уничтожаем если нет активных стримов более 5 минут)
125
- engine.lastActivity = Date.now();
126
- engine.activeStreams = 0;
127
-
128
- const checkActivity = setInterval(() => {
129
- if (engine.activeStreams === 0 && (Date.now() - engine.lastActivity > 5 * 60 * 1000)) {
130
- if (activeTorrents.has(magnet)) {
131
- engine.destroy();
132
- activeTorrents.delete(magnet);
133
- console.log('Torrent destroyed due to inactivity (no active streams for 5m):', engine.infoHash);
134
- clearInterval(checkActivity);
135
- }
136
- }
137
- }, 60 * 1000);
138
-
139
- engine.on('destroyed', () => clearInterval(checkActivity));
140
- });
141
-
142
- engine.on('error', (err) => {
143
- clearTimeout(timeout);
144
- console.error('Torrent engine error:', err);
145
- reject(err);
146
- });
147
- }
148
  });
149
 
150
  initializingTorrents.set(magnet, initPromise);
@@ -260,12 +262,12 @@ app.listen(PORT, () => {
260
 
261
  // Мониторинг скорости в логах Hugging Face
262
  setInterval(() => {
263
- activeTorrents.forEach((engine, magnet) => {
264
- if (engine.activeStreams > 0 && engine.swarm) {
265
- const speed = (engine.swarm.downloadSpeed() / 1024 / 1024).toFixed(2);
266
- const peers = engine.swarm.wires ? engine.swarm.wires.length : 0;
267
  if (speed > 0 || peers > 0) {
268
- console.log(`[Stream Active] Hash: ${engine.infoHash} | Speed: ${speed} MB/s | Peers: ${peers}`);
269
  }
270
  }
271
  });
 
1
  const express = require('express');
2
+ const WebTorrent = require('webtorrent');
3
  const cors = require('cors');
4
  const pump = require('pump');
5
  const mime = require('mime-types');
 
11
  app.use(cors());
12
 
13
  // В Hugging Face Spaces для хранения кэша можно использовать /tmp
14
+ const tmpDir = '/tmp/webtorrent';
15
  if (!fs.existsSync(tmpDir)){
16
  fs.mkdirSync(tmpDir, { recursive: true });
17
  }
18
 
19
+ // Создаем ОДИН инстанс клиента Webtorrent на весь сервер.
20
+ // Это критически важно: Webtorrent делит порты DHT и соединения между торрентами,
21
+ // что позволяет находить пиров гораздо быстрее, чем каждый раз создавать новый движок.
22
+ const client = new WebTorrent({
23
+ maxConns: 500, // Максимум соединений для клиента
24
+ tracker: true,
25
+ dht: true,
26
+ webSeeds: true // Поддержка web-пиров (ускоряет скачивание)
27
+ });
28
+
29
  // Кэш активных торрентов
30
  const activeTorrents = new Map();
31
  const initializingTorrents = new Map();
 
79
  }
80
  }
81
 
82
+ // WebTorrent сам умеет парсить трекеры из magnet-ссылки,
83
+ // но мы добавим несколько надежных WebSocket-трекеров для WebRTC-пиров
84
+ let opts = { path: tmpDir };
85
+
86
  if (typeof torrentInput === 'string' && torrentInput.startsWith('magnet:')) {
87
  const trackers = [
88
  'udp://tracker.opentrackr.org:1337/announce',
 
89
  'udp://tracker.openbittorrent.com:80',
 
 
 
90
  'wss://tracker.btorrent.xyz',
91
  'wss://tracker.openwebtorrent.com'
92
  ];
 
98
  });
99
  }
100
 
 
101
  try {
102
+ client.add(torrentInput, opts, (torrent) => {
103
+ clearTimeout(timeout);
104
+ console.log('Torrent ready:', torrent.infoHash);
105
+
106
+ // Таймер неактивности
107
+ torrent.lastActivity = Date.now();
108
+ torrent.activeStreams = 0;
109
+
110
+ activeTorrents.set(magnet, torrent);
111
+ resolve(torrent);
112
+
113
+ const checkActivity = setInterval(() => {
114
+ if (torrent.activeStreams === 0 && (Date.now() - torrent.lastActivity > 5 * 60 * 1000)) {
115
+ if (activeTorrents.has(magnet)) {
116
+ torrent.destroy();
117
+ activeTorrents.delete(magnet);
118
+ console.log('Torrent destroyed due to inactivity (no active streams for 5m):', torrent.infoHash);
119
+ clearInterval(checkActivity);
120
+ }
121
+ }
122
+ }, 60 * 1000);
123
+
124
+ torrent.on('error', (err) => {
125
+ console.error('Torrent engine error:', err);
126
+ clearInterval(checkActivity);
127
+ });
128
  });
129
  } catch (err) {
130
  console.error('Failed to parse torrent identifier:', err.message);
 
137
 
138
  // Устанавливаем таймаут на получение метаданных (60 секунд)
139
  const timeout = setTimeout(() => {
140
+ // Пытаемся найти и удалить зависший торрент
141
+ const hashMatch = typeof magnet === 'string' ? magnet.match(/urn:btih:([a-zA-Z0-9]+)/i) : null;
142
+ if (hashMatch) {
143
+ const existing = client.get(hashMatch[1]);
144
+ if (existing) existing.destroy();
145
  }
146
+
147
+ activeTorrents.delete(magnet);
148
  reject(new Error('Timeout: failed to fetch torrent metadata within 60s. No peers found. (Убедитесь, что торрент живой и имеет раздающих)'));
149
  }, 60000);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
150
  });
151
 
152
  initializingTorrents.set(magnet, initPromise);
 
262
 
263
  // Мониторинг скорости в логах Hugging Face
264
  setInterval(() => {
265
+ activeTorrents.forEach((torrent, magnet) => {
266
+ if (torrent.activeStreams > 0) {
267
+ const speed = (torrent.downloadSpeed / 1024 / 1024).toFixed(2);
268
+ const peers = torrent.numPeers;
269
  if (speed > 0 || peers > 0) {
270
+ console.log(`[Stream Active] Hash: ${torrent.infoHash} | Speed: ${speed} MB/s | Peers: ${peers}`);
271
  }
272
  }
273
  });