mirror of
https://github.com/Shik3i/KoalaSync.git
synced 2026-08-13 04:57:07 +00:00
feat:local-blacklist-and-audio-boost
This commit is contained in:
@@ -8,6 +8,8 @@ import { fileURLToPath } from 'node:url';
|
||||
|
||||
const repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
|
||||
const sourcePath = path.join(repoRoot, 'extension/audio-options.js');
|
||||
const contentPath = path.join(repoRoot, 'extension/content.js');
|
||||
const htmlPath = path.join(repoRoot, 'extension/audio-options.html');
|
||||
const source = fs.readFileSync(sourcePath, 'utf8')
|
||||
.replace("import { loadLocale, translateDOM, getSystemLanguage } from './i18n.js';", '')
|
||||
.replace(/init\(\)\.catch[\s\S]*?;\n?$/, '');
|
||||
@@ -61,7 +63,11 @@ const sandbox = {
|
||||
},
|
||||
document: {
|
||||
getElementById: () => makeInput(),
|
||||
querySelectorAll: (selector) => selector === '.control-row' ? rows : [makeInput({ value: 'recommended' })]
|
||||
querySelectorAll: (selector) => selector === '.control-row[data-param]' ? rows : [makeInput({ value: 'recommended' })]
|
||||
},
|
||||
window: {
|
||||
addEventListener: () => {},
|
||||
close: () => {}
|
||||
},
|
||||
setTimeout,
|
||||
clearTimeout
|
||||
@@ -71,7 +77,9 @@ vm.createContext(sandbox);
|
||||
vm.runInContext(`${source}
|
||||
globalThis.__audioSettingsTest = {
|
||||
mergeAudioSettings,
|
||||
normalizeBoostDb,
|
||||
getParamValue,
|
||||
setBoostDb,
|
||||
setCustomParam,
|
||||
get currentSettings() { return currentSettings; }
|
||||
};`, sandbox, { filename: sourcePath });
|
||||
@@ -80,6 +88,11 @@ const helpers = sandbox.__audioSettingsTest;
|
||||
|
||||
assert.doesNotThrow(() => helpers.mergeAudioSettings(null), 'mergeAudioSettings tolerates null storage values');
|
||||
assert.doesNotThrow(() => helpers.mergeAudioSettings('bad'), 'mergeAudioSettings tolerates non-object storage values');
|
||||
assert.equal(helpers.normalizeBoostDb(-5), 0, 'boost clamps to 0 dB minimum');
|
||||
assert.equal(helpers.normalizeBoostDb(99), 20, 'boost clamps to 20 dB maximum');
|
||||
assert.equal(helpers.normalizeBoostDb(7.26), 7.5, 'boost rounds to half-decibel steps');
|
||||
assert.equal(helpers.normalizeBoostDb('bad'), 0, 'invalid boost falls back to 0 dB');
|
||||
assert.equal(helpers.mergeAudioSettings({ boostDb: 8 }).boostDb, 8, 'boost persists independently of compressor');
|
||||
|
||||
assert.equal(helpers.getParamValue('threshold', '-999'), -60, 'threshold clamps to minimum');
|
||||
assert.equal(helpers.getParamValue('threshold', '999'), 0, 'threshold clamps to maximum');
|
||||
@@ -95,4 +108,24 @@ assert.equal(helpers.getParamValue('release', '5000', true), 1, 'release ms inpu
|
||||
helpers.setCustomParam('threshold', 999);
|
||||
assert.equal(helpers.currentSettings.compressor.customParams.threshold, 0, 'setCustomParam stores clamped values');
|
||||
|
||||
helpers.setBoostDb(6);
|
||||
assert.equal(helpers.currentSettings.boostDb, 6, 'setBoostDb stores the normalized boost');
|
||||
assert.equal(helpers.currentSettings.enabled, true, 'positive boost enables audio processing');
|
||||
helpers.setBoostDb(0);
|
||||
assert.equal(helpers.currentSettings.enabled, false, 'zero boost disables processing when compressor is off');
|
||||
|
||||
const contentSource = fs.readFileSync(contentPath, 'utf8');
|
||||
assert.match(contentSource, /const outputGain = ctx\.createGain\(\)/, 'content chain creates a shared output gain');
|
||||
assert.match(contentSource, /const limiter = ctx\.createDynamicsCompressor\(\)/, 'content chain creates a post-boost limiter');
|
||||
assert.match(contentSource, /outputGain\.connect\(limiter\)/, 'boost output feeds the limiter');
|
||||
assert.match(contentSource, /limiter\.connect\(ctx\.destination\)/, 'limiter feeds the audio destination');
|
||||
assert.match(contentSource, /chain\.limiter\.threshold\.setValueAtTime\(0, t\)/, 'audio bypass resets the limiter ceiling');
|
||||
assert.match(contentSource, /Math\.pow\(10, boostDb \/ 20\)/, 'content chain converts decibels to linear gain');
|
||||
assert.match(contentSource, /changes\.audioSettings\.newValue/, 'content updates active video when local audio settings change');
|
||||
assert.match(source, /querySelectorAll\('\.control-row\[data-param\]'\)/, 'boost row is excluded from compressor parameter handling');
|
||||
assert.match(source, /await flushPendingSave\(\);[\s\S]*?window\.close\(\)/, 'back navigation flushes the final audio setting');
|
||||
|
||||
const htmlSource = fs.readFileSync(htmlPath, 'utf8');
|
||||
assert.match(htmlSource, /id="boostRange"[^>]+max="20"[^>]+step="0\.5"/, 'audio UI exposes a bounded half-decibel boost slider');
|
||||
|
||||
console.log('audio settings tests passed');
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
import assert from 'node:assert/strict';
|
||||
import fs from 'node:fs';
|
||||
import path from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import {
|
||||
BLACKLIST_DOMAINS,
|
||||
CUSTOM_BLACKLIST_STORAGE_KEY,
|
||||
getEffectiveBlacklistDomains,
|
||||
isUrlBlacklisted,
|
||||
normalizeBlacklistDomain,
|
||||
parseBlacklistDomains
|
||||
} from '../shared/blacklist.js';
|
||||
|
||||
const repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
|
||||
|
||||
assert.equal(CUSTOM_BLACKLIST_STORAGE_KEY, 'customBlacklistDomains');
|
||||
assert.equal(normalizeBlacklistDomain(' Example.COM. '), 'example.com');
|
||||
assert.equal(normalizeBlacklistDomain('https://Video.Example.com/watch/123'), 'video.example.com');
|
||||
assert.equal(normalizeBlacklistDomain('*.example.com'), null, 'wildcards are rejected');
|
||||
assert.equal(normalizeBlacklistDomain('not a domain'), null, 'spaces are rejected');
|
||||
|
||||
const parsed = parseBlacklistDomains('Example.com\nhttps://sub.example.com/path\nexample.com\n');
|
||||
assert.deepEqual(parsed.domains, ['example.com', 'sub.example.com'], 'domains are normalized and deduplicated');
|
||||
assert.deepEqual(parsed.invalid, []);
|
||||
|
||||
const invalid = parseBlacklistDomains('example.com\nnot a domain');
|
||||
assert.deepEqual(invalid.invalid, ['not a domain'], 'invalid entries are reported without partial silent saves');
|
||||
|
||||
assert.deepEqual(getEffectiveBlacklistDomains(undefined), BLACKLIST_DOMAINS, 'missing local setting uses shipped defaults');
|
||||
assert.deepEqual(getEffectiveBlacklistDomains([]), [], 'an explicitly empty local list stays empty');
|
||||
assert.equal(isUrlBlacklisted('https://mail.google.com/inbox', ['google.com']), true, 'subdomains match a parent domain');
|
||||
assert.equal(isUrlBlacklisted('https://notgoogle.com/', ['google.com']), false, 'lookalike domains do not match');
|
||||
assert.equal(isUrlBlacklisted('not a url', ['example.com']), false, 'invalid URLs are ignored');
|
||||
|
||||
const popupSource = fs.readFileSync(path.join(repoRoot, 'extension/popup.js'), 'utf8');
|
||||
assert.match(popupSource, /chrome\.storage\.local\.set\(\{ \[CUSTOM_BLACKLIST_STORAGE_KEY\]: domains \}\)/, 'custom list is saved locally');
|
||||
assert.doesNotMatch(popupSource, /chrome\.storage\.sync\.set\(\{ \[CUSTOM_BLACKLIST_STORAGE_KEY\]/, 'custom list is never synced');
|
||||
assert.match(popupSource, /isUrlBlacklisted\(tab\.url, blacklistDomains\)/, 'tab filtering uses the effective custom list');
|
||||
|
||||
const popupHtml = fs.readFileSync(path.join(repoRoot, 'extension/popup.html'), 'utf8');
|
||||
assert.match(popupHtml, /id="blacklistDomains"/, 'settings UI contains the editable domain list');
|
||||
assert.match(popupHtml, /id="blacklistReset"/, 'settings UI contains a defaults reset');
|
||||
|
||||
console.log('blacklist settings tests passed');
|
||||
@@ -19,6 +19,7 @@ const checks = [
|
||||
['names generator', 'node', ['scripts/test-names.mjs']],
|
||||
['content video finder', 'node', ['scripts/test-content-video-finder.cjs']],
|
||||
['audio settings', 'node', ['scripts/test-audio-settings.mjs']],
|
||||
['blacklist settings', 'node', ['scripts/test-blacklist-settings.mjs']],
|
||||
['popup refresh cooldown', 'node', ['scripts/test-popup-refresh-cooldown.mjs']],
|
||||
['chat settings', 'node', ['scripts/test-chat-settings.mjs']],
|
||||
['host access recovery', 'node', ['scripts/test-host-access.mjs']],
|
||||
|
||||
Reference in New Issue
Block a user