Uploads library on the USB drive with a nightly stable-disk copy; Topic channels resolve by name

- UPLOAD_DIR moves to the USB drive; reads fall back to UPLOAD_BACKUP_DIR on the
  ytplayer-data volume, and while the drive is offline new uploads land there
- scripts/ops/uploads-backup.sh (homelab cron, 03:30) copies both ways, never
  deletes; the server removes a deleted upload from both places
- /api/channel resolves a bare channel name ('Artist - Topic') to its id via a
  search, and the client falls back to the channel name for old saved entries
This commit is contained in:
Jonathan Sykes
2026-10-02 22:38:05 +08:00
parent 1f9a97a6ae
commit 11ddb8a970
6 changed files with 134 additions and 19 deletions

View File

@@ -165,3 +165,30 @@ describe('streaming upload (large / long files)', () => {
expect((await db.getUpload(up.upload.id)).art).toBeTruthy();
});
});
describe('upload storage on a removable drive', () => {
test('reads the drive copy, falls back to the backup copy, and writes to the backup while offline', async () => {
const { mkdtempSync, writeFileSync, rmSync } = await import('node:fs');
const { tmpdir } = await import('node:os');
const { join } = await import('node:path');
const { registerUploadRoutes } = await import('./uploads.js');
const root = mkdtempSync(join(tmpdir(), 'ytp-up-'));
const drive = join(root, 'usb'), uploadDir = join(drive, 'uploads'), backupDir = join(root, 'backup');
const marker = join(drive, '.hl-data');
(await import('node:fs')).mkdirSync(drive, { recursive: true });
writeFileSync(marker, '');
const noop = () => {};
const app = new Proxy({}, { get: () => noop });
const up = registerUploadRoutes(app, { db: {}, uploadDir, backupDir, volumeMarker: marker, rangeFileResponse: noop, requireAdminOrToken: noop });
const u = { id: 'up_test1', ext: 'mp4' };
writeFileSync(join(backupDir, 'up_test1.mp4'), 'backup');
expect(up.filePath(u)).toBe(join(backupDir, 'up_test1.mp4')); // drive copy missing → backup
writeFileSync(join(uploadDir, 'up_test1.mp4'), 'drive');
expect(up.filePath(u)).toBe(join(uploadDir, 'up_test1.mp4')); // drive copy preferred
rmSync(marker);
expect(up.filePath(u)).toBe(join(backupDir, 'up_test1.mp4')); // drive offline → backup
expect(up.filePath({ id: 'up_new', ext: 'mp4' })).toBe(join(backupDir, 'up_new.mp4')); // new writes go to the stable disk
rmSync(root, { recursive: true, force: true });
});
});