mirror of
https://github.com/PR0M3TH3AN/bitvid-seeder.git
synced 2026-11-07 21:31:14 +00:00
update
This commit is contained in:
1 parent
f6e707db13
commit
55d6dad5fd
3 files changed
+97
-94
No files matched your search
+5
-5
@@ -1,11 +1,11 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>bitvid Torrent Seeder</title>
|
||||
<!-- Bootstrap CSS -->
|
||||
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" />
|
||||
</head>
|
||||
<body>
|
||||
<div class="container my-4">
|
||||
@@ -44,7 +44,7 @@
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="torrentList">
|
||||
<!-- Rows are populated dynamically -->
|
||||
<!-- Rows populated dynamically -->
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
@@ -79,7 +79,7 @@
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- JavaScript -->
|
||||
<!-- JavaScript for UI -->
|
||||
<script>
|
||||
async function fetchTorrents() {
|
||||
try {
|
||||
|
||||
@@ -26,7 +26,7 @@ const app = express();
|
||||
const port = process.env.PORT || 3000;
|
||||
const client = new WebTorrent();
|
||||
|
||||
// Increase max listeners for our client (and all EventEmitters)
|
||||
// Increase max listeners for our client
|
||||
client.setMaxListeners(50);
|
||||
|
||||
// ES module __dirname workaround
|
||||
@@ -99,12 +99,99 @@ async function pathExists(p) {
|
||||
}
|
||||
}
|
||||
|
||||
// GET /torrents - Return both active and paused torrents
|
||||
app.get('/torrents', (req, res) => {
|
||||
try {
|
||||
// Active torrents: those in the client
|
||||
const active = client.torrents.map(t => ({
|
||||
infoHash: t.infoHash,
|
||||
name: t.name,
|
||||
progress: t.progress,
|
||||
numPeers: t.numPeers,
|
||||
downloaded: t.downloaded,
|
||||
uploaded: t.uploaded,
|
||||
paused: false
|
||||
}));
|
||||
// Paused torrents: those saved with paused: true
|
||||
const paused = savedTorrents
|
||||
.filter(s => s.paused)
|
||||
.map(s => ({
|
||||
infoHash: s.infoHash,
|
||||
name: s.name,
|
||||
progress: 1,
|
||||
numPeers: 0,
|
||||
downloaded: 0,
|
||||
uploaded: 0,
|
||||
paused: true
|
||||
}));
|
||||
const torrents = [...active, ...paused];
|
||||
logger.info('GET /torrents returning: ' + JSON.stringify(torrents));
|
||||
res.json(torrents);
|
||||
} catch (err) {
|
||||
logger.error('Error listing torrents: ' + err);
|
||||
res.status(500).json({ error: 'Error listing torrents' });
|
||||
}
|
||||
});
|
||||
|
||||
// POST /pause/:infoHash - Pause a torrent (remove it from the active client and mark as paused)
|
||||
app.post('/pause/:infoHash', (req, res) => {
|
||||
const infoHash = req.params.infoHash;
|
||||
const torrent = client.get(infoHash);
|
||||
if (!torrent) {
|
||||
return res.status(400).json({ error: 'Torrent not active or already paused' });
|
||||
}
|
||||
client.remove(infoHash, { destroyStore: false }, err => {
|
||||
if (err) {
|
||||
logger.error('Error pausing torrent: ' + err);
|
||||
return res.status(500).json({ error: 'Error pausing torrent' });
|
||||
}
|
||||
// Update savedTorrents to mark this torrent as paused.
|
||||
const entry = savedTorrents.find(s => s.infoHash === infoHash);
|
||||
if (entry) entry.paused = true;
|
||||
saveTorrents();
|
||||
logger.info(`Torrent paused: ${infoHash}`);
|
||||
res.json({ message: 'Torrent paused' });
|
||||
});
|
||||
});
|
||||
|
||||
// POST /resume/:infoHash - Resume a paused torrent (re-add it to the client)
|
||||
app.post('/resume/:infoHash', async (req, res) => {
|
||||
const infoHash = req.params.infoHash;
|
||||
const entry = savedTorrents.find(s => s.infoHash === infoHash);
|
||||
if (!entry) {
|
||||
return res.status(400).json({ error: 'Torrent not found in saved data' });
|
||||
}
|
||||
entry.paused = false;
|
||||
saveTorrents();
|
||||
const torrentPath = path.join(STORAGE_DIR, entry.name);
|
||||
const exists = await pathExists(torrentPath);
|
||||
try {
|
||||
if (exists) {
|
||||
client.seed(torrentPath, { name: entry.name, keepSeeding: true }, torrent => {
|
||||
logger.info(`Torrent resumed (seeding from file): ${torrent.infoHash}`);
|
||||
res.json({ message: 'Torrent resumed' });
|
||||
});
|
||||
} else {
|
||||
client.add(entry.magnet, { path: STORAGE_DIR, keepSeeding: true }, torrent => {
|
||||
logger.info(`Torrent resumed (downloading): ${torrent.infoHash}`);
|
||||
res.json({ message: 'Torrent resumed' });
|
||||
});
|
||||
}
|
||||
} catch (err) {
|
||||
logger.error('Error resuming torrent: ' + err);
|
||||
res.status(500).json({ error: 'Error resuming torrent' });
|
||||
}
|
||||
});
|
||||
|
||||
// Load saved torrents concurrently on startup.
|
||||
// For each saved torrent, if the expected file/folder exists, we seed from that location;
|
||||
// otherwise, we add the torrent to download.
|
||||
// (Paused torrents will have "paused": true in savedTorrents and should not be added automatically.)
|
||||
async function loadSavedTorrents() {
|
||||
await Promise.all(
|
||||
savedTorrents.map(async torrentData => {
|
||||
// Only auto-load if not marked paused.
|
||||
if (torrentData.paused) return;
|
||||
const torrentPath = path.join(STORAGE_DIR, torrentData.name);
|
||||
const exists = await pathExists(torrentPath);
|
||||
try {
|
||||
@@ -125,11 +212,6 @@ async function loadSavedTorrents() {
|
||||
}
|
||||
loadSavedTorrents();
|
||||
|
||||
// GET /config - Return current storage configuration
|
||||
app.get('/config', (req, res) => {
|
||||
res.json({ storageDir: STORAGE_DIR });
|
||||
});
|
||||
|
||||
// POST /config - Update storage directory (with input validation)
|
||||
app.post('/config', (req, res) => {
|
||||
const { storageDir } = req.body;
|
||||
@@ -159,7 +241,6 @@ app.post('/add', (req, res) => {
|
||||
if (!magnet.startsWith('magnet:?')) {
|
||||
return res.status(400).json({ error: 'Invalid magnet link format' });
|
||||
}
|
||||
// Check if the torrent already exists in saved metadata.
|
||||
if (savedTorrents.some(t => t.magnet === magnet)) {
|
||||
logger.info('Attempted to add duplicate torrent.');
|
||||
return res.status(409).json({ error: 'Torrent already added.' });
|
||||
@@ -170,7 +251,8 @@ app.post('/add', (req, res) => {
|
||||
const torrentData = {
|
||||
magnet,
|
||||
infoHash: torrent.infoHash,
|
||||
name: torrent.name
|
||||
name: torrent.name,
|
||||
paused: false
|
||||
};
|
||||
savedTorrents.push(torrentData);
|
||||
saveTorrents();
|
||||
@@ -182,86 +264,6 @@ app.post('/add', (req, res) => {
|
||||
}
|
||||
});
|
||||
|
||||
// GET /torrents - List active torrents
|
||||
app.get('/torrents', (req, res) => {
|
||||
try {
|
||||
// Active torrents: those currently in the client.
|
||||
const active = client.torrents.map(t => ({
|
||||
infoHash: t.infoHash,
|
||||
name: t.name,
|
||||
progress: t.progress,
|
||||
numPeers: t.numPeers,
|
||||
downloaded: t.downloaded,
|
||||
uploaded: t.uploaded,
|
||||
paused: false
|
||||
}));
|
||||
// Paused torrents: in savedTorrents but not active.
|
||||
const paused = savedTorrents
|
||||
.filter(s => !client.get(s.infoHash))
|
||||
.map(s => ({
|
||||
infoHash: s.infoHash,
|
||||
name: s.name,
|
||||
progress: 1,
|
||||
numPeers: 0,
|
||||
downloaded: 0,
|
||||
uploaded: 0,
|
||||
paused: true
|
||||
}));
|
||||
const torrents = [...active, ...paused];
|
||||
logger.info('GET /torrents returning: ' + JSON.stringify(torrents));
|
||||
res.json(torrents);
|
||||
} catch (err) {
|
||||
logger.error('Error listing torrents: ' + err);
|
||||
res.status(500).json({ error: 'Error listing torrents' });
|
||||
}
|
||||
});
|
||||
|
||||
// POST /pause/:infoHash - Pause a torrent by removing it from the active client.
|
||||
// We do not remove its saved metadata.
|
||||
app.post('/pause/:infoHash', (req, res) => {
|
||||
const infoHash = req.params.infoHash;
|
||||
const torrent = client.get(infoHash);
|
||||
if (!torrent) {
|
||||
return res.status(400).json({ error: 'Torrent not active or already paused' });
|
||||
}
|
||||
// Use client.remove to remove the torrent from active seeding.
|
||||
client.remove(infoHash, { destroyStore: false }, err => {
|
||||
if (err) {
|
||||
logger.error('Error pausing torrent: ' + err);
|
||||
return res.status(500).json({ error: 'Error pausing torrent' });
|
||||
}
|
||||
logger.info(`Torrent paused: ${infoHash}`);
|
||||
res.json({ message: 'Torrent paused' });
|
||||
});
|
||||
});
|
||||
|
||||
// POST /resume/:infoHash - Resume a paused torrent (re-add it).
|
||||
app.post('/resume/:infoHash', async (req, res) => {
|
||||
const infoHash = req.params.infoHash;
|
||||
const savedData = savedTorrents.find(s => s.infoHash === infoHash);
|
||||
if (!savedData) {
|
||||
return res.status(400).json({ error: 'Torrent not found in saved data' });
|
||||
}
|
||||
const torrentPath = path.join(STORAGE_DIR, savedData.name);
|
||||
const exists = await pathExists(torrentPath);
|
||||
try {
|
||||
if (exists) {
|
||||
client.seed(torrentPath, { name: savedData.name, keepSeeding: true }, torrent => {
|
||||
logger.info(`Torrent resumed (seeding from file): ${torrent.infoHash}`);
|
||||
res.json({ message: 'Torrent resumed' });
|
||||
});
|
||||
} else {
|
||||
client.add(savedData.magnet, { path: STORAGE_DIR, keepSeeding: true }, torrent => {
|
||||
logger.info(`Torrent resumed (downloading): ${torrent.infoHash}`);
|
||||
res.json({ message: 'Torrent resumed' });
|
||||
});
|
||||
}
|
||||
} catch (err) {
|
||||
logger.error('Error resuming torrent: ' + err);
|
||||
res.status(500).json({ error: 'Error resuming torrent' });
|
||||
}
|
||||
});
|
||||
|
||||
// DELETE /remove/:infoHash - Remove a torrent completely.
|
||||
app.delete('/remove/:infoHash', (req, res) => {
|
||||
const infoHash = req.params.infoHash;
|
||||
|
||||
+2
-1
@@ -2,7 +2,8 @@
|
||||
{
|
||||
"magnet": "magnet:?xt=urn:btih:0b0176838873aa20b1d16e15f77bd4e4aa36a706&dn=bitvid-logo-loop.mp4&tr=udp%3A%2F%2Ftracker.leechers-paradise.org%3A6969&tr=udp%3A%2F%2Ftracker.coppersurfer.tk%3A6969&tr=udp%3A%2F%2Ftracker.opentrackr.org%3A1337&tr=udp%3A%2F%2Fexplodie.org%3A6969&tr=udp%3A%2F%2Ftracker.empire-js.us%3A1337&tr=wss%3A%2F%2Ftracker.btorrent.xyz&tr=wss%3A%2F%2Ftracker.openwebtorrent.com",
|
||||
"infoHash": "0b0176838873aa20b1d16e15f77bd4e4aa36a706",
|
||||
"name": "bitvid-logo-loop.mp4"
|
||||
"name": "bitvid-logo-loop.mp4",
|
||||
"paused": false
|
||||
},
|
||||
{
|
||||
"magnet": "magnet:?xt=urn:btih:846b56e6ac935e02a6047dc9369129c3bf013822&dn=Alien+Plexus+in+Cinema+4D.mp4&tr=udp%3A%2F%2Ftracker.leechers-paradise.org%3A6969&tr=udp%3A%2F%2Ftracker.coppersurfer.tk%3A6969&tr=udp%3A%2F%2Ftracker.opentrackr.org%3A1337&tr=udp%3A%2F%2Fexplodie.org%3A6969&tr=udp%3A%2F%2Ftracker.empire-js.us%3A1337&tr=wss%3A%2F%2Ftracker.btorrent.xyz&tr=wss%3A%2F%2Ftracker.openwebtorrent.com",
|
||||
|
||||
Reference in new issue
Block a user