diff --git a/web/packages/extension/assets/css/player.css b/web/packages/extension/assets/css/player.css
new file mode 100644
index 000000000..f4f3e31d4
--- /dev/null
+++ b/web/packages/extension/assets/css/player.css
@@ -0,0 +1,9 @@
+#player {
+ position: absolute;
+ top: 0;
+ bottom: 0;
+ left: 0;
+ right: 0;
+ width: auto;
+ height: auto;
+}
diff --git a/web/packages/extension/assets/player.html b/web/packages/extension/assets/player.html
new file mode 100644
index 000000000..ed976b746
--- /dev/null
+++ b/web/packages/extension/assets/player.html
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+ Ruffle
+
+
+
+
+
+
+
diff --git a/web/packages/extension/manifest.json b/web/packages/extension/manifest.json
index 7ad143b73..f07a989d2 100644
--- a/web/packages/extension/manifest.json
+++ b/web/packages/extension/manifest.json
@@ -10,6 +10,10 @@
"default_popup": "popup.html",
"browser_style": true
},
+ "background": {
+ "scripts": ["dist/background.js"],
+ "persistent": true
+ },
"content_scripts": [
{
"matches": [""],
@@ -18,7 +22,7 @@
"run_at": "document_start"
}
],
- "content_security_policy": "default-src 'self'; script-src 'self' 'unsafe-eval'; style-src 'unsafe-inline';",
+ "content_security_policy": "default-src 'self'; script-src 'self' 'unsafe-eval'; style-src 'unsafe-inline'; connect-src *;",
"icons": {
"16": "images/icon16.png",
"32": "images/icon32.png",
@@ -30,6 +34,11 @@
"page": "options.html",
"open_in_tab": true
},
- "permissions": ["storage"],
- "web_accessible_resources": ["dist/*"]
+ "permissions": [
+ "storage",
+ "",
+ "webRequest",
+ "webRequestBlocking"
+ ],
+ "web_accessible_resources": ["*"]
}
diff --git a/web/packages/extension/src/background.js b/web/packages/extension/src/background.js
new file mode 100644
index 000000000..945614af1
--- /dev/null
+++ b/web/packages/extension/src/background.js
@@ -0,0 +1,39 @@
+function isSwf(details) {
+ const typeHeader = details.responseHeaders.find(({name}) => name.toLowerCase() === "content-type");
+ if (!typeHeader) {
+ return false;
+ }
+
+ const mime = typeHeader.value.toLowerCase().match(/^\s*(.*?)\s*(?:;.*)?$/)[1];
+
+ // Some sites (e.g. swfchan.net) might (wrongly?) send octet-stream, so check file extension too.
+ if (mime === "application/octet-stream") {
+ const url = new URL(details.url);
+ const extension = url.pathname.substring(url.pathname.lastIndexOf("."));
+ return extension.toLowerCase() === ".swf";
+ }
+
+ return mime === "application/x-shockwave-flash";
+}
+
+function onHeadersReceived(details) {
+ if (!isSwf(details)) {
+ return;
+ }
+
+ const baseUrl = chrome.runtime.getURL("player.html");
+ return { redirectUrl: `${baseUrl}?url=${details.url}` };
+}
+
+// TODO: Support Firefox.
+// TODO: Only if configured.
+chrome.webRequest.onHeadersReceived.addListener(
+ onHeadersReceived,
+ {
+ urls: [""],
+ types: ["main_frame"],
+ },
+ ["blocking", "responseHeaders"]
+);
+
+// TODO: chrome.webRequest.onHeadersReceived.removeListener(onHeadersReceived);
diff --git a/web/packages/extension/src/player.js b/web/packages/extension/src/player.js
new file mode 100644
index 000000000..fc02cee28
--- /dev/null
+++ b/web/packages/extension/src/player.js
@@ -0,0 +1,32 @@
+import { PublicAPI, SourceAPI, publicPath } from "ruffle-core";
+
+let ruffle;
+let player;
+
+// Default config used by the player.
+const config = {
+ letterbox: "on",
+ logLevel: "warn",
+};
+
+window.RufflePlayer = PublicAPI.negotiate(
+ window.RufflePlayer,
+ "local",
+ new SourceAPI("local")
+);
+__webpack_public_path__ = publicPath(window.RufflePlayer.config, "local");
+
+window.addEventListener("DOMContentLoaded", () => {
+ const url = new URL(window.location);
+ const swfUrl = url.searchParams.get("url");
+ if (!swfUrl) {
+ return;
+ }
+
+ ruffle = window.RufflePlayer.newest();
+ player = ruffle.createPlayer();
+ player.id = "player";
+ document.getElementById("main").append(player);
+
+ player.load({ url: swfUrl, ...config });
+});
diff --git a/web/packages/extension/webpack.config.js b/web/packages/extension/webpack.config.js
index b203d28f2..3e4a03336 100644
--- a/web/packages/extension/webpack.config.js
+++ b/web/packages/extension/webpack.config.js
@@ -18,6 +18,8 @@ module.exports = (env, argv) => {
options: path.resolve(__dirname, "src/options.js"),
content: path.resolve(__dirname, "src/content.js"),
ruffle: path.resolve(__dirname, "src/ruffle.js"),
+ background: path.resolve(__dirname, "src/background.js"),
+ player: path.resolve(__dirname, "src/player.js"),
},
output: {
path: path.resolve(__dirname, "assets/dist/"),