Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 13 additions & 4 deletions content.js
Original file line number Diff line number Diff line change
Expand Up @@ -2385,13 +2385,22 @@ class YTMBlockController {
console.log('[YTM Block Debug] normalized song:', normalizedInput);
console.log('[YTM Block Debug] blockedSongs array:', this.blockedSongs);

for (const blocked of this.blockedSongs) {
const normalizedBlocked = this.normalizeSongTitle(blocked);
// Cache normalized versions of blocked songs to avoid redundant normalization per iteration
if (!this._normalizedBlockedSongsCache || this._normalizedBlockedSongsSource !== this.blockedSongs) {
this._normalizedBlockedSongsSource = this.blockedSongs;
this._normalizedBlockedSongsCache = this.blockedSongs.map((blocked) => ({
raw: blocked,
normalized: this.normalizeSongTitle(blocked)
}));
}

for (const item of this._normalizedBlockedSongsCache) {
const normalizedBlocked = item.normalized;
if (normalizedInput === normalizedBlocked ||
normalizedInput.includes(normalizedBlocked) ||
normalizedBlocked.includes(normalizedInput)) {
console.log('[YTM Block Debug] shouldBlockSong result:', blocked);
return blocked;
console.log('[YTM Block Debug] shouldBlockSong result:', item.raw);
return item.raw;
}
}
console.log('[YTM Block Debug] shouldBlockSong result: null');
Expand Down
59 changes: 59 additions & 0 deletions tests/shouldBlockSong.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
const test = require('node:test');
const assert = require('node:assert');
const { performance } = require('node:perf_hooks');
const { YTMBlockController } = require('../content.js');

test('YTMBlockController - shouldBlockSong correctness', async (t) => {
const controller = new YTMBlockController();

await t.test('returns null when songTitle is empty or blockedSongs is empty', () => {
controller.blockedSongs = [];
assert.strictEqual(controller.shouldBlockSong('Some Song'), null);

controller.blockedSongs = ['Some Song'];
assert.strictEqual(controller.shouldBlockSong(''), null);
assert.strictEqual(controller.shouldBlockSong(null), null);
});

await t.test('matches exact, substring, or superstring blocked songs', () => {
controller.blockedSongs = ['Radioactive (Official Video)', 'Believer'];

// Exact match normalized
assert.strictEqual(controller.shouldBlockSong('Radioactive'), 'Radioactive (Official Video)');
assert.strictEqual(controller.shouldBlockSong('Believer'), 'Believer');

// Substring match
assert.strictEqual(controller.shouldBlockSong('Believer (Remix)'), 'Believer');

// Non-match
assert.strictEqual(controller.shouldBlockSong('Demons'), null);
});
});

test('YTMBlockController - shouldBlockSong performance benchmark', async (t) => {
const controller = new YTMBlockController();

await t.test('benchmark performance of song blocking evaluation', () => {
const blockedSongs = [];
for (let i = 0; i < 100; i++) {
blockedSongs.push(`Blocked Song Title Number ${i} (Official Audio) [Remastered 2023]`);
}
controller.blockedSongs = blockedSongs;

const testSong = 'Unblocked Song Title (Live at Wembley Stadium 2020) [Deluxe Edition]';

// Warmup JIT
for (let i = 0; i < 100; i++) {
controller.shouldBlockSong(testSong);
}

const iterations = 5000;
const start = performance.now();
for (let i = 0; i < iterations; i++) {
controller.shouldBlockSong(testSong);
}
const duration = performance.now() - start;

console.log(`[Benchmark] ${iterations} shouldBlockSong calls duration: ${duration.toFixed(2)}ms`);
});
});
Loading