diff --git a/config.yaml b/config.yaml
index d70988db..8084753d 100644
--- a/config.yaml
+++ b/config.yaml
@@ -40,3 +40,7 @@ redirect_to_exact: true
# locales:
# - en
# - ru
+
+# Uncomment to inject extra scripts into replayed pages (place scripts under static/ or your alternate static_dir location)
+# inject_scripts:
+# - ruffle/ruffle.js
diff --git a/docs/manual/configuring.rst b/docs/manual/configuring.rst
index ff8bf32b..3680a19f 100644
--- a/docs/manual/configuring.rst
+++ b/docs/manual/configuring.rst
@@ -655,3 +655,30 @@ By default, SSL-Certificates of websites are not verified. To enable verificatio
``ca_cert_dir`` can optionally point to a directory containing the CA certificates that you trust. Most linux distributions provide CA certificates via a package called ``ca-certificates``.
If omitted, the default system CA used by Python is used.
+
+Injecting Scripts
+-----------------
+
+Extra JavaScript files can be injected into replayed pages. This can be useful for emulating removed browser features
+or applying compatibility tweaks.
+
+For example, to emulate Flash Player using `Ruffle `_, create a subdirectory named ``static/ruffle``
+and unzip the `Ruffle self-hosted package `_ into it. Then add the following
+configuration::
+
+ inject_scripts:
+ - ruffle/ruffle.js
+
+Note: Paths listed under ``inject_scripts`` are relative to the ``static_dir`` directory (default ``static/``).
+
+Injected scripts can also be configured per collection::
+
+ inject_scripts:
+ - all.js
+ - other.js
+
+ collections:
+ mycoll:
+ inject_scripts:
+ - all.js # static/all.js
+ - _/mycoll/tweaks.js # collections/mycoll/static/tweaks.js
\ No newline at end of file
diff --git a/pywb/apps/rewriterapp.py b/pywb/apps/rewriterapp.py
index cae36ed7..dab7d3f4 100644
--- a/pywb/apps/rewriterapp.py
+++ b/pywb/apps/rewriterapp.py
@@ -536,7 +536,8 @@ def render_content(self, wb_url, kwargs, environ):
replay_mod=self.replay_mod,
metadata=kwargs.get('metadata', {}),
ui=kwargs.get('ui', {}),
- config=self.config))
+ config=self.config,
+ inject_scripts=self.get_inject_scripts(kwargs)))
cookie_rewriter = None
if self.cookie_tracker and cookie_key:
@@ -926,6 +927,14 @@ def get_top_frame_params(self, wb_url, kwargs):
'ui': kwargs.get('ui', {})
}
+ def get_inject_scripts(self, kwargs):
+ coll = kwargs.get('coll')
+ coll_config = self.config.get('collections', {}).get(coll, {})
+ # ignore special collections like live or all
+ if isinstance(coll_config, str):
+ coll_config = {}
+ return coll_config.get('inject_scripts', self.config.get('inject_scripts', []))
+
def handle_custom_response(self, environ, wb_url, full_prefix, host_prefix, kwargs):
if self.is_framed_replay(wb_url):
extra_params = self.get_top_frame_params(wb_url, kwargs)
@@ -936,6 +945,7 @@ def handle_custom_response(self, environ, wb_url, full_prefix, host_prefix, kwar
self.frame_mod,
self.replay_mod,
self.client_side_replay,
+ self.get_inject_scripts(kwargs),
coll=kwargs.get("coll"),
extra_params=extra_params)
diff --git a/pywb/rewrite/templateview.py b/pywb/rewrite/templateview.py
index d21b3f29..4becd880 100644
--- a/pywb/rewrite/templateview.py
+++ b/pywb/rewrite/templateview.py
@@ -389,6 +389,7 @@ def get_top_frame(self, wb_url,
frame_mod,
replay_mod,
client_side_replay,
+ inject_scripts,
coll='',
extra_params=None):
"""
@@ -429,7 +430,8 @@ def get_top_frame(self, wb_url,
'timestamp': timestamp,
'url': wb_url.get_url(),
- 'sw_prefix': env.get('pywb.app_prefix', '')
+ 'sw_prefix': env.get('pywb.app_prefix', ''),
+ 'inject_scripts': inject_scripts,
}
if extra_params:
diff --git a/pywb/static/loadWabac.js b/pywb/static/loadWabac.js
index 94b2330f..c48f5fb4 100644
--- a/pywb/static/loadWabac.js
+++ b/pywb/static/loadWabac.js
@@ -1,6 +1,6 @@
class WabacReplay
{
- constructor(prefix, url, ts, staticPrefix, coll, swScopePrefix) {
+ constructor(prefix, url, ts, staticPrefix, coll, swScopePrefix, injectScripts) {
this.prefix = prefix;
this.url = url;
this.ts = ts;
@@ -8,6 +8,7 @@ class WabacReplay
this.collName = coll;
this.isRoot = coll === "$root";
this.swScope = swScopePrefix;
+ this.injectScripts = injectScripts;
this.adblockUrl = undefined;
this.queryParams = {"replayPrefix": ""};
@@ -54,6 +55,7 @@ class WabacReplay
archiveMod: "ir_",
adblockUrl: this.adblockUrl,
noPostToGet: true,
+ injectScripts: this.injectScripts.map(src => "../" + src),
},
};
diff --git a/pywb/templates/frame_insert.html b/pywb/templates/frame_insert.html
index f0d2a393..3e75d9f3 100644
--- a/pywb/templates/frame_insert.html
+++ b/pywb/templates/frame_insert.html
@@ -55,7 +55,7 @@
if (navigator.serviceWorker) {
{% if client_side_replay %}
- window.cframe = new WabacReplay("{{ wb_prefix }}", "{{ url }}", "{{ timestamp }}", "{{ static_prefix }}", "{{ coll }}", "{{ sw_prefix }}");
+ window.cframe = new WabacReplay("{{ wb_prefix }}", "{{ url }}", "{{ timestamp }}", "{{ static_prefix }}", "{{ coll }}", "{{ sw_prefix }}", {{ inject_scripts | tojson }});
window.cframe.init();
{% else %}
navigator.serviceWorker.getRegistration("{{ sw_prefix }}").then(reg => { if (reg) reg.unregister() });
diff --git a/pywb/templates/head_insert.html b/pywb/templates/head_insert.html
index 460b1c8e..11cf0f1e 100644
--- a/pywb/templates/head_insert.html
+++ b/pywb/templates/head_insert.html
@@ -54,6 +54,10 @@
{% endif %}
+{% for script in inject_scripts %}
+
+{% endfor %}
+
{% if config.enable_flash_video_rewrite or config.transclusions_version == 1 %}
diff --git a/tests/config_test.yaml b/tests/config_test.yaml
index 5671069d..5ce2328e 100644
--- a/tests/config_test.yaml
+++ b/tests/config_test.yaml
@@ -41,3 +41,6 @@ enable_memento: true
# enable new transclusion system
transclusions_version: 2
+
+inject_scripts:
+ - inject.js
diff --git a/tests/test_integration.py b/tests/test_integration.py
index e131ab3c..fd0c3ff9 100644
--- a/tests/test_integration.py
+++ b/tests/test_integration.py
@@ -118,6 +118,7 @@ def test_replay_content(self, fmod):
assert '"20140127171238"' in resp.text, resp.text
assert 'wombat.js' in resp.text
assert 'transclusions.js' in resp.text
+ assert 'inject.js' in resp.text
assert '_WBWombatInit' in resp.text, resp.text
assert 'wbinfo.enable_auto_fetch = false;' in resp.text
assert '/pywb/20140127171238{0}/http://www.iana.org/time-zones"'.format(fmod) in resp.text