PageSourceSearch

https://guess.fr/SoundPlayer.js

js guess.fr collected 2026-09-24 12:48:56 UTC 2,650 bytes, 97 lines download raw bytes

1class SoundPlayer {
2	constructor({ soundsApiUrl = '/api/sounds', soundsBaseUrl = '/sounds', delayMs = 2000 } = {}) {
3		this.soundsApiUrl = soundsApiUrl;
4		this.soundsBaseUrl = soundsBaseUrl;
5		this.delayMs = delayMs;
6		this.queue = [];
7		this.audio = null;
8		this.stopped = false;
9		this.timeout        = null;     // ← ADD THIS
10
11	}
12
13	// Fisher-Yates shuffle
14	_shuffle(array) {
15		const arr = [...array];
16		for (let i = arr.length - 1; i > 0; i--) {
17			const j = Math.floor(Math.random() * (i + 1));
18			[arr[i], arr[j]] = [arr[j], arr[i]];
19		}
20		return arr;
21	}
22
23	async _fetchQueue() {
24		const response = await fetch(this.soundsApiUrl);
25		if (!response.ok) throw new Error('Failed to fetch sound list');
26		const files = await response.json();
27		if (!files.length) throw new Error('No sound files found');
28		this.queue = this._shuffle(files); // randomized on each page visit
29	}
30
31	_playNext() {
32		if (this.stopped || this.queue.length === 0) return;
33
34		const file = this.queue.shift(); // remove from queue as we go
35		const url = `${this.soundsBaseUrl}/${file}`;
36
37		console.log(`[SoundPlayer] Playing: ${file} (${this.queue.length} remaining)`);
38
39		this.audio = new Audio(url);
40
41		this.audio.addEventListener('ended', () => {
42			if (this.queue.length === 0) {
43				console.log('[SoundPlayer] All sounds played.');
44				return;
45			}
46			setTimeout(() => this._playNext(), this.delayMs);
47		});
48
49		this.audio.addEventListener('error', (e) => {
50			console.warn(`[SoundPlayer] Error playing ${file}:`, e);
51			setTimeout(() => this._playNext(), this.delayMs); // skip broken file
52		});
53
54		this.audio.play().catch(err => {
55			// Autoplay was blocked by the browser — wait for user interaction
56			console.warn('[SoundPlayer] Autoplay blocked. Waiting for user gesture...');
57			const resume = () => {
58				this.audio.play();
59				document.removeEventListener('click', resume);
60				document.removeEventListener('keydown', resume);
61			};
62			document.addEventListener('click', resume, { once: true });
63			document.addEventListener('keydown', resume, { once: true });
64		});
65	}
66
67	async start() {
68		this.stopped = false;
69		await this._fetchQueue();
70		this._playNext();
71	}
72
73	stop() {
74		this.stopped = true;
75		clearTimeout(this.timeout);
76		if (this.audio) {
77			this.audio.pause();
78			this.audio.src = '';
79		}
80		$('#mindful-soundholder').remove()
81	}
82
83	toggle() {
84		if (this.stopped || (this.audio && this.audio.paused)) {
85			this.stopped = false;
86			if (this.audio) {
87				this.audio.play()
88			} else {
89				this._playNext()   // no audio yet, start fresh
90			}
91		} else {
92			this.stopped = true;
93			clearTimeout(this.timeout);
94			if (this.audio) this.audio.pause();
95		}
96	}
97}

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.