Browse Source

Workaround for audio from 'file:' URLs.

master
Gerben 4 years ago
parent
commit
21967a2e47
2 changed files with 52 additions and 23 deletions
  1. +51
    -23
      app/audio-player/background.js
  2. +1
    -0
      app/manifest.json

+ 51
- 23
app/audio-player/background.js View File

@@ -3,8 +3,7 @@ import delay from 'delay';
async function tryUntilItWorks(func, delayBetweenTries = 1, maxTries = 10) {
for (let i = 0; i < maxTries; i++) {
try {
await func();
return;
return await func();
} catch (err) {
await delay(delayBetweenTries);
continue;
@@ -12,33 +11,38 @@ async function tryUntilItWorks(func, delayBetweenTries = 1, maxTries = 10) {
}
}

async function insertOurAudioPlayer(tabId) {
// 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/waveform-playlist.css',
}));

await tryUntilItWorks(() => browser.tabs.insertCSS(tabId, {
runAt: 'document_end',
file: '/assets/main.css',
}));
}

// Load the player on any file with an audio/* mime type.
async function onHeadersReceived({ responseHeaders, url, tabId }) {
const isAudio = responseHeaders.some(header =>
header.name.toLowerCase() === 'content-type' && header.value.toLowerCase().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/waveform-playlist.css',
}));

await tryUntilItWorks(() => browser.tabs.insertCSS(tabId, {
runAt: 'document_end',
file: '/assets/main.css',
}));
insertOurAudioPlayer(tabId);
}
}

@@ -50,3 +54,27 @@ browser.webRequest.onHeadersReceived.addListener(
},
['responseHeaders'],
);

// As files loaded through file://… URLs do not have headers, we run a separate check for these.
async function onVisitFileUrl({ url, tabId }) {
// I don’t know how we could neatly test whether the file is an audio file. This expression is a
// pragmatic solution working for (at least) the current versions of Firefox and Chromium.
const isAudioPlayerExpression =
`document.body.childElementCount === 1
&& document.body.firstElementChild instanceof HTMLVideoElement
&& document.body.firstElementChild.videoHeight === 0
&& document.body.firstElementChild.videoWidth === 0
`;
const [isAudio] = await tryUntilItWorks(() => browser.tabs.executeScript(tabId, {
code: isAudioPlayerExpression,
runAt: 'document_idle', // (at document_end it’s not clear yet whether it’s audio or video..)
}));
if (isAudio) {
insertOurAudioPlayer(tabId);
}
}

browser.webNavigation.onCommitted.addListener(
onVisitFileUrl,
{ url: [{ schemes: ['file'] }] },
);

+ 1
- 0
app/manifest.json View File

@@ -13,6 +13,7 @@
"clipboardWrite",
"bookmarks",
"tabs",
"webNavigation",
"webRequest"
]
}

Loading…
Cancel
Save