diff --git a/README.md b/README.md
new file mode 100644
index 0000000..e69de29
diff --git a/src/index.php b/src/index.php
index 3c799c7..5d9dfeb 100644
--- a/src/index.php
+++ b/src/index.php
@@ -98,7 +98,7 @@ class SyncedTimer
if (($this->_basepath !== '' && strpos($_SERVER['REQUEST_URI'], $this->_basepath) === false) || $_SERVER['REQUEST_URI'] === $this->_basepath)
$this->_path = "/";
else
- $this->_path = str_replace($this->_basepath, "", $_SERVER['REQUEST_URI']);
+ $this->_path = str_replace($this->_basepath, "", parse_url($_SERVER["REQUEST_URI"], PHP_URL_PATH));
}
private function _redirect($path)
diff --git a/src/static/js/synced-timer.js b/src/static/js/synced-timer.js
index f27878f..9cc9995 100644
--- a/src/static/js/synced-timer.js
+++ b/src/static/js/synced-timer.js
@@ -1,9 +1,9 @@
-document.addEventListener('alpine:init' , () => {
+document.addEventListener('alpine:init', () => {
console.log("Synced-timer is starting")
Alpine.store("siteData", {
lastResponse: null,
- currentData: null,
+ currentData: null,
time: '00:00:00',
header: '...',
@@ -14,24 +14,24 @@ document.addEventListener('alpine:init' , () => {
init() {
Alpine.effect(() => {
const response = this.lastResponse
- if(!response) return;
-
- if(response.status !== 200) {
+ if (!response) return;
+
+ if (response.status !== 200) {
this.header = `Error: ${response.status}`
return;
}
-
+
this.currentData = response.data
Alpine.store("audioPlayback").isDisabledByServer = !this.currentData.soundEnabled
this.header = this.currentData.header
})
setInterval(() => {
- if(!this.currentData) return;
+ if (!this.currentData) return;
- const passedSeconds = parseInt(((performance.now()-this.timeOffsetToServer) / 1000) - this.currentData.startedAt);
+ const passedSeconds = parseInt(((performance.now() - this.timeOffsetToServer) / 1000) - this.currentData.startedAt);
let remaningSeconds;
- if(this.currentData.repeatEnabled) {
+ if (this.currentData.repeatEnabled) {
remaningSeconds = parseInt(this.currentData.time * 60 - (passedSeconds % (this.currentData.time * 60)));
}
else {
@@ -47,26 +47,38 @@ document.addEventListener('alpine:init' , () => {
scheduleNextRequest() {
setTimeout(() => {
let requestUrl;
- const requestId = Date.now();
- fetch(`/api/${username}#${requestId}`)
- .then((response) => {
- requestUrl = response.url
- return response.json()
- })
- .then((data) => {
- if(data && data.status === 200) {
- const performanceEntry = performance.getEntriesByName(`${requestUrl}#${requestId}`)[0];
- console.log(performanceEntry)
- const requestDuration = performanceEntry.responseEnd - performanceEntry.requestStart;
- this.timeOffsetToServer = performanceEntry.responseEnd - data.data.currentServerTime + (requestDuration / 2);
- console.log(requestDuration, "offset: ", this.timeOffsetToServer)
- }
-
- this.lastResponse = data
- this.scheduleNextRequest()
- });
+ // Add a request Id to be able to identify this request later on
+ fetch(`/api/${username}?id=${parseInt(performance.now())}`)
+ .then((response) => {
+ requestUrl = response.url
+ return response.json()
+ })
+ .then((data) => {
+ this.handleRequestFinished(data, requestUrl)
+
+ this.lastResponse = data
+ this.scheduleNextRequest()
+ });
}, 1000)
- }
+ },
+
+ handleRequestFinished(data, requestName) {
+ if (!data || data.status !== 200) return;
+
+ // identify request using its id
+ const performanceEntry = performance.getEntriesByName(requestName)[0];
+ if (!performanceEntry) {
+ // retry
+ console.warn("Could not find performance entry, discarding...")
+ return
+ }
+
+ console.log(performanceEntry)
+ const requestDuration = performanceEntry.responseEnd - performanceEntry.requestStart;
+ this.timeOffsetToServer = performanceEntry.responseEnd - data.data.currentServerTime + (requestDuration / 2);
+ console.log(requestDuration, "offset: ", this.timeOffsetToServer)
+
+ },
})
Alpine.store("audioPlayback", {
@@ -75,13 +87,19 @@ document.addEventListener('alpine:init' , () => {
isDisabledByUser: false,
isDisabledByServer: true,
audioPlayer: null,
+ replayLocked: false,
+ sounds: {
+ silence: '/static/sound/silence.mp3',
+ countdown: '/static/sound/countdown.mp3',
+ beep: '/static/sound/beep.mp3'
+ },
init() {
this.audioPlayer = new Audio('/static/sound/silence.mp3');
this.testPermission()
const audioPlaybackStore = this
-
+
Alpine.bind('audioPlaybackEnableButton', () => ({
'@click'() {
audioPlaybackStore.testPermission()
@@ -95,15 +113,19 @@ document.addEventListener('alpine:init' , () => {
}))
Alpine.effect(() => {
- if(Alpine.store("audioPlayback").isDisabledByUser) this.isAvailable = false;
+ if (Alpine.store("audioPlayback").isDisabledByUser) this.isAvailable = false;
})
},
-
+
testPermission() {
this.audioPlayer.src = '/static/sound/silence.mp3';
this.audioPlayer.play().then(() => {
this.isAvailable = true
this.hasBeenTested = true
+
+ this.preloadSound(this.sounds.beep)
+ this.preloadSound(this.sounds.countdown)
+
}).catch((error) => {
console.warn("Audio permission not granted!")
this.isAvailable = false
@@ -112,11 +134,41 @@ document.addEventListener('alpine:init' , () => {
},
playSound(soundFile) {
- if(!this.audioPlayer.paused || !this.isAvailable || this.isDisabledByUser || this.isDisabledByServer) {
+ if (!this.audioPlayer.paused || !this.isAvailable || this.isDisabledByUser || this.isDisabledByServer || this.replayLocked) {
return;
}
- this.audioPlayer.src = soundFile;
+ if (this.audioPlayer.src !== soundFile) {
+ this.audioPlayer.src = soundFile;
+ }
+ this.replayLocked = true;
this.audioPlayer.play();
+ },
+
+ preloadSound(soundFile) {
+ if (this.audioPlayer.src === soundFile) {
+ return;
+ }
+ console.log(`Preloading sound ${soundFile}`)
+ this.audioPlayer.src = soundFile;
+ this.audioPlayer.load();
+ },
+
+ playCountdown() {
+ this.playSound(this.sounds.countdown)
+ },
+ preloadCountdown() {
+ this.preloadSound(this.sounds.countdown)
+ },
+
+ playBeep() {
+ this.playSound(this.sounds.beep);
+ },
+ preloadBeep() {
+ this.preloadSound(this.sounds.beep);
+ },
+
+ unlockReplay() {
+ this.replayLocked = false;
}
})
@@ -127,9 +179,9 @@ document.addEventListener('alpine:init' , () => {
document.documentElement.requestFullscreen();
this.enabled = true
} else {
- if (document.exitFullscreen) {
- document.exitFullscreen();
- }
+ if (document.exitFullscreen) {
+ document.exitFullscreen();
+ }
}
}
})
@@ -159,7 +211,7 @@ function getTimerText(remaningSeconds) {
var remaningMinutes = zeroPad(parseInt(remaningSeconds / 60) % 60, 2)
var remaningSeconds = zeroPad(remaningSeconds % 60, 2)
- if(parseInt(remaningHours) === 0) {
+ if (parseInt(remaningHours) === 0) {
return " " + remaningMinutes + ":" + remaningSeconds + " "
}
@@ -167,10 +219,25 @@ function getTimerText(remaningSeconds) {
}
function playTimerSound(remaningSeconds) {
- if(parseInt(remaningSeconds) === 5) {
- Alpine.store("audioPlayback").playSound('/static/sound/countdown.mp3')
+ switch (parseInt(remaningSeconds)) {
+ case 65:
+ Alpine.store("audioPlayback").preloadBeep()
+ break;
+ case 60:
+ Alpine.store("audioPlayback").playBeep()
+ break;
+ case 59:
+ Alpine.store("audioPlayback").unlockReplay()
+ break;
+
+ case 10:
+ Alpine.store("audioPlayback").preloadCountdown()
+ break;
+ case 5:
+ Alpine.store("audioPlayback").playCountdown()
+ break;
+ case 4:
+ Alpine.store("audioPlayback").unlockReplay()
+ break;
}
- else if(parseInt(remaningSeconds) === 60){
- Alpine.store("audioPlayback").playSound('/static/sound/beep.mp3')
- }
}
\ No newline at end of file
diff --git a/src/theme.php b/src/theme.php
index ba93a5c..71be349 100644
--- a/src/theme.php
+++ b/src/theme.php
@@ -424,9 +424,7 @@ class LandingpageTheme
-
-
-
+