From 54604c1be19044638dd95353353fd1ccbcdd30ab Mon Sep 17 00:00:00 2001 From: relrelb Date: Mon, 1 Mar 2021 23:12:49 +0200 Subject: [PATCH] web: Prototype direct SWFs --- web/packages/extension/assets/css/player.css | 9 +++++ web/packages/extension/assets/player.html | 14 +++++++ web/packages/extension/manifest.json | 15 ++++++-- web/packages/extension/src/background.js | 39 ++++++++++++++++++++ web/packages/extension/src/player.js | 32 ++++++++++++++++ web/packages/extension/webpack.config.js | 2 + 6 files changed, 108 insertions(+), 3 deletions(-) create mode 100644 web/packages/extension/assets/css/player.css create mode 100644 web/packages/extension/assets/player.html create mode 100644 web/packages/extension/src/background.js create mode 100644 web/packages/extension/src/player.js 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/"),