aboutsummaryrefslogtreecommitdiff
path: root/content
diff options
context:
space:
mode:
authorjahoti <jahoti@tilde.team>2021-08-15 00:00:00 +0000
committerjahoti <jahoti@tilde.team>2021-08-15 00:00:00 +0000
commitd104aaf3ebcddfbda495bdfe3ba3a905f75b936f (patch)
treef617204baeb4919cd1bad2cf3e302acf3ef7116f /content
parent428c474c4c71ef4c7961070d4246017d15aa0c0c (diff)
downloadhydrilla-fixes-bundle-d104aaf3ebcddfbda495bdfe3ba3a905f75b936f.tar.gz
hydrilla-fixes-bundle-d104aaf3ebcddfbda495bdfe3ba3a905f75b936f.zip
Port existing fixes from hachette_fixes_tmp to Hydrilla format
Diffstat (limited to 'content')
-rw-r--r--content/babc_aus/index.json8
-rw-r--r--content/bstallman.org/index.json8
-rw-r--r--content/pabc.net.au./index.json5
-rw-r--r--content/pabc_aus/index.json5
-rw-r--r--content/paccuweather/index.json5
-rw-r--r--content/paskubuntu.com/index.json5
-rw-r--r--content/pbandcamp/index.json5
-rw-r--r--content/pcentrum24_santander_3d-secure/index.json5
-rw-r--r--content/pgoogle_sheets/index.json5
-rw-r--r--content/pinternet_archive/index.json5
-rw-r--r--content/pmathoverflow.net/index.json5
-rw-r--r--content/podysee/index.json5
-rw-r--r--content/podysee_home/index.json5
-rw-r--r--content/popencores/index.json5
-rw-r--r--content/ppcspecialist.co.uk.view/index.json5
-rw-r--r--content/ppcspecialist.co.uk/index.json5
-rw-r--r--content/pphoronix/index.json5
-rw-r--r--content/proyal_geographical_society/index.json5
-rw-r--r--content/pserverfault.com/index.json5
-rw-r--r--content/pstack_exchange/index.json5
-rw-r--r--content/pstack_overflow/index.json5
-rw-r--r--content/pstackapps.com/index.json5
-rw-r--r--content/pstackoverflow.com/index.json5
-rw-r--r--content/pstallman.org/index.json5
-rw-r--r--content/psumofus/index.json5
-rw-r--r--content/psuperuser.com/index.json5
-rw-r--r--content/pworldcat/index.json5
-rw-r--r--content/pworldcat2/index.json5
-rw-r--r--content/sabc_aus/abc_aus.js61
-rw-r--r--content/sabc_aus/index.json6
-rw-r--r--content/saccuweather/accuweather.js17
-rw-r--r--content/saccuweather/index.json6
-rw-r--r--content/sbandcamp/bandcamp.js29
-rw-r--r--content/sbandcamp/index.json6
-rw-r--r--content/scentrum24_santander_3d-secure/centrum24_santander_3d-secure.js14
-rw-r--r--content/scentrum24_santander_3d-secure/index.json6
-rw-r--r--content/sgoogle_sheets_download/google_sheets_download.js198
-rw-r--r--content/sgoogle_sheets_download/index.json6
-rw-r--r--content/sinternet_archive_video/index.json6
-rw-r--r--content/sinternet_archive_video/internet_archive_video.js80
-rw-r--r--content/sodysee/index.json6
-rw-r--r--content/sodysee/odysee.js414
-rw-r--r--content/sopencores/index.json6
-rw-r--r--content/sopencores/opencores.js33
-rw-r--r--content/sparse_layout_generator/index.json6
-rw-r--r--content/sparse_layout_generator/sparse_layout_generator.js132
-rw-r--r--content/spc_specialist_uk-_cookie_banner/cookie_banner.js19
-rw-r--r--content/spc_specialist_uk-_cookie_banner/index.json6
-rw-r--r--content/spc_specialist_uk-_display_prices/display_prices.js55
-rw-r--r--content/spc_specialist_uk-_display_prices/index.json6
-rw-r--r--content/sphoronix_benchmarks/index.json6
-rw-r--r--content/sphoronix_benchmarks/phoronix_benchmarks.js27
-rw-r--r--content/sroyal_geographical_society/index.json6
-rw-r--r--content/sroyal_geographical_society/royal_geographical_society.js18
-rw-r--r--content/sstack_overflow/index.json6
-rw-r--r--content/sstack_overflow/stack_overflow.js18
-rw-r--r--content/sstallman.org/index.json6
-rw-r--r--content/sstallman.org/stallman.org.js91
-rw-r--r--content/ssumofus_sign_petition/index.json6
-rw-r--r--content/ssumofus_sign_petition/sign_petition.js54
-rw-r--r--content/sworldcat_library_holdings/index.json6
-rw-r--r--content/sworldcat_library_holdings/library_holdings.js65
62 files changed, 1573 insertions, 0 deletions
diff --git a/content/babc_aus/index.json b/content/babc_aus/index.json
new file mode 100644
index 0000000..c0dbb0a
--- /dev/null
+++ b/content/babc_aus/index.json
@@ -0,0 +1,8 @@
+{
+"type" : "bag",
+"name" : "ABC Aus",
+"components" : [
+["script", "SParse layout generator"]
+["script", "ABC Aus"]
+]
+} \ No newline at end of file
diff --git a/content/bstallman.org/index.json b/content/bstallman.org/index.json
new file mode 100644
index 0000000..98effae
--- /dev/null
+++ b/content/bstallman.org/index.json
@@ -0,0 +1,8 @@
+{
+"type" : "bag",
+"name" : "stallman.org",
+"components" : [
+["script", "SParse layout generator"]
+["script", "stallman.org"]
+]
+} \ No newline at end of file
diff --git a/content/pabc.net.au./index.json b/content/pabc.net.au./index.json
new file mode 100644
index 0000000..e3d5513
--- /dev/null
+++ b/content/pabc.net.au./index.json
@@ -0,0 +1,5 @@
+{
+"type" : "page",
+"pattern" : "https://abc.net.au/",
+"payload" : ["bag", "ABC Aus"]
+} \ No newline at end of file
diff --git a/content/pabc_aus/index.json b/content/pabc_aus/index.json
new file mode 100644
index 0000000..bede74c
--- /dev/null
+++ b/content/pabc_aus/index.json
@@ -0,0 +1,5 @@
+{
+"type" : "page",
+"pattern" : "https://www.abc.net.au/",
+"payload" : ["bag", "ABC Aus"]
+} \ No newline at end of file
diff --git a/content/paccuweather/index.json b/content/paccuweather/index.json
new file mode 100644
index 0000000..9f99e5f
--- /dev/null
+++ b/content/paccuweather/index.json
@@ -0,0 +1,5 @@
+{
+"type" : "page",
+"pattern" : "https://www.accuweather.com/***",
+"payload" : ["script", "AccuWeather"]
+} \ No newline at end of file
diff --git a/content/paskubuntu.com/index.json b/content/paskubuntu.com/index.json
new file mode 100644
index 0000000..052d685
--- /dev/null
+++ b/content/paskubuntu.com/index.json
@@ -0,0 +1,5 @@
+{
+"type" : "page",
+"pattern" : "https://askubuntu.com/***",
+"payload" : ["script", "stack overflow"]
+} \ No newline at end of file
diff --git a/content/pbandcamp/index.json b/content/pbandcamp/index.json
new file mode 100644
index 0000000..609c1f5
--- /dev/null
+++ b/content/pbandcamp/index.json
@@ -0,0 +1,5 @@
+{
+"type" : "page",
+"pattern" : "https://*.bandcamp.com/track/*",
+"payload" : ["script", "bandcamp"]
+} \ No newline at end of file
diff --git a/content/pcentrum24_santander_3d-secure/index.json b/content/pcentrum24_santander_3d-secure/index.json
new file mode 100644
index 0000000..ce6962f
--- /dev/null
+++ b/content/pcentrum24_santander_3d-secure/index.json
@@ -0,0 +1,5 @@
+{
+"type" : "page",
+"pattern" : "https://acsv.centrum24.pl/ACS/servlet/ACSAuthoriz",
+"payload" : ["script", "centrum24 Santander 3D-Secure"]
+} \ No newline at end of file
diff --git a/content/pgoogle_sheets/index.json b/content/pgoogle_sheets/index.json
new file mode 100644
index 0000000..0c669bc
--- /dev/null
+++ b/content/pgoogle_sheets/index.json
@@ -0,0 +1,5 @@
+{
+"type" : "page",
+"pattern" : "https://docs.google.com/spreadsheets/d/**",
+"payload" : ["script", "google sheets download"]
+} \ No newline at end of file
diff --git a/content/pinternet_archive/index.json b/content/pinternet_archive/index.json
new file mode 100644
index 0000000..838a527
--- /dev/null
+++ b/content/pinternet_archive/index.json
@@ -0,0 +1,5 @@
+{
+"type" : "page",
+"pattern" : "https://archive.org/details/*",
+"payload" : ["script", "internet archive video"]
+} \ No newline at end of file
diff --git a/content/pmathoverflow.net/index.json b/content/pmathoverflow.net/index.json
new file mode 100644
index 0000000..2667e1b
--- /dev/null
+++ b/content/pmathoverflow.net/index.json
@@ -0,0 +1,5 @@
+{
+"type" : "page",
+"pattern" : "https://mathoverflow.net/***",
+"payload" : ["script", "stack overflow"]
+} \ No newline at end of file
diff --git a/content/podysee/index.json b/content/podysee/index.json
new file mode 100644
index 0000000..f4fb08f
--- /dev/null
+++ b/content/podysee/index.json
@@ -0,0 +1,5 @@
+{
+"type" : "page",
+"pattern" : "https://odysee.com/***",
+"payload" : ["script", "odysee"]
+} \ No newline at end of file
diff --git a/content/podysee_home/index.json b/content/podysee_home/index.json
new file mode 100644
index 0000000..d4d09ce
--- /dev/null
+++ b/content/podysee_home/index.json
@@ -0,0 +1,5 @@
+{
+"type" : "page",
+"pattern" : "https://odysee.com",
+"payload" : ["script", "odysee"]
+} \ No newline at end of file
diff --git a/content/popencores/index.json b/content/popencores/index.json
new file mode 100644
index 0000000..dc53a23
--- /dev/null
+++ b/content/popencores/index.json
@@ -0,0 +1,5 @@
+{
+"type" : "page",
+"pattern" : "https://opencores.org/projects",
+"payload" : ["script", "opencores"]
+} \ No newline at end of file
diff --git a/content/ppcspecialist.co.uk.view/index.json b/content/ppcspecialist.co.uk.view/index.json
new file mode 100644
index 0000000..f2b7e1d
--- /dev/null
+++ b/content/ppcspecialist.co.uk.view/index.json
@@ -0,0 +1,5 @@
+{
+"type" : "page",
+"pattern" : "https://www.pcspecialist.co.uk/view/*",
+"payload" : ["script", "PC Specialist UK- Display Prices"]
+} \ No newline at end of file
diff --git a/content/ppcspecialist.co.uk/index.json b/content/ppcspecialist.co.uk/index.json
new file mode 100644
index 0000000..89a33ea
--- /dev/null
+++ b/content/ppcspecialist.co.uk/index.json
@@ -0,0 +1,5 @@
+{
+"type" : "page",
+"pattern" : "https://www.pcspecialist.co.uk/***",
+"payload" : ["script", "PC Specialist UK- Cookie Banner"]
+} \ No newline at end of file
diff --git a/content/pphoronix/index.json b/content/pphoronix/index.json
new file mode 100644
index 0000000..58d693d
--- /dev/null
+++ b/content/pphoronix/index.json
@@ -0,0 +1,5 @@
+{
+"type" : "page",
+"pattern" : "https://www.phoronix.com/***",
+"payload" : ["script", "phoronix benchmarks"]
+} \ No newline at end of file
diff --git a/content/proyal_geographical_society/index.json b/content/proyal_geographical_society/index.json
new file mode 100644
index 0000000..13cda7a
--- /dev/null
+++ b/content/proyal_geographical_society/index.json
@@ -0,0 +1,5 @@
+{
+"type" : "page",
+"pattern" : "https://www.rgs.org/about/our-collections/online-exhibitions/***",
+"payload" : ["script", "Royal Geographical Society"]
+} \ No newline at end of file
diff --git a/content/pserverfault.com/index.json b/content/pserverfault.com/index.json
new file mode 100644
index 0000000..c35db3e
--- /dev/null
+++ b/content/pserverfault.com/index.json
@@ -0,0 +1,5 @@
+{
+"type" : "page",
+"pattern" : "https://serverfault.com/***",
+"payload" : ["script", "stack overflow"]
+} \ No newline at end of file
diff --git a/content/pstack_exchange/index.json b/content/pstack_exchange/index.json
new file mode 100644
index 0000000..a94b515
--- /dev/null
+++ b/content/pstack_exchange/index.json
@@ -0,0 +1,5 @@
+{
+"type" : "page",
+"pattern" : "https://*.stackexchange.com/***",
+"payload" : ["script", "stack overflow"]
+} \ No newline at end of file
diff --git a/content/pstack_overflow/index.json b/content/pstack_overflow/index.json
new file mode 100644
index 0000000..3ed9c9c
--- /dev/null
+++ b/content/pstack_overflow/index.json
@@ -0,0 +1,5 @@
+{
+"type" : "page",
+"pattern" : "https://*.stackoverflow.com/***",
+"payload" : ["script", "stack overflow"]
+} \ No newline at end of file
diff --git a/content/pstackapps.com/index.json b/content/pstackapps.com/index.json
new file mode 100644
index 0000000..d2d5d14
--- /dev/null
+++ b/content/pstackapps.com/index.json
@@ -0,0 +1,5 @@
+{
+"type" : "page",
+"pattern" : "https://stackapps.com/***",
+"payload" : ["script", "stack overflow"]
+} \ No newline at end of file
diff --git a/content/pstackoverflow.com/index.json b/content/pstackoverflow.com/index.json
new file mode 100644
index 0000000..a6eb86c
--- /dev/null
+++ b/content/pstackoverflow.com/index.json
@@ -0,0 +1,5 @@
+{
+"type" : "page",
+"pattern" : "https://stackoverflow.com/***",
+"payload" : ["script", "stack overflow"]
+} \ No newline at end of file
diff --git a/content/pstallman.org/index.json b/content/pstallman.org/index.json
new file mode 100644
index 0000000..1fc7a0a
--- /dev/null
+++ b/content/pstallman.org/index.json
@@ -0,0 +1,5 @@
+{
+"type" : "page",
+"pattern" : "https://stallman.org/",
+"payload" : ["bag", "stallman.org"]
+} \ No newline at end of file
diff --git a/content/psumofus/index.json b/content/psumofus/index.json
new file mode 100644
index 0000000..4478cda
--- /dev/null
+++ b/content/psumofus/index.json
@@ -0,0 +1,5 @@
+{
+"type" : "page",
+"pattern" : "https://actions.sumofus.org/a/*",
+"payload" : ["script", "sumofus (sign petition)"]
+} \ No newline at end of file
diff --git a/content/psuperuser.com/index.json b/content/psuperuser.com/index.json
new file mode 100644
index 0000000..5c123cb
--- /dev/null
+++ b/content/psuperuser.com/index.json
@@ -0,0 +1,5 @@
+{
+"type" : "page",
+"pattern" : "https://superuser.com/***",
+"payload" : ["script", "stack overflow"]
+} \ No newline at end of file
diff --git a/content/pworldcat/index.json b/content/pworldcat/index.json
new file mode 100644
index 0000000..fb68d5d
--- /dev/null
+++ b/content/pworldcat/index.json
@@ -0,0 +1,5 @@
+{
+"type" : "page",
+"pattern" : "https://www.worldcat.org/title/**",
+"payload" : ["script", "worldcat (library holdings)"]
+} \ No newline at end of file
diff --git a/content/pworldcat2/index.json b/content/pworldcat2/index.json
new file mode 100644
index 0000000..82990f0
--- /dev/null
+++ b/content/pworldcat2/index.json
@@ -0,0 +1,5 @@
+{
+"type" : "page",
+"pattern" : "https://worldcat.org/title/**",
+"payload" : ["script", "worldcat (library holdings)"]
+} \ No newline at end of file
diff --git a/content/sabc_aus/abc_aus.js b/content/sabc_aus/abc_aus.js
new file mode 100644
index 0000000..9ad1cb0
--- /dev/null
+++ b/content/sabc_aus/abc_aus.js
@@ -0,0 +1,61 @@
+/*
+ Copyright © 2021 jahoti (jahoti@tilde.team)
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+var pages = ['ABC News'], comp, wrapper, heading, section, cards, card, text,
+ home = ['Home'], comps = document.getElementById('content').children;
+
+pages.push(home);
+for (i = 0; i < comps.length; i++) {
+ comp = comps[i];
+ card = undefined;
+ if (!comp.dataset.component) continue;
+
+ heading = comp.querySelector('[data-component="Heading"], [data-component="CollectionHeading"]');
+ heading = heading ? heading.innerText : 'Featured';
+ if (heading === 'Top Stories from ABC News') heading = 'Top Stories';
+
+ wrapper = document.createElement('div');
+ pages.push(['* ' + heading, wrapper])
+
+ for (card of comp.querySelectorAll('[data-component$=Card]')) {
+ text = card.innerText; //HTML.replace(/<[^<]*>/g, '\n').replace(/\n\n+/g, '\n').replace(/^\n/, '');
+ section = document.createElement('section');
+ wrapper.append(section);
+
+ heading = document.createElement('a');
+ heading.href = card.querySelector('a').href;
+ heading.style.display = 'block';
+ heading.style.fontWeight = 'bold';
+ section.append(heading);
+
+ var index = text.indexOf('\n');
+ if (index === -1) wrapper.innerText = text;
+ else {
+ heading.innerText = text.substr(0, index);
+ link = document.createElement('p'); // Reuse or abuse?
+ link.innerText = text.substr(index + 1);
+ section.append(link);
+ }
+ }
+
+ if (!card) pages.pop();
+ else if (i < 3) home.push(wrapper);
+}
+
+pages.push(['Just in', '/news/justin']);
+pages.push(['Ed. Standards', 'https://about.abc.net.au/how-the-abc-is-run/what-guides-us/abc-editorial-standards/'])
+pages.push(['Footer', document.querySelector('[data-component="Footer"]')]);
+Sparse(pages, {bgcolor: 'pink'}); \ No newline at end of file
diff --git a/content/sabc_aus/index.json b/content/sabc_aus/index.json
new file mode 100644
index 0000000..038bb5a
--- /dev/null
+++ b/content/sabc_aus/index.json
@@ -0,0 +1,6 @@
+{
+"type" : "script",
+"name" : "ABC Aus",
+"sha256" : "78f7ba7acbe53b172a1a4cbf2e045dae2c4d3a12a021414d1a6706ac356da3d4",
+"location" : "abc_aus.js"
+} \ No newline at end of file
diff --git a/content/saccuweather/accuweather.js b/content/saccuweather/accuweather.js
new file mode 100644
index 0000000..33f7794
--- /dev/null
+++ b/content/saccuweather/accuweather.js
@@ -0,0 +1,17 @@
+/*
+ Copyright © 2021 jahoti (jahoti@tilde.team)
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+for (var nonAd of document.querySelectorAll('.ads-not-loaded .non-ad')) nonAd.style.visibility = 'visible'; \ No newline at end of file
diff --git a/content/saccuweather/index.json b/content/saccuweather/index.json
new file mode 100644
index 0000000..056b634
--- /dev/null
+++ b/content/saccuweather/index.json
@@ -0,0 +1,6 @@
+{
+"type" : "script",
+"name" : "AccuWeather",
+"sha256" : "a763b4b03d5ca56eb3dbd92dad798e79e9bf105f2bd9d26ca96c54630b975d31",
+"location" : "accuweather.js"
+} \ No newline at end of file
diff --git a/content/sbandcamp/bandcamp.js b/content/sbandcamp/bandcamp.js
new file mode 100644
index 0000000..af38d77
--- /dev/null
+++ b/content/sbandcamp/bandcamp.js
@@ -0,0 +1,29 @@
+/*
+ Copyright © 2021 jahoti (jahoti@tilde.team)
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+var div, player, playerBox = document.querySelector('.inline_player');
+playerBox.innerHTML = '';
+
+for (var track of JSON.parse(document.querySelector('[data-tralbum]').dataset.tralbum).trackinfo) {
+ div = document.createElement('div');
+ player = document.createElement('audio');
+ player.controls = 'controls';
+
+ div.innerText = track.title + ': ';
+ player.src = track.file['mp3-128']; // Is this always available?
+ div.append(player);
+ playerBox.append(div);
+} \ No newline at end of file
diff --git a/content/sbandcamp/index.json b/content/sbandcamp/index.json
new file mode 100644
index 0000000..cb35d73
--- /dev/null
+++ b/content/sbandcamp/index.json
@@ -0,0 +1,6 @@
+{
+"type" : "script",
+"name" : "bandcamp",
+"sha256" : "b71ce80edaff65aae8ecefce542015a60718bdfde0c43438bffcdf51009cd64d",
+"location" : "bandcamp.js"
+} \ No newline at end of file
diff --git a/content/scentrum24_santander_3d-secure/centrum24_santander_3d-secure.js b/content/scentrum24_santander_3d-secure/centrum24_santander_3d-secure.js
new file mode 100644
index 0000000..28fcdc5
--- /dev/null
+++ b/content/scentrum24_santander_3d-secure/centrum24_santander_3d-secure.js
@@ -0,0 +1,14 @@
+/**
+ * Copyright 2021 Wojtek Kosior
+ *
+ * Available under the terms of Creative Commons Zero.
+ */
+
+const submit_button = document.getElementById("submit");
+submit_button.classList.remove("disabled");
+submit_button.removeAttribute("disabled");
+
+console.log(document.querySelectorAll(".noscript"));
+
+for (const noscript_element of document.querySelectorAll(".noscript"))
+ noscript_element.remove();
diff --git a/content/scentrum24_santander_3d-secure/index.json b/content/scentrum24_santander_3d-secure/index.json
new file mode 100644
index 0000000..eca1bba
--- /dev/null
+++ b/content/scentrum24_santander_3d-secure/index.json
@@ -0,0 +1,6 @@
+{
+"type" : "script",
+"name" : "centrum24 Santander 3D-Secure",
+"sha256" : "b3f76e437c48bf5567165e224c8a7fed0fce7a93706302968614b2225bf03277",
+"location" : "centrum24_santander_3d-secure.js"
+} \ No newline at end of file
diff --git a/content/sgoogle_sheets_download/google_sheets_download.js b/content/sgoogle_sheets_download/google_sheets_download.js
new file mode 100644
index 0000000..dc959e1
--- /dev/null
+++ b/content/sgoogle_sheets_download/google_sheets_download.js
@@ -0,0 +1,198 @@
+/**
+ * Copyright 2021 Wojtek Kosior
+ *
+ * This program is free software; you can redistribute it
+ * and/or modify it under the terms of either:
+ * - the GNU General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at
+ * your option) any later version, or
+ * - the "A" license: <https://koszko.org/alicense.txt>; explained
+ * at: <https://koszko.org/en/articles/my-new-license.html>
+ *
+ * As additional permission under GNU GPL version 3 section 7, you
+ * may distribute forms of that code without the copy of the GNU
+ * GPL normally required by section 4, provided you include this
+ * license notice and, in case of non-source distribution, a URL
+ * through which recipients can access the Corresponding Source.
+ * If you modify file(s) with this exception, you may extend this
+ * exception to your version of the file(s), but you are not
+ * obligated to do so. If you do not wish to do so, delete this
+ * exception statement from your version. If you delete this
+ * exception statement from all source files in the program, then
+ * also delete it here.
+ *
+ * As a special exception to the GPL, any HTML file which merely
+ * makes function calls to this code, and for that purpose
+ * includes it by reference shall be deemed a separate work for
+ * copyright law purposes. If you modify this code, you may extend
+ * this exception to your version of the code, but you are not
+ * obligated to do so. If you do not wish to do so, delete this
+ * exception statement from your version.
+ */
+
+
+/* Make the view scrollable. */
+
+document.body.setAttribute("style",
+ "width: 100vw; height: 100vh; overflow: scroll;" +
+ (document.body.getAttribute("style") || ""));
+
+let container = document.querySelectorAll(".waffle")[0];
+let main_gid = null;
+
+while (container) {
+ container = container.parentElement;
+ console.log(container);
+ if (container === document.body || !container)
+ break;
+
+ const match = /([0-9]+)-grid-container/.exec(container.id);
+ if (match)
+ main_gid = match[1];
+
+ container.setAttribute("style",
+ "width: fit-content; width: -moz-fit-content;");
+}
+
+
+/* Remove editor toolbars and bottom bar - these don't work anyway. */
+
+const docs_chrome = document.getElementById("docs-chrome");
+if (docs_chrome)
+ docs_chrome.remove()
+const grid_bottom_bar = document.getElementById("grid-bottom-bar");
+if (grid_bottom_bar)
+ grid_bottom_bar.remove()
+
+
+/* Remove no Javascript warning. */
+
+for (const no_js_warning of document.querySelectorAll("noscript"))
+ no_js_warning.remove();
+
+
+/* Get opengraph data. */
+
+const og = {};
+
+for (const node of document.head.childNodes) {
+ if (node.tagName === "STYLE") {
+ document.head.removeChild(node);
+ continue;
+ }
+
+ if (node.tagName !== "META")
+ continue;
+
+ const match = /^og:(.+)/.exec(node.getAttribute("property"));
+ if (!match)
+ continue;
+
+ og[match[1]] = node.getAttribute("content");
+}
+
+
+/* Construct download link. */
+
+let download_link = null;
+
+const match = new RegExp("/spreadsheets/d/([^/]+)").exec(document.URL);
+if (match)
+ download_link = `https://docs.google.com/spreadsheets/d/${match[1]}/export`;
+
+
+/* Add title bar with sheet name and download button. */
+
+const title_bar = document.createElement("div");
+const title_heading = document.createElement("h1");
+const title_text = document.createElement("span");
+const main_download_button = document.createElement("a");
+
+main_download_button.textContent = "download";
+main_download_button.setAttribute("style", "border-radius: 10px; padding: 20px; color: #333; background-color: lightgreen; text-decoration: none; box-shadow: -4px 8px 8px #888; display: inline-block;");
+
+if (og.title) {
+ title_text.textContent = og.title;
+ title_heading.appendChild(title_text);
+}
+
+title_text.setAttribute("style", "margin-right: 10px;");
+
+if (download_link) {
+ main_download_button.setAttribute("href", download_link);
+ title_heading.appendChild(main_download_button);
+}
+
+title_bar.setAttribute("style", "padding: 0 20px; color: #555;");
+
+title_bar.appendChild(title_heading);
+
+document.body.insertBefore(title_bar, document.body.firstElementChild);
+
+
+/* Extract sheet data from a script that sets the `bootstrapData' variable. */
+
+let data = null;
+for (const script of document.scripts) {
+ const match = /bootstrapData = ({([^;]|[^}];)+})/.exec(script.textContent);
+ if (!match)
+ continue;
+ data = JSON.parse(match[1]);
+}
+
+/*
+ * Add download buttons for individual sheets belonging to this spreadsheet.
+ * Data schema has been observed by looking at various spreadsheets.
+ */
+
+function add_sheet_download(data)
+{
+ if (!Array.isArray(data))
+ return;
+
+ const gid = data[2];
+ if (!["string", "number"].includes(typeof gid))
+ return;
+
+ const sheet_download_link = `${download_link}?gid=${gid}`;
+ const sheet_download_button = document.createElement("a");
+
+ sheet_download_button.setAttribute("style", "border-radius: 5px; padding: 10px; color: #333; background-color: lightgreen; text-decoration: none; box-shadow: -4px 8px 8px #888; display: inline-block; margin: 0 5px 5px 0;");
+ sheet_download_button.setAttribute("href", sheet_download_link);
+
+ let sheet_name = null;
+ if (Array.isArray(data[3]) &&
+ data[3][0] && typeof data[3][0] === "object"
+ && Array.isArray(data[3][0][1]) &&
+ Array.isArray(data[3][0][1][0]) &&
+ typeof data[3][0][1][0][2] === "string") {
+
+ const sheet_name = data[3][0][1][0][2];
+ sheet_download_button.textContent = sheet_name;
+ if (gid == main_gid)
+ title_text.textContent = `${title_text.textContent} - ${sheet_name}`;
+ } else {
+ sheet_download_button.textContent = `<sheet gid=${gid}>`;
+ }
+
+ title_bar.appendChild(sheet_download_button);
+}
+
+if (download_link) {
+ for (const entry of data.changes.topsnapshot) {
+ if (!Array.isArray(entry) || entry[0] !== 21350203 ||
+ typeof entry[1] !== "string")
+ continue;
+
+ let entry_data = null;
+
+ try {
+ entry_data = JSON.parse(entry[1]);
+ } catch (e) {
+ console.log(e);
+ continue;
+ }
+
+ add_sheet_download(entry_data);
+ }
+}
diff --git a/content/sgoogle_sheets_download/index.json b/content/sgoogle_sheets_download/index.json
new file mode 100644
index 0000000..e827ef4
--- /dev/null
+++ b/content/sgoogle_sheets_download/index.json
@@ -0,0 +1,6 @@
+{
+"type" : "script",
+"name" : "google sheets download",
+"sha256" : "d929bf08fdbbc2f4ffe861aa1250950bbc7ceb7978c7b8a6cd5e9b57307699ef",
+"location" : "google_sheets_download.js"
+} \ No newline at end of file
diff --git a/content/sinternet_archive_video/index.json b/content/sinternet_archive_video/index.json
new file mode 100644
index 0000000..aeecce8
--- /dev/null
+++ b/content/sinternet_archive_video/index.json
@@ -0,0 +1,6 @@
+{
+"type" : "script",
+"name" : "internet archive video",
+"sha256" : "bc0c37e1aee1971b7d604b90625c96cc9ded7e22901b65540046243ccc12fe33",
+"location" : "internet_archive_video.js"
+} \ No newline at end of file
diff --git a/content/sinternet_archive_video/internet_archive_video.js b/content/sinternet_archive_video/internet_archive_video.js
new file mode 100644
index 0000000..7c2c6b4
--- /dev/null
+++ b/content/sinternet_archive_video/internet_archive_video.js
@@ -0,0 +1,80 @@
+/**
+ * Copyright 2021 Wojtek Kosior
+ *
+ * This program is free software; you can redistribute it
+ * and/or modify it under the terms of either:
+ * - the GNU General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at
+ * your option) any later version, or
+ * - the "A" license: <https://koszko.org/alicense.txt>; explained
+ * at: <https://koszko.org/en/articles/my-new-license.html>
+ *
+ * As additional permission under GNU GPL version 3 section 7, you
+ * may distribute forms of that code without the copy of the GNU
+ * GPL normally required by section 4, provided you include this
+ * license notice and, in case of non-source distribution, a URL
+ * through which recipients can access the Corresponding Source.
+ * If you modify file(s) with this exception, you may extend this
+ * exception to your version of the file(s), but you are not
+ * obligated to do so. If you do not wish to do so, delete this
+ * exception statement from your version. If you delete this
+ * exception statement from all source files in the program, then
+ * also delete it here.
+ *
+ * As a special exception to the GPL, any HTML file which merely
+ * makes function calls to this code, and for that purpose
+ * includes it by reference shall be deemed a separate work for
+ * copyright law purposes. If you modify this code, you may extend
+ * this exception to your version of the code, but you are not
+ * obligated to do so. If you do not wish to do so, delete this
+ * exception statement from your version.
+ */
+
+const theatre_ia = document.getElementById("theatre-ia");
+
+let srcs = [];
+
+let ogv_src = null;
+let webm_src = null;
+let mp4_src = null;
+
+function process_link(link)
+{
+ ogv_src = ogv_src || (/\.ogv$/.test(link) && link);
+ webm_src = webm_src || (/\.webm$/.test(link) && link);
+ mp4_src = mp4_src || (/\.mp4$/.test(link) && link);
+}
+
+if (theatre_ia) {
+ for (const a of
+ document.querySelectorAll(".item-download-options a.download-pill"))
+ process_link(a.href);
+
+ for (const link of document.querySelectorAll("link[itemprop=contentUrl]"))
+ process_link(link.href);
+
+ srcs = [
+ {src: ogv_src, type: "video/ogg"},
+ {src: webm_src, type: "video/webm"},
+ {src: mp4_src, type: "video/mp4"}
+ ].filter(src => src.src);
+}
+
+if (srcs.length > 0) {
+ const video = document.createElement("video");
+
+ for (const src of srcs) {
+ const source = document.createElement("source");
+ Object.assign(source, src);
+ video.appendChild(source);
+ }
+
+ video.setAttribute("width", "100%");
+ video.setAttribute("height", "auto");
+ video.setAttribute("controls", "");
+
+ for (const child of theatre_ia.children)
+ child.remove();
+
+ theatre_ia.appendChild(video);
+}
diff --git a/content/sodysee/index.json b/content/sodysee/index.json
new file mode 100644
index 0000000..c56e9e8
--- /dev/null
+++ b/content/sodysee/index.json
@@ -0,0 +1,6 @@
+{
+"type" : "script",
+"name" : "odysee",
+"sha256" : "476d63dffb66969d863e47ded926221f9337e7628642f99b8725907743fdac8b",
+"location" : "odysee.js"
+} \ No newline at end of file
diff --git a/content/sodysee/odysee.js b/content/sodysee/odysee.js
new file mode 100644
index 0000000..5a06957
--- /dev/null
+++ b/content/sodysee/odysee.js
@@ -0,0 +1,414 @@
+/**
+ * Copyright 2021 Wojtek Kosior
+ *
+ * This program is free software; you can redistribute it
+ * and/or modify it under the terms of either:
+ * - the GNU General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at
+ * your option) any later version, or
+ * - the "A" license: <https://koszko.org/alicense.txt>; explained
+ * at: <https://koszko.org/en/articles/my-new-license.html>
+ *
+ * As additional permission under GNU GPL version 3 section 7, you
+ * may distribute forms of that code without the copy of the GNU
+ * GPL normally required by section 4, provided you include this
+ * license notice and, in case of non-source distribution, a URL
+ * through which recipients can access the Corresponding Source.
+ * If you modify file(s) with this exception, you may extend this
+ * exception to your version of the file(s), but you are not
+ * obligated to do so. If you do not wish to do so, delete this
+ * exception statement from your version. If you delete this
+ * exception statement from all source files in the program, then
+ * also delete it here.
+ *
+ * As a special exception to the GPL, any HTML file which merely
+ * makes function calls to this code, and for that purpose
+ * includes it by reference shall be deemed a separate work for
+ * copyright law purposes. If you modify this code, you may extend
+ * this exception to your version of the code, but you are not
+ * obligated to do so. If you do not wish to do so, delete this
+ * exception statement from your version.
+ */
+
+/* use with https://odysee.com/*** */
+
+/* Helper functions for ajax. */
+
+function ajax_callback(xhttp, cb)
+{
+ cb(xhttp.response);
+}
+
+function perform_ajax(method, url, callback, err_callback, data)
+{
+ const xhttp = new XMLHttpRequest();
+ xhttp.onload = () => ajax_callback(xhttp, callback);
+ xhttp.onerror = err_callback;
+ xhttp.onabort = err_callback;
+ xhttp.open(method, url, true);
+ try {
+ xhttp.send(data);
+ } catch(e) {
+ err_callback();
+ }
+}
+
+/* Helper functions for strings with HTML entities (e.g. `&quot;'). */
+function HTML_decode(text)
+{
+ const tmp_span = document.createElement("span");
+ tmp_span.innerHTML = text;
+ return tmp_span.textContent;
+}
+
+/* Odysee API servers. */
+
+const odysee_resolve_url = "https://api.na-backend.odysee.com/api/v1/proxy?m=resolve";
+const lighthouse_search_url = "https://lighthouse.odysee.com/search";
+
+/*
+ * If we're on a video page, show the video. Use JSON data embedded in <head>
+ * if possible. If not - fetch video data using Odysee API.
+ */
+
+let data = null;
+
+function process_json_script(json_script)
+{
+ try {
+ data = JSON.parse(json_script.textContent);
+ } catch (e) {
+ console.log("Error parsing content data", e);
+ }
+}
+
+for (const json_script of document.querySelectorAll("head script")) {
+ if (["blocked-type", "type"].map(a => json_script.getAttribute(a))
+ .includes("application/ld+json"))
+ process_json_script(json_script);
+}
+
+const body = document.createElement("body");
+const video_container = document.createElement("div");
+
+body.appendChild(video_container);
+
+function show_video(content_url, title, upload_date, description)
+{
+ if (content_url) {
+ const video = document.createElement("video");
+ const source = document.createElement("source");
+
+ source.src = content_url;
+
+ video.setAttribute("width", "100%");
+ video.setAttribute("height", "auto");
+ video.setAttribute("controls", "");
+
+ video.appendChild(source);
+
+ video_container.appendChild(video);
+ }
+
+ if (title) {
+ const h1 = document.createElement("h1");
+
+ h1.textContent = HTML_decode(title);
+ h1.setAttribute("style", "color: #555;");
+
+ video_container.appendChild(h1);
+ }
+
+ if (upload_date) {
+ try {
+ const date = new Date(upload_date).toString();
+ const date_div = document.createElement("div");
+
+ date_div.textContent = `Uploaded: ${date}`;
+ date_div.setAttribute("style", "font-size: 14px; font-weight: bold; margin-bottom: 5px;");
+
+ video_container.appendChild(date_div);
+ } catch(e) {
+ console.log("Error parsing content upload date", e);
+ }
+ }
+
+ if (description) {
+ const description_div = document.createElement("div");
+
+ description_div.textContent = HTML_decode(description);
+ description_div.setAttribute("style", "white-space: pre;");
+
+ video_container.appendChild(description_div);
+ }
+}
+
+function show_video_from_query(response)
+{
+ try {
+ var result = Object.values(JSON.parse(response).result)[0];
+
+ if (result.value_type !== "stream")
+ return;
+
+ var date = result.timestamp * 1000;
+ var description = result.value.description;
+ var title = result.value.title;
+ const name = encodeURIComponent(result.name);
+ var url = `https://odysee.com/$/stream/${name}/${result.claim_id}`;
+ } catch (e) {
+ return;
+ }
+
+ show_video(url, title, date, description);
+}
+
+function fetch_show_video(name, claim_id)
+{
+ const payload = {
+ jsonrpc: "2.0",
+ method: "resolve",
+ params: {
+ urls: [`lbry://${decodeURIComponent(name)}#${claim_id}`],
+ include_purchase_receipt: true
+ },
+ id: Math.round(Math.random() * 10**14)
+ };
+
+ perform_ajax("POST", odysee_resolve_url, show_video_from_query,
+ () => null, JSON.stringify(payload));
+}
+
+if (data && typeof data === "object" && data["@type"] === "VideoObject") {
+ show_video(data.contentUrl, data.name, data.uploadDate, data.description);
+} else {
+ const match = /\/([^/]+):([0-9a-f]+)$/.exec(document.URL);
+ if (match)
+ fetch_show_video(match[1], match[2]);
+}
+
+/* Show search. */
+
+const search_input = document.createElement("input");
+const search_submit = document.createElement("button");
+const search_form = document.createElement("form");
+const error_div = document.createElement("div");
+
+search_submit.textContent = "Search Odysee";
+
+search_form.setAttribute("style", "margin: 15px 0 0 0;");
+
+search_form.appendChild(search_input);
+search_form.appendChild(search_submit);
+
+error_div.textContent = "Failed to perform search :c";
+error_div.setAttribute("style", "display: none;");
+
+body.appendChild(search_form);
+body.appendChild(error_div);
+
+/* Replace the UI. */
+
+document.documentElement.replaceChild(body, document.body);
+
+/* Add the logic of performing search and showing results. */
+
+function show_error()
+{
+ error_div.setAttribute("style", "color: #b44;");
+}
+
+function clear_error()
+{
+ error_div.setAttribute("style", "display: none;");
+}
+
+let results_div = null;
+const load_more_but = document.createElement("button");
+
+load_more_but.textContent = "Load more";
+
+function show_search_entries(new_results_div, response)
+{
+ try {
+ var results = Object.values(JSON.parse(response).result);
+ } catch (e) {
+ console.log("Failed to parse search response :c",
+ "Bad response format from api.na-backend.odysee.com.");
+ show_error();
+ return;
+ }
+
+ for (const result of results) {
+ try {
+ if (result.value_type !== "stream")
+ continue;
+
+ let channel_specifier = "";
+ let channel_name = null;
+ try {
+ channel_name = result.signing_channel.name;
+ const channel_name_enc = encodeURIComponent(channel_name);
+ const channel_digit = result.signing_channel.claim_id[0];
+ channel_specifier = `${channel_name_enc}:${channel_digit}`;
+ } catch (e) {
+ }
+ const video_name = encodeURIComponent(result.name);
+ const video_id = result.claim_id[0];
+
+ const result_a = document.createElement("a");
+ const thumbnail = document.createElement("img");
+ const title_span = document.createElement("span");
+ const uploader_div = document.createElement("div");
+ const description_div = document.createElement("div");
+
+ thumbnail.setAttribute("style", "width: 100px; height: auto;");
+ thumbnail.setAttribute("alt", result.value.thumbnail.url);
+ thumbnail.src = result.value.thumbnail.url;
+
+ title_span.setAttribute("style", "font-weight: bold;");
+ title_span.textContent = result.value.title;
+
+ uploader_div.setAttribute("style", "margin-left: 5px; font-size: 21px; color: #555;");
+ uploader_div.textContent = channel_name;
+
+ description_div.setAttribute("style", "white-space: pre;");
+ description_div.textContent = result.value.description;
+
+ result_a.setAttribute("style", "display: block; width: 100%; text-decoration: none; color: #333; margin: 8px; border-style: solid; border-width: 3px 0 0 0; border-color: #7aa;");
+ result_a.href = `https://odysee.com${channel_specifier}/${video_name}:${video_id}`;
+
+ if (result.value.thumbnail.url)
+ result_a.appendChild(thumbnail);
+ result_a.appendChild(title_span);
+ if (channel_name)
+ result_a.appendChild(uploader_div);
+ result_a.appendChild(description_div);
+
+ new_results_div.appendChild(result_a);
+ }
+ catch(e) {
+ console.log(e);
+ }
+ }
+
+ clear_error();
+
+ if (results_div)
+ results_div.remove();
+
+ results_div = new_results_div;
+
+ body.appendChild(results_div);
+ body.appendChild(load_more_but);
+
+ enable_search_form();
+}
+
+function search_ajax_error(url)
+{
+ console.log(`Failed to query ${url} :c`);
+ show_error();
+ enable_search_form();
+}
+
+function get_detailed_search_entries(new_results_div, response)
+{
+ /* TODO: Simplify JSON handling using sanitize_JSON.js from Hachette. */
+ try {
+ var response_data = JSON.parse(response);
+ if (!Array.isArray(response_data))
+ throw "Bad response format from lighthouse.odysee.com.";
+ } catch (e) {
+ show_error();
+ console.log("Failed to parse search response :c", e);
+ enable_search_form();
+ return;
+ }
+
+ const callback = r => show_search_entries(new_results_div, r);
+ const lbry_urls = [];
+
+ for (const search_result of response_data) {
+ if (!search_result.claimId || !search_result.name)
+ continue;
+ lbry_urls.push(`lbry://${search_result.name}#${search_result.claimId}`);
+ }
+
+ const payload = {
+ jsonrpc: "2.0",
+ method: "resolve",
+ params: {
+ urls: lbry_urls,
+ include_purchase_receipt: true
+ },
+ id: Math.round(Math.random() * 10**14)
+ };
+
+ const url = odysee_resolve_url;
+
+ perform_ajax("POST", url, callback, () => search_ajax_error(url),
+ JSON.stringify(payload));
+}
+
+function get_search_entries(new_results_div, query, from)
+{
+ const callback = r => get_detailed_search_entries(new_results_div, r);
+ const url = `${lighthouse_search_url}?s=${encodeURIComponent(query)}&size=20&from=${from}&claimType=file,channel&nsfw=false&free_only=true`;
+
+ new_results_div.setAttribute("data-fetched", parseInt(from) + 20);
+
+ perform_ajax("GET", url, callback, () => search_ajax_error(url));
+}
+
+function search(event)
+{
+ if (event)
+ event.preventDefault();
+
+ if (!/[^\s]/.test(search_input.value))
+ return;
+
+ disable_search_form();
+
+ const new_results_div = document.createElement("div");
+
+ new_results_div.setAttribute("data-query", search_input.value);
+
+ get_search_entries(new_results_div, search_input.value, 0);
+}
+
+function search_more()
+{
+ disable_search_form();
+
+ get_search_entries(results_div, results_div.getAttribute("data-query"),
+ results_div.getAttribute("data-fetched"));
+}
+
+load_more_but.addEventListener("click", search_more);
+
+function enable_search_form()
+{
+ search_form.addEventListener("submit", search);
+ search_submit.removeAttribute("disabled");
+ if (results_div)
+ load_more_but.removeAttribute("disabled");
+}
+
+function disable_search_form()
+{
+ search_form.removeEventListener("submit", search);
+ search_submit.setAttribute("disabled", "");
+ load_more_but.setAttribute("disabled", "");
+}
+
+
+enable_search_form();
+
+
+const match = /^[^?]*search\?q=([^&]+)/.exec(document.URL)
+if (match) {
+ search_input.value = decodeURIComponent(match[1]);
+ search();
+}
diff --git a/content/sopencores/index.json b/content/sopencores/index.json
new file mode 100644
index 0000000..a8e2b61
--- /dev/null
+++ b/content/sopencores/index.json
@@ -0,0 +1,6 @@
+{
+"type" : "script",
+"name" : "opencores",
+"sha256" : "5ce6359ef5f253a95c13a43a622712ea1edf67e7f1df7b52b5456fbf8c59c377",
+"location" : "opencores.js"
+} \ No newline at end of file
diff --git a/content/sopencores/opencores.js b/content/sopencores/opencores.js
new file mode 100644
index 0000000..085a613
--- /dev/null
+++ b/content/sopencores/opencores.js
@@ -0,0 +1,33 @@
+/**
+ * Copyright 2021 Wojtek Kosior
+ *
+ * Available under the terms of Creative Commons Zero.
+ */
+
+let data = JSON.parse(document.getElementById("__NEXT_DATA__").textContent);
+let sections = {};
+for (let h1 of document.getElementsByClassName("cMJCrc")) {
+ let ul = document.createElement("ul");
+ if (h1.nextElementSibling !== null)
+ h1.parentNode.insertBefore(ul, h1.nextElementSibling);
+ else
+ h1.parentNode.appendChild(ul);
+
+ sections[h1.children[1].firstChild.textContent] = ul;
+}
+
+for (let prop of data.props.pageProps.list) {
+ let ul = sections[prop.category];
+ if (ul === undefined) {
+ console.log(`unknown category "${prop.category}" for project "${prop.title}"`);
+ continue;
+ }
+
+ let li = document.createElement("li");
+ let a = document.createElement("a");
+ a.setAttribute("href", "/projects/" + prop.slug);
+ a.textContent = prop.title;
+
+ li.appendChild(a);
+ ul.appendChild(li);
+}
diff --git a/content/sparse_layout_generator/index.json b/content/sparse_layout_generator/index.json
new file mode 100644
index 0000000..167f06c
--- /dev/null
+++ b/content/sparse_layout_generator/index.json
@@ -0,0 +1,6 @@
+{
+"type" : "script",
+"name" : "SParse layout generator",
+"sha256" : "f7bd9d6446254275f158c0ea6ec53160d4c52542741adbc0b3f34b48521aff65",
+"location" : "sparse_layout_generator.js"
+} \ No newline at end of file
diff --git a/content/sparse_layout_generator/sparse_layout_generator.js b/content/sparse_layout_generator/sparse_layout_generator.js
new file mode 100644
index 0000000..bf82fdd
--- /dev/null
+++ b/content/sparse_layout_generator/sparse_layout_generator.js
@@ -0,0 +1,132 @@
+/*
+ Generate simple yet clean single-page site(oids)
+
+ Copyright © 2021 jahoti (jahoti@tilde.team)
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+function Sparse(navItems, opts) {
+ opts = opts || {};
+ var width = opts.width || 20,
+ text = opts.text || 'black',
+ bg = opts.bgcolor || opts.background || 'yellow',
+ pagebg = opts.tabcolor || 'white';
+ gap = opts.gap || '10px';
+
+ var body = document.createElement('body'),
+ nav = document.createElement('nav'),
+ style = document.createElement('style');
+
+ var link, activeLink, title;
+
+ style.innerText = `
+ body {
+ display: grid;
+ grid-column-gap: ${gap};
+ column-gap: ${gap};
+ grid-template-columns: ${width}%;
+ }
+
+ nav {
+ grid-column: 1;
+ position: sticky;
+ top: 0;
+ }
+
+ nav > a:not([href]) {
+ color: ${text};
+ font-weight: bold;
+ }
+
+ body, nav { background-color: ${bg}; }
+ body > * { grid-row: 1; }
+ body > *:not(nav) { background-color: ${pagebg} }
+ `
+
+ body.append(style);
+ body.append(nav);
+
+ function onLinkClick(e) {
+ var link, section, title;
+ if (activeLink) {
+ link = activeLink.inactive
+ nav.replaceChild(link, activeLink);
+ for (pane of link.panes) body.removeChild(pane.parentNode);
+
+ delete activeLink.inactive;
+ }
+
+ link = e.target;
+ activeLink = document.createElement('span');
+ activeLink.innerText = link.textContent;
+ activeLink.inactive = link;
+ nav.replaceChild(activeLink, link);
+
+ link.panes.forEach((pane, i) => {
+ section = document.createElement('article');
+ title = document.createElement('h1');
+
+ title.innerText = pane.docTitle;
+ section.style.gridColumn = (i + 2).toString();
+
+ if (pane.docTitleLink) {
+ let titleLink = document.createElement('a');
+
+ titleLink.href = pane.docTitleLink;
+ titleLink.append(title);
+ title = titleLink;
+ }
+
+ section.append(title);
+ section.append(pane);
+ body.append(section);
+ });
+ }
+
+ document.title = navItems[0];
+
+ for (var item of navItems) {
+ link = document.createElement('a');
+ if (typeof item === 'string') link.innerText = item;
+ else {
+ link.innerText = item.shift();
+ if (link.textContent.startsWith('* ')) {
+ link.innerText = link.textContent.substr(2);
+ link.style.fontSize = '80%';
+ }
+
+ if (typeof item[0] === 'string' && item.length === 1) link.href = item[0];
+ else {
+ link.onclick = onLinkClick;
+ link.href = '#';
+ if (item.length === 2 && typeof item[1] === 'string') {
+ // Add a title link (if applicable)
+ item[0].docTitleLink = item.pop();
+ }
+
+ link.panes = item;
+
+ // Add the title info
+ if (item.length === 1) item[0].docTitle = link.textContent;
+ }
+ }
+
+ nav.append(link);
+ nav.append(document.createElement('br'));
+ }
+
+ activeLink = null;
+ document.body.parentNode.replaceChild(body, document.body);
+ nav.querySelector('a[href]').click();
+} \ No newline at end of file
diff --git a/content/spc_specialist_uk-_cookie_banner/cookie_banner.js b/content/spc_specialist_uk-_cookie_banner/cookie_banner.js
new file mode 100644
index 0000000..02e16fa
--- /dev/null
+++ b/content/spc_specialist_uk-_cookie_banner/cookie_banner.js
@@ -0,0 +1,19 @@
+/*
+ Copyright © 2021 jahoti (jahoti@tilde.team)
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+const jbc = document.querySelector('.cc-policy');
+
+jbc.querySelector('.cc-buttons').onclick = () => jbc.parentNode.removeChild(jbc); \ No newline at end of file
diff --git a/content/spc_specialist_uk-_cookie_banner/index.json b/content/spc_specialist_uk-_cookie_banner/index.json
new file mode 100644
index 0000000..faf1d06
--- /dev/null
+++ b/content/spc_specialist_uk-_cookie_banner/index.json
@@ -0,0 +1,6 @@
+{
+"type" : "script",
+"name" : "PC Specialist UK- Cookie Banner",
+"sha256" : "1b8ca715c9f1275685282a9bdf43fd94b0abaf24284d20be9ee63eeaa413ba85",
+"location" : "cookie_banner.js"
+}
diff --git a/content/spc_specialist_uk-_display_prices/display_prices.js b/content/spc_specialist_uk-_display_prices/display_prices.js
new file mode 100644
index 0000000..f60f6ae
--- /dev/null
+++ b/content/spc_specialist_uk-_display_prices/display_prices.js
@@ -0,0 +1,55 @@
+/*
+ Copyright © 2021 jahoti (jahoti@tilde.team)
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+const formId = document.querySelector('input[name="page_id"]').value;
+const form = document.querySelector('form[name="specbuilder"]');
+const noVat = document.getElementById('running_total_ex');
+const incVat = document.getElementById('running_total_inc');
+
+function updatePrice() {
+ const xhr = new XMLHttpRequest();
+
+ var names = [], values = [];
+ for (var inputElement of form.querySelectorAll('select, input[type="radio"]')) {
+ if (inputElement.name && (inputElement.checked || inputElement.tagName === 'SELECT')) {
+ names.push(inputElement.name);
+ values.push(inputElement.value);
+ }
+ }
+
+ const url = 'https://www.pcspecialist.co.uk/ajax/running_total.php?categories=' + names.join('%2C') +
+ '%2C&products=' + values.join('%2C') + '%2C&q=' + form.querySelector('input[name="q"]').value + '&form_id=' + formId;
+
+ xhr.onreadystatechange = priceUpdated;
+ xhr.open('GET', url, true);
+ xhr.send();
+}
+
+function priceUpdated() {
+ if (this.readyState === 4) {
+ if (this.status === 200) {
+ const parts = this.responseText.split("'");
+ noVat.innerText = parts[parts.length - 6];
+ incVat.innerText = parts[parts.length - 2];
+ }
+ else alert('Failed to get data: HTTP status code ' + this.status);
+ }
+}
+
+const button = document.createElement('button');
+button.innerText = 'Update Prices';
+button.onclick = updatePrice;
+document.querySelector('.price-holder.price-finance-holder').append(button); \ No newline at end of file
diff --git a/content/spc_specialist_uk-_display_prices/index.json b/content/spc_specialist_uk-_display_prices/index.json
new file mode 100644
index 0000000..98ebc2f
--- /dev/null
+++ b/content/spc_specialist_uk-_display_prices/index.json
@@ -0,0 +1,6 @@
+{
+"type" : "script",
+"name" : "PC Specialist UK- Display Prices",
+"sha256" : "2fe767a1b8ee4d28e4c15eb065ecfbc0d4aebebfb2569497ed779a0ebe71112b",
+"location" : "display_prices.js"
+}
diff --git a/content/sphoronix_benchmarks/index.json b/content/sphoronix_benchmarks/index.json
new file mode 100644
index 0000000..61bb5ce
--- /dev/null
+++ b/content/sphoronix_benchmarks/index.json
@@ -0,0 +1,6 @@
+{
+"type" : "script",
+"name" : "phoronix benchmarks",
+"sha256" : "575ec9b3c356337c1f8d1670f3ba459cd9b39b15d51999df1dee35e34da427e1",
+"location" : "phoronix_benchmarks.js"
+} \ No newline at end of file
diff --git a/content/sphoronix_benchmarks/phoronix_benchmarks.js b/content/sphoronix_benchmarks/phoronix_benchmarks.js
new file mode 100644
index 0000000..264545f
--- /dev/null
+++ b/content/sphoronix_benchmarks/phoronix_benchmarks.js
@@ -0,0 +1,27 @@
+/**
+ * Copyright 2021 Wojtek Kosior
+ *
+ * Available under the terms of Creative Commons Zero.
+ */
+
+/* Use with https://www.phoronix.com/*** */
+
+/*
+ * Phoronix normally includes scripts that call document.write() to inject
+ * <img> tags. The most obvious way o code a fix would then be do download and
+ * parse the contents of those scripts. CORS, however, doesn't allow this.
+ * Instead, we notice that the openbenchmarking embed script url is related to
+ * the actual image url we need, so we can create <img>'s from it straight away.
+ */
+for (const script of document.scripts) {
+ const match = /openbenchmarking.org\/+(embed.php\?.*)p=0$/.exec(script.src);
+ if (!match) continue;
+
+ const img = document.createElement("img");
+ img.src = `https://openbenchmarking.org/${match[1]}p=2`;
+ img.setAttribute("type", "image/svg+xml");
+ img.setAttribute("width", "100%");
+ img.setAttribute("height", "auto");
+
+ script.parentElement.insertBefore(img, script);
+}
diff --git a/content/sroyal_geographical_society/index.json b/content/sroyal_geographical_society/index.json
new file mode 100644
index 0000000..6eb24ad
--- /dev/null
+++ b/content/sroyal_geographical_society/index.json
@@ -0,0 +1,6 @@
+{
+"type" : "script",
+"name" : "Royal Geographical Society",
+"sha256" : "68c0722fee4231350f46189b838205b8e62a5004a0493d87f495cdad4ff179f5",
+"location" : "royal_geographical_society.js"
+} \ No newline at end of file
diff --git a/content/sroyal_geographical_society/royal_geographical_society.js b/content/sroyal_geographical_society/royal_geographical_society.js
new file mode 100644
index 0000000..be35d14
--- /dev/null
+++ b/content/sroyal_geographical_society/royal_geographical_society.js
@@ -0,0 +1,18 @@
+/*
+ Copyright © 2021 jahoti (jahoti@tilde.team)
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+document.documentElement.style.visibility = 'visible';
+document.documentElement.style.opacity = '100'; \ No newline at end of file
diff --git a/content/sstack_overflow/index.json b/content/sstack_overflow/index.json
new file mode 100644
index 0000000..d954064
--- /dev/null
+++ b/content/sstack_overflow/index.json
@@ -0,0 +1,6 @@
+{
+"type" : "script",
+"name" : "stack overflow",
+"sha256" : "aee03e534fbac5e505194c784cd6d7bfdad63dd4e9bea0df7448352541a65e73",
+"location" : "stack_overflow.js"
+} \ No newline at end of file
diff --git a/content/sstack_overflow/stack_overflow.js b/content/sstack_overflow/stack_overflow.js
new file mode 100644
index 0000000..22849bc
--- /dev/null
+++ b/content/sstack_overflow/stack_overflow.js
@@ -0,0 +1,18 @@
+/*
+ Copyright © 2021 jahoti (jahoti@tilde.team)
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+const jcb = document.querySelector('.js-consent-banner');
+document.querySelector('.js-accept-cookies').onclick = e => jcb.parentNode.removeChild(jcb); \ No newline at end of file
diff --git a/content/sstallman.org/index.json b/content/sstallman.org/index.json
new file mode 100644
index 0000000..20f664c
--- /dev/null
+++ b/content/sstallman.org/index.json
@@ -0,0 +1,6 @@
+{
+"type" : "script",
+"name" : "stallman.org",
+"sha256" : "d3c5ce2e1add15093f5630171a0a80d6f5f3f62d50d12d797900a074a4b8962a",
+"location" : "stallman.org.js"
+} \ No newline at end of file
diff --git a/content/sstallman.org/stallman.org.js b/content/sstallman.org/stallman.org.js
new file mode 100644
index 0000000..f9f0e6b
--- /dev/null
+++ b/content/sstallman.org/stallman.org.js
@@ -0,0 +1,91 @@
+/*
+ Copyright © 2021 jahoti (jahoti@tilde.team)
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+var div1 = document.querySelector('.column1'),
+ div2 = document.querySelector('.column2'),
+ div3 = document.querySelector('.column3'),
+ rest = document.querySelector('.rest'),
+ head = document.body;
+
+head.removeChild(div1);
+head.removeChild(div2);
+head.removeChild(div3);
+head.removeChild(rest);
+
+var wrapper, chaseHeader = div1.querySelector('#urgent');
+var urgent = chaseHeader.parentNode.nextElementSibling;
+chaseHeader.parentNode.removeChild(chaseHeader);
+urgent.parentNode.removeChild(urgent);
+
+var chaseHeader = div1.querySelector('#oughttobe');
+var oughttobe = chaseHeader.parentNode.nextElementSibling;
+var oughttobe_more = oughttobe.nextElementSibling;
+chaseHeader.parentNode.removeChild(chaseHeader);
+oughttobe.parentNode.removeChild(oughttobe)
+oughttobe_more.parentNode.removeChild(oughttobe_more)
+
+div1.style.width = '100%';
+
+var polnotes = div2.querySelector('iframe');
+polnotes.parentNode.removeChild(polnotes);
+
+var trailing = ['More'];
+var current, text, node;
+for (var child of rest.children) if (child.tagName === 'HR') chaseHeader = child;
+while (node = rest.firstChild) {
+ rest.removeChild(node);
+
+ if (node === chaseHeader) text = 'Footer';
+ else if (node.tagName === 'HR') continue;
+ else if (/H\d/.test(node.tagName)) text = '* ' + node.textContent.trim();
+
+ if (text) {
+ if (current && !current.children.length) trailing[trailing.length - 1].splice(1, 1);
+
+ if (text === '* Media/Press/Bios') {
+ text = current = undefined;
+ continue;
+ }
+
+ current = document.createElement('div');
+ if (node.children.length && node.firstElementChild.tagName === 'A' && !node.firstElementChild.href.startsWith('#')) {
+ trailing.push([text, current, node.firstElementChild.href]);
+ }
+ else trailing.push([text, current]);
+
+ text = undefined;
+ }
+ else current && current.append(node);
+}
+
+
+// Build the nav index, and then render the page
+
+Sparse([
+ 'stallman.org',
+ ['Home', urgent, polnotes],
+ ['* Urgent action items', urgent],
+ ['* Political Notes', polnotes, div2.firstElementChild.querySelector('a').href],
+ ['There Ought to Be a Law', oughttobe, oughttobe_more.href],
+ ['Media/Press/Bios', 'https://stallman.org/media.html']
+].concat(
+ trailing
+).concat([
+ ['Miscellaneous', div1, div2],
+ 'Miscellaneous',
+ ['* Misc. 1', div3],
+ ['* Misc. 2', head]
+])); \ No newline at end of file
diff --git a/content/ssumofus_sign_petition/index.json b/content/ssumofus_sign_petition/index.json
new file mode 100644
index 0000000..7828329
--- /dev/null
+++ b/content/ssumofus_sign_petition/index.json
@@ -0,0 +1,6 @@
+{
+"type" : "script",
+"name" : "sumofus (sign petition)",
+"sha256" : "5638c4c9caf3dc5f92d0279d34bb955138b016f973a6038720994e00ca110a93",
+"location" : "sign_petition.js"
+}
diff --git a/content/ssumofus_sign_petition/sign_petition.js b/content/ssumofus_sign_petition/sign_petition.js
new file mode 100644
index 0000000..c442d05
--- /dev/null
+++ b/content/ssumofus_sign_petition/sign_petition.js
@@ -0,0 +1,54 @@
+/*
+ Copyright © 2021 jahoti (jahoti@tilde.team)
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+function submitFormItem() {
+ var name, val, queryString = '', xhr = new content.XMLHttpRequest();
+ for (var formItem of this.querySelectorAll('select, input:not([type="radio"]):not([type="checkbox"])' +
+ ':not([type="submit"]):not([type="reset"])')) {
+ queryString += (queryString && '&') + formItem.name + '=' + encodeURIComponent(formItem.value);
+ }
+
+ xhr.onreadystatechange = function () {
+ if (this.readyState === 4) {
+ if (this.status === 200) location.href = JSON.parse(this.responseText).follow_up_url;
+ else if (this.status === 422) {
+ var failMessage = [], response = JSON.parse(this.responseText);
+ for (field in response.errors) for (error of response.errors[field]) {
+ failMessage.push('Field "' + field + '" ' + error);
+ }
+ alert(failMessage.join('\n'));
+ }
+ else alert('Submission failed: response code ' + this.status);
+ }
+ }
+
+ xhr.open('POST', this.action, true); // Manually add the domain, as it's not properly handled in extensions
+ xhr.setRequestHeader('X-CSRF-Token', csrf);
+ xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
+ xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
+ xhr.send(queryString);
+ return false;
+}
+
+// Apply CSS as necessary
+if (notice = document.querySelector('#petition-bar-main > span')) notice.style.display = 'none'; // Hide the totally mistaken (even without this extension) anti-anti-JS warning
+document.querySelector('.script-dependent').style.display = 'block';
+document.querySelector('.button-wrapper').style.position = 'static'; // Stop the "submit" button obscuring the form
+
+
+
+csrf = document.querySelector('meta[name="csrf-token"]').content
+for (var button of document.querySelectorAll('button[type="submit"].button.action-form__submit-button')) button.form.onsubmit = submitFormItem; \ No newline at end of file
diff --git a/content/sworldcat_library_holdings/index.json b/content/sworldcat_library_holdings/index.json
new file mode 100644
index 0000000..f2f3a39
--- /dev/null
+++ b/content/sworldcat_library_holdings/index.json
@@ -0,0 +1,6 @@
+{
+"type" : "script",
+"name" : "worldcat (library holdings)",
+"sha256" : "b1ffa6162dc9f68e2bfb1d4b6adaeac850c23bcfcc86162a2d4450aecc22f7fd",
+"location" : "library_holdings.js"
+}
diff --git a/content/sworldcat_library_holdings/library_holdings.js b/content/sworldcat_library_holdings/library_holdings.js
new file mode 100644
index 0000000..3a30b2b
--- /dev/null
+++ b/content/sworldcat_library_holdings/library_holdings.js
@@ -0,0 +1,65 @@
+/*
+ Copyright © 2021 jahoti (jahoti@tilde.team)
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+var pathParts = location.pathname.split('/'), itemRef = pathParts[pathParts.length - 1];
+
+// Generate a function which, when invoked, loads the catalog holdings starting at i (one-indexed) focused on loc
+function generateGoTo(i, set_loc) {
+ return function () {
+ ; // If this is a new search, "set_loc" won't be set; set it
+ var xhr = new content.XMLHttpRequest(), loc = set_loc || encodeURIComponent(locInput.value);
+ xhr.onreadystatechange = function () {
+ if (this.readyState === 4) {
+ if (this.status === 200) {
+ retrieved.innerHTML = this.responseText;
+
+ var i, node = document.getElementById('libslocator');
+ node.parentNode.removeChild(node);
+ for (node of retrieved.querySelectorAll('a[href^="javascript:findLibs(\'\', "]')) {
+ i = parseInt(node.href.split(',', 2)[1]);
+ node.onclick = generateGoTo(i, loc);
+ }
+ }
+ else alert('Search failed: response code ' + this.status);
+ }
+ }
+
+ xhr.open('GET', 'https://www.worldcat.org/wcpa/servlet/org.oclc.lac.ui.ajax.ServiceServlet?wcoclcnum=' + itemRef + '&start_holding='
+ + i + '&serviceCommand=holdingsdata&loc=' + loc, true);
+ xhr.send();
+ return false; // Make sure the browser doesn't try to submit any holding form
+ };
+}
+
+
+var retriever = document.querySelector('.retrieving'), retrieved = document.getElementById('donelocator');
+
+var locForm = document.createElement('form'), locLabel = document.createElement('label'), locInput = document.createElement('input'),
+ locSubmit = document.createElement('input');
+
+locForm.appendChild(locLabel);
+locForm.appendChild(locInput);
+locForm.appendChild(locSubmit);
+
+locInput.name = locLabel.htmlFor = 'cat_location';
+locInput.type = 'text';
+locInput.required = 'yes';
+locLabel.innerText = 'Find copies closest to: ';
+locSubmit.value = 'Go';
+locSubmit.type = 'submit';
+locForm.onsubmit = generateGoTo(1);
+
+retriever.parentNode.replaceChild(locForm, retriever); \ No newline at end of file