Skip to content

Commit 854f69a

Browse files
authored
Merge pull request #16 from greirson/notification-enhancements
Size and Total Storage templates for Notifications
2 parents 2b78c12 + 89fe5c7 commit 854f69a

File tree

4 files changed

+95
-24
lines changed

4 files changed

+95
-24
lines changed

.env.example

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,5 @@ DUMBDROP_PIN= # Optional PIN protection (4-10 digits, leave empty to
1010

1111
# Notifications
1212
APPRISE_URL= # Apprise URL for notifications (leave empty to disable)
13-
APPRISE_MESSAGE= # Custom message for notifications (default: "File uploaded: {filename}")
13+
APPRISE_MESSAGE= # Custom message for notifications (default: "New file uploaded: {filename} ({size}), Storage used: {storage}")
14+
APPRISE_SIZE_UNIT= # Size unit for notifications (B, KB, MB, GB, TB). Leave empty for auto

README.md

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -23,14 +23,32 @@ No auth (unless you want it now!), no storage, no nothing. Just a simple file up
2323

2424
## Environment Variables
2525

26-
| Variable | Description | Default | Required |
27-
|--------------|---------------------------------------|---------|----------|
28-
| PORT | Server port | 3000 | No |
29-
| MAX_FILE_SIZE| Maximum file size in MB | 1024 | No |
30-
| DUMBDROP_PIN | PIN protection (4-10 digits) | None | No |
31-
| DUMBDROP_TITLE| Site title displayed in header | DumbDrop| No |
32-
| APPRISE_URL | Apprise URL for notifications | None | No |
33-
| APPRISE_MESSAGE| Notification message template | "File uploaded: {filename}" | No |
26+
| Variable | Description | Default | Required |
27+
|------------------|---------------------------------------|---------|----------|
28+
| PORT | Server port | 3000 | No |
29+
| MAX_FILE_SIZE | Maximum file size in MB | 1024 | No |
30+
| DUMBDROP_PIN | PIN protection (4-10 digits) | None | No |
31+
| DUMBDROP_TITLE | Site title displayed in header | DumbDrop| No |
32+
| APPRISE_URL | Apprise URL for notifications | None | No |
33+
| APPRISE_MESSAGE | Notification message template | New file uploaded {filename} ({size}), Storage used {storage} | No |
34+
| APPRISE_SIZE_UNIT| Size unit for notifications | Auto | No |
35+
36+
## Notification Templates
37+
The notification message supports the following placeholders:
38+
- `{filename}`: Name of the uploaded file
39+
- `{size}`: Size of the file (formatted according to APPRISE_SIZE_UNIT)
40+
- `{storage}`: Total size of all files in upload directory
41+
42+
Example message template:
43+
```env
44+
APPRISE_MESSAGE: New file uploaded {filename} ({size}), Storage used {storage}
45+
```
46+
47+
Size formatting examples:
48+
- Auto (default): Chooses nearest unit (e.g., "1.44MB", "256KB")
49+
- Fixed unit: Set APPRISE_SIZE_UNIT to B, KB, MB, GB, or TB
50+
51+
Both {size} and {storage} use the same formatting rules based on APPRISE_SIZE_UNIT.
3452

3553
## Security Features
3654

docker-compose.yml

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,11 @@ services:
66
volumes:
77
- ./local_uploads:/app/uploads
88
environment:
9-
- DUMBDROP_PIN=123456
10-
- APPRISE_URL= # i.e. tgram://bottoken/ChatID
11-
- APPRISE_MESSAGE= # dont add quotes here
12-
image: abite3/dumbdrop:latest
9+
DUMBDROP_TITLE: DumbDrop
10+
MAX_FILE_SIZE: 1024
11+
DUMBDROP_PIN: 123456
12+
# APPRISE_URL: ntfys://
13+
APPRISE_MESSAGE: New file uploaded - {filename} ({size}), Storage used {storage}
14+
APPRISE_SIZE_UNIT: auto
15+
image: abite3/dumbdrop:latest
16+
# build: .

server.js

Lines changed: 59 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,9 @@ const port = process.env.PORT || 3000;
1515
const uploadDir = './uploads'; // Local development
1616
const maxFileSize = parseInt(process.env.MAX_FILE_SIZE || '1024') * 1024 * 1024; // Convert MB to bytes
1717
const APPRISE_URL = process.env.APPRISE_URL;
18-
const APPRISE_MESSAGE = process.env.APPRISE_MESSAGE || 'File uploaded: {filename}';
18+
const APPRISE_MESSAGE = process.env.APPRISE_MESSAGE || 'New file uploaded - {filename} ({size}), Storage used: {storage}';
1919
const siteTitle = process.env.DUMBDROP_TITLE || 'DumbDrop';
20+
const APPRISE_SIZE_UNIT = process.env.APPRISE_SIZE_UNIT;
2021

2122
// Brute force protection setup
2223
const loginAttempts = new Map(); // Stores IP addresses and their attempt counts
@@ -259,7 +260,7 @@ app.post('/upload/init', async (req, res) => {
259260
app.post('/upload/chunk/:uploadId', express.raw({
260261
limit: '10mb',
261262
type: 'application/octet-stream'
262-
}), (req, res) => {
263+
}), async (req, res) => {
263264
const { uploadId } = req.params;
264265
const upload = uploads.get(uploadId);
265266
const chunkSize = req.body.length;
@@ -273,7 +274,7 @@ app.post('/upload/chunk/:uploadId', express.raw({
273274
upload.bytesReceived += chunkSize;
274275

275276
const progress = Math.round((upload.bytesReceived / upload.fileSize) * 100);
276-
log.info(`Received chunk for ${upload.filename}: ${progress}%`);
277+
log.info(`Received chunk for ${upload.safeFilename}: ${progress}%`);
277278

278279
res.json({
279280
bytesReceived: upload.bytesReceived,
@@ -284,10 +285,10 @@ app.post('/upload/chunk/:uploadId', express.raw({
284285
if (upload.bytesReceived >= upload.fileSize) {
285286
upload.writeStream.end();
286287
uploads.delete(uploadId);
287-
log.success(`Upload completed: ${upload.filename}`);
288+
log.success(`Upload completed: ${upload.safeFilename}`);
288289

289-
// Add notification here
290-
sendNotification(upload.filename);
290+
// Update notification call to use safeFilename
291+
await sendNotification(upload.safeFilename, upload.fileSize);
291292
}
292293
} catch (err) {
293294
log.error(`Chunk upload failed: ${err.message}`);
@@ -305,7 +306,7 @@ app.post('/upload/cancel/:uploadId', (req, res) => {
305306
if (err) log.error(`Failed to delete incomplete upload: ${err.message}`);
306307
});
307308
uploads.delete(uploadId);
308-
log.info(`Upload cancelled: ${upload.filename}`);
309+
log.info(`Upload cancelled: ${upload.safeFilename}`);
309310
}
310311

311312
res.json({ message: 'Upload cancelled' });
@@ -346,16 +347,63 @@ app.listen(port, () => {
346347
}
347348
});
348349

349-
// Add this helper function after other helper functions
350-
async function sendNotification(filename) {
350+
// Remove async from formatFileSize function
351+
function formatFileSize(bytes) {
352+
const units = ['B', 'KB', 'MB', 'GB', 'TB'];
353+
let size = bytes;
354+
let unitIndex = 0;
355+
356+
// If a specific unit is requested
357+
if (APPRISE_SIZE_UNIT) {
358+
const requestedUnit = APPRISE_SIZE_UNIT.toUpperCase();
359+
const unitIndex = units.indexOf(requestedUnit);
360+
if (unitIndex !== -1) {
361+
size = bytes / Math.pow(1024, unitIndex);
362+
return size.toFixed(2) + requestedUnit;
363+
}
364+
}
365+
366+
// Auto format to nearest unit
367+
while (size >= 1024 && unitIndex < units.length - 1) {
368+
size /= 1024;
369+
unitIndex++;
370+
}
371+
372+
// Round to 2 decimal places
373+
return size.toFixed(2) + units[unitIndex];
374+
}
375+
376+
// Add this helper function
377+
function calculateDirectorySize(directoryPath) {
378+
let totalSize = 0;
379+
const files = fs.readdirSync(directoryPath);
380+
381+
files.forEach(file => {
382+
const filePath = path.join(directoryPath, file);
383+
const stats = fs.statSync(filePath);
384+
if (stats.isFile()) {
385+
totalSize += stats.size;
386+
}
387+
});
388+
389+
return totalSize;
390+
}
391+
392+
// Modify the sendNotification function
393+
async function sendNotification(filename, fileSize) {
351394
if (!APPRISE_URL) return;
352395

353396
try {
354-
const message = APPRISE_MESSAGE.replace('{filename}', filename);
397+
const formattedSize = formatFileSize(fileSize);
398+
const totalStorage = formatFileSize(calculateDirectorySize(uploadDir));
399+
const message = APPRISE_MESSAGE
400+
.replace('{filename}', filename)
401+
.replace('{size}', formattedSize)
402+
.replace('{storage}', totalStorage);
355403

356404
// Execute apprise command
357405
await execAsync(`apprise "${APPRISE_URL}" -b "${message}"`);
358-
log.info(`Notification sent for: ${filename}`);
406+
log.info(`Notification sent for: ${filename} (${formattedSize}, Total storage: ${totalStorage})`);
359407
} catch (err) {
360408
log.error(`Failed to send notification: ${err.message}`);
361409
}

0 commit comments

Comments
 (0)