release: v2.0.6

Redesign the desktop workspace with task sidebars, live filters, clearer settings, and an accessible update dialog.

Harden encrypted backup imports, configuration persistence, history retention, queue snapshots, shutdown recovery, and update installation ordering.

Publish verified Windows artifacts and refreshed English documentation.
This commit is contained in:
Sucukdeluxe
2026-08-10 09:28:28 +02:00
commit 76a228fb7c
113 changed files with 36923 additions and 0 deletions
+115
View File
@@ -0,0 +1,115 @@
const test = require('node:test');
const assert = require('node:assert');
const fs = require('fs');
const os = require('os');
const path = require('path');
const { detectKind, isVideoLikeKind, probeFileHead, summarizeFileStat } = require('../lib/file-probe');
function tmpWrite(name, buf) {
const p = path.join(os.tmpdir(), `mhu-probe-${Date.now()}-${name}`);
fs.writeFileSync(p, buf);
return p;
}
test('detectKind recognizes ISO-MP4 (ftyp box at offset 4)', () => {
const buf = Buffer.concat([Buffer.from([0x00, 0x00, 0x00, 0x20]), Buffer.from('ftypisom', 'ascii'), Buffer.alloc(8, 0)]);
assert.strictEqual(detectKind(buf), 'mp4-iso');
assert.strictEqual(isVideoLikeKind('mp4-iso'), true);
});
test('detectKind recognizes Matroska / WebM EBML header', () => {
const buf = Buffer.from([0x1A, 0x45, 0xDF, 0xA3, 0x01, 0x00]);
assert.strictEqual(detectKind(buf), 'matroska');
assert.strictEqual(isVideoLikeKind('matroska'), true);
});
test('detectKind recognizes AVI (RIFF...AVI )', () => {
const buf = Buffer.concat([Buffer.from('RIFF', 'ascii'), Buffer.from([0x00, 0x00, 0x00, 0x00]), Buffer.from('AVI ', 'ascii')]);
assert.strictEqual(detectKind(buf), 'avi');
});
test('detectKind recognizes FLV', () => {
const buf = Buffer.concat([Buffer.from('FLV', 'ascii'), Buffer.from([0x01])]);
assert.strictEqual(detectKind(buf), 'flv');
});
test('detectKind recognizes ASF (WMV)', () => {
const buf = Buffer.from([0x30, 0x26, 0xB2, 0x75, 0x00, 0x00]);
assert.strictEqual(detectKind(buf), 'asf-wmv');
});
test('detectKind recognizes MPEG-PS (00 00 01 BA)', () => {
const buf = Buffer.from([0x00, 0x00, 0x01, 0xBA, 0x00]);
assert.strictEqual(detectKind(buf), 'mpeg-ps');
});
test('detectKind recognizes JPEG (non-video)', () => {
const buf = Buffer.from([0xFF, 0xD8, 0xFF, 0xE0]);
assert.strictEqual(detectKind(buf), 'jpeg');
assert.strictEqual(isVideoLikeKind('jpeg'), false);
});
test('detectKind recognizes HTML response (non-video)', () => {
const buf = Buffer.from('<!DOCTYPE html><html><head>', 'ascii');
assert.strictEqual(detectKind(buf), 'html');
assert.strictEqual(isVideoLikeKind('html'), false);
});
test('detectKind returns empty for zero-length and unknown for noise', () => {
assert.strictEqual(detectKind(Buffer.alloc(0)), 'empty');
assert.strictEqual(detectKind(Buffer.from([0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF])), 'unknown');
});
test('probeFileHead reads first bytes and returns hex + kind for an MP4-like file', async () => {
const mp4Head = Buffer.concat([Buffer.from([0x00, 0x00, 0x00, 0x20]), Buffer.from('ftypisom', 'ascii'), Buffer.alloc(16, 0xAA)]);
const p = tmpWrite('fake.mp4', mp4Head);
try {
const res = await probeFileHead(p, 64);
assert.strictEqual(res.ok, true);
assert.strictEqual(res.kind, 'mp4-iso');
assert.strictEqual(res.isVideoLike, true);
assert.ok(res.headHex.startsWith('0000002066747970'));
assert.strictEqual(res.bytesRead, mp4Head.length);
} finally {
fs.unlinkSync(p);
}
});
test('probeFileHead returns ok:false with kind=unreadable for missing file', async () => {
const res = await probeFileHead(path.join(os.tmpdir(), `does-not-exist-${Date.now()}.mp4`), 32);
assert.strictEqual(res.ok, false);
assert.strictEqual(res.kind, 'unreadable');
assert.ok(res.error);
});
test('summarizeFileStat returns size + mtime for a real file', () => {
const p = tmpWrite('stat.bin', Buffer.alloc(123, 0xCC));
try {
const stat = summarizeFileStat(p);
assert.strictEqual(stat.size, 123);
assert.strictEqual(stat.isFile, true);
assert.ok(stat.mtime);
} finally {
fs.unlinkSync(p);
}
});
test('summarizeFileStat returns error for missing file', () => {
const stat = summarizeFileStat(path.join(os.tmpdir(), `does-not-exist-${Date.now()}.bin`));
assert.ok(stat.error);
});
test('detectKind requires TS sync-byte periodicity — GIF and G-prefixed text are NOT mpeg-ts', () => {
const ts = Buffer.alloc(377, 0xFF);
ts[0] = 0x47; ts[188] = 0x47; ts[376] = 0x47;
assert.strictEqual(detectKind(ts), 'mpeg-ts');
assert.strictEqual(isVideoLikeKind('mpeg-ts'), true);
const gif = Buffer.concat([Buffer.from('GIF89a', 'ascii'), Buffer.alloc(400, 0x00)]);
assert.strictEqual(detectKind(gif), 'gif');
assert.strictEqual(isVideoLikeKind('gif'), false);
const gText = Buffer.concat([Buffer.from('Gewinnerliste 2026\n', 'ascii'), Buffer.alloc(400, 0x20)]);
assert.notStrictEqual(detectKind(gText), 'mpeg-ts');
assert.strictEqual(isVideoLikeKind(detectKind(gText)), false);
});