@@ -0,0 +1,52 @@ | |||
import delay from 'delay'; | |||
async function tryUntilItWorks(func, delayBetweenTries = 1, maxTries = 10) { | |||
for (let i = 0; i < maxTries; i++) { | |||
try { | |||
await func(); | |||
return; | |||
} catch (err) { | |||
await delay(delayBetweenTries); | |||
continue; | |||
} | |||
} | |||
} | |||
async function onHeadersReceived({ responseHeaders, url, tabId }) { | |||
const isAudio = responseHeaders.some(header => | |||
header.name === 'Content-Type' && header.value.startsWith('audio/') | |||
); | |||
if (isAudio) { | |||
// Avoid any short glitch of sound (observed in Firefox) before our injected script executes. | |||
await browser.tabs.update(tabId, { muted: true }); | |||
// Too quickly executing the script may fail (bug in Firefox), so we retry if necessary. | |||
await tryUntilItWorks(() => browser.tabs.executeScript(tabId, { | |||
runAt: 'document_end', | |||
file: '/scripts/contentscript.js', | |||
})); | |||
// Unmute again. | |||
await browser.tabs.update(tabId, { muted: false }); | |||
await tryUntilItWorks(() => browser.tabs.insertCSS(tabId, { | |||
runAt: 'document_end', | |||
file: '/assets/main.css', | |||
})); | |||
await tryUntilItWorks(() => browser.tabs.insertCSS(tabId, { | |||
runAt: 'document_end', | |||
file: '/assets/waveform-playlist.css', | |||
})); | |||
} | |||
} | |||
browser.webRequest.onHeadersReceived.addListener( | |||
onHeadersReceived, | |||
{ | |||
urls: ['<all_urls>'], | |||
types: ['main_frame'], | |||
}, | |||
['responseHeaders'], | |||
); |
@@ -0,0 +1,88 @@ | |||
import * as WaveformPlaylist from 'waveform-playlist'; | |||
import delay from 'delay'; | |||
async function init() { | |||
document.body.innerHTML = ` | |||
<main> | |||
<div id="controls"> | |||
<button id="playpause">⏯</button> | |||
<div> | |||
<label for="volume" id="volume-label">🔊</label> | |||
<input type="range" min="0" max="100" value="100" id="volume" /> | |||
</div> | |||
</div> | |||
<div id="container"> | |||
</div> | |||
</main> | |||
`; | |||
const playlist = WaveformPlaylist.init({ | |||
container: document.getElementById('container'), | |||
timescale: true, | |||
waveHeight: 100, | |||
state: 'select', | |||
}); | |||
const eventEmitter = playlist.getEventEmitter(); | |||
// Hook up play/pause and volume inputs | |||
const playpauseEl = document.getElementById('playpause'); | |||
const volumeEl = document.getElementById('volume'); | |||
playpauseEl.addEventListener('click', | |||
e => eventEmitter.emit(playlist.isPlaying() ? 'pause' : 'play') | |||
); | |||
volumeEl.addEventListener('input', | |||
e => eventEmitter.emit("mastervolumechange", e.target.value) | |||
); | |||
// Read target fragment from URL | |||
let start, end; | |||
async function setFragmentToSelection() { | |||
const fragmentIdentifier = window.location.hash; | |||
if (fragmentIdentifier) { | |||
const match = fragmentIdentifier.match(/#t=(\d+(?:\.\d+)?)?(?:,(\d+(?:\.\d+)?))?/); | |||
if (match) { | |||
if (match[1] !== undefined) { | |||
start = Number.parseFloat(match[1]); | |||
} | |||
if (match[2] !== undefined) { | |||
end = Number.parseFloat(match[2]); | |||
} | |||
} | |||
} | |||
// Emit event to update selection in player | |||
eventEmitter.emit('select', start, end); | |||
} | |||
// Bind window hash change to update player | |||
window.addEventListener('hashchange', async function() { | |||
if(playlist.isPlaying()) { | |||
eventEmitter.emit('stop') | |||
// pause needs a small delay, coz the lib doesn't | |||
// update player view (drawRequest) when isPlaying() = true. | |||
await delay(10); | |||
} | |||
await setFragmentToSelection(); | |||
eventEmitter.emit('play'); | |||
}); | |||
// Load Playlist | |||
await playlist.load([{ | |||
src: document.URL | |||
}]); | |||
// update start & end for initial load | |||
setFragmentToSelection(); | |||
// Start playing. A tiny delay seems needed in Firefox to show the cursor at the right place. | |||
requestAnimationFrame(() => eventEmitter.emit('play')); | |||
} | |||
init(); |
@@ -1,52 +1 @@ | |||
import delay from 'delay'; | |||
async function tryUntilItWorks(func, delayBetweenTries = 1, maxTries = 10) { | |||
for (let i = 0; i < maxTries; i++) { | |||
try { | |||
await func(); | |||
return; | |||
} catch (err) { | |||
await delay(delayBetweenTries); | |||
continue; | |||
} | |||
} | |||
} | |||
async function onHeadersReceived({ responseHeaders, url, tabId }) { | |||
const isAudio = responseHeaders.some(header => | |||
header.name === 'Content-Type' && header.value.startsWith('audio/') | |||
); | |||
if (isAudio) { | |||
// Avoid any short glitch of sound (observed in Firefox) before our injected script executes. | |||
await browser.tabs.update(tabId, { muted: true }); | |||
// Too quickly executing the script may fail (bug in Firefox), so we retry if necessary. | |||
await tryUntilItWorks(() => browser.tabs.executeScript(tabId, { | |||
runAt: 'document_end', | |||
file: '/scripts/contentscript.js', | |||
})); | |||
// Unmute again. | |||
await browser.tabs.update(tabId, { muted: false }); | |||
await tryUntilItWorks(() => browser.tabs.insertCSS(tabId, { | |||
runAt: 'document_end', | |||
file: '/assets/main.css', | |||
})); | |||
await tryUntilItWorks(() => browser.tabs.insertCSS(tabId, { | |||
runAt: 'document_end', | |||
file: '/assets/waveform-playlist.css', | |||
})); | |||
} | |||
} | |||
browser.webRequest.onHeadersReceived.addListener( | |||
onHeadersReceived, | |||
{ | |||
urls: ['<all_urls>'], | |||
types: ['main_frame'], | |||
}, | |||
['responseHeaders'], | |||
); | |||
import '../audio-player/background.js' |
@@ -1,88 +1 @@ | |||
import * as WaveformPlaylist from 'waveform-playlist'; | |||
import delay from 'delay'; | |||
async function init() { | |||
document.body.innerHTML = ` | |||
<main> | |||
<div id="controls"> | |||
<button id="playpause">⏯</button> | |||
<div> | |||
<label for="volume" id="volume-label">🔊</label> | |||
<input type="range" min="0" max="100" value="100" id="volume" /> | |||
</div> | |||
</div> | |||
<div id="container"> | |||
</div> | |||
</main> | |||
`; | |||
const playlist = WaveformPlaylist.init({ | |||
container: document.getElementById('container'), | |||
timescale: true, | |||
waveHeight: 100, | |||
state: 'select', | |||
}); | |||
const eventEmitter = playlist.getEventEmitter(); | |||
// Hook up play/pause and volume inputs | |||
const playpauseEl = document.getElementById('playpause'); | |||
const volumeEl = document.getElementById('volume'); | |||
playpauseEl.addEventListener('click', | |||
e => eventEmitter.emit(playlist.isPlaying() ? 'pause' : 'play') | |||
); | |||
volumeEl.addEventListener('input', | |||
e => eventEmitter.emit("mastervolumechange", e.target.value) | |||
); | |||
// Read target fragment from URL | |||
let start, end; | |||
async function setFragmentToSelection() { | |||
const fragmentIdentifier = window.location.hash; | |||
if (fragmentIdentifier) { | |||
const match = fragmentIdentifier.match(/#t=(\d+(?:\.\d+)?)?(?:,(\d+(?:\.\d+)?))?/); | |||
if (match) { | |||
if (match[1] !== undefined) { | |||
start = Number.parseFloat(match[1]); | |||
} | |||
if (match[2] !== undefined) { | |||
end = Number.parseFloat(match[2]); | |||
} | |||
} | |||
} | |||
// Emit event to update selection in player | |||
eventEmitter.emit('select', start, end); | |||
} | |||
// Bind window hash change to update player | |||
window.addEventListener('hashchange', async function() { | |||
if(playlist.isPlaying()) { | |||
eventEmitter.emit('stop') | |||
// pause needs a small delay, coz the lib doesn't | |||
// update player view (drawRequest) when isPlaying() = true. | |||
await delay(10); | |||
} | |||
await setFragmentToSelection(); | |||
eventEmitter.emit('play'); | |||
}); | |||
// Load Playlist | |||
await playlist.load([{ | |||
src: document.URL | |||
}]); | |||
// update start & end for initial load | |||
setFragmentToSelection(); | |||
// Start playing. A tiny delay seems needed in Firefox to show the cursor at the right place. | |||
requestAnimationFrame(() => eventEmitter.emit('play')); | |||
} | |||
init(); | |||
import '../audio-player/contentscript.js' |