This commit is contained in:
thePR0M3TH3AN committed 2025-02-16 12:25:08 -05:00
1 parent f6e707db13
commit 55d6dad5fd
3 files changed
+97 -94

No files matched your search

+5 -5
View File
@@ -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 {
+90 -88
View File
@@ -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
View File
@@ -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",