From 25a5523361a0af110d764a38774d19ca8cf38d11 Mon Sep 17 00:00:00 2001 From: StaticPH <7786502+StaticPH@users.noreply.github.com> Date: Sat, 12 Jul 2025 19:33:44 -0400 Subject: [PATCH 01/38] Add stackexchange_wide_mode.user.js; removes the width restrictions on the main content part of question pages across stackexchange network sites. --- README.md | 11 +++++ build/data_files/main_script_manifest.json | 11 +++++ stackexchange_wide_mode.user.js | 52 ++++++++++++++++++++++ 3 files changed, 74 insertions(+) create mode 100644 stackexchange_wide_mode.user.js diff --git a/README.md b/README.md index d66bccd..27c4057 100644 --- a/README.md +++ b/README.md @@ -72,6 +72,7 @@ To add a script: | [Softpedia Improvements](#SFTPD) | [install][raw-SFTPD] | N/A | :heavy_check_mark: | MIT | Jan 4, 2024 | Jan 4, 2024 | | [Sublime Package Control Description in Title](#SPCDIT) | [install][raw-SPCDIT] | N/A | :heavy_check_mark: | MIT | Jan 23, 2024 | Jan 23, 2024 | | [YouTrack Use Standard Scrollbar](#YUSS) | [install][raw-YUSS] | N/A | :heavy_check_mark: | MIT | Aug 22, 2024 | Aug 22, 2024 | +| [StackExchange Wide Mode](#SEWM) | [install][raw-SEWM] | N/A | :heavy_check_mark: | MIT | Jun 20, 2024 | Jun 20, 2024 | @@ -461,6 +462,15 @@ Use the browser's regular scrollbar style on JetBrains' YouTrack pages [[Install]][raw-YUSS] +--- + + +### StackExchange Wide Mode + +StackExchange sites should take better advantage of the horizontal screen space, particularly on question pages. This removes the width restrictions on the main content part of those pages. + +[[Install]][raw-SEWM] + --- ## Legacy Workaround Scripts @@ -595,6 +605,7 @@ Format END --> [raw-SFTPD]: /softpedia_improvements.user.js?raw=1 [raw-SPCDIT]: /sublime_package_control_description_in_title.user.js?raw=1 [raw-YUSS]: /youtrack_use_standard_scrollbar.user.js?raw=1 +[raw-SEWM]: /stackexchange_wide_mode.user.js?raw=1 [raw-DFSF]: /legacy_browser_workarounds/discourse_forum_scroll_fixer.user.js?raw=1 diff --git a/build/data_files/main_script_manifest.json b/build/data_files/main_script_manifest.json index c2c69f6..01c62b4 100644 --- a/build/data_files/main_script_manifest.json +++ b/build/data_files/main_script_manifest.json @@ -406,6 +406,17 @@ "updated": "Aug 22, 2024", "desc": "Use the browser's regular scrollbar style on JetBrains' YouTrack pages", "version": "1.0.0" + }, + { + "name": "StackExchange Wide Mode", + "anchorString": "SEWM", + "path": "/stackexchange_wide_mode.user.js", + "license": "MIT", + "autoUpdates": true, + "created": "Jun 20, 2024", + "updated": "Jun 20, 2024", + "desc": "StackExchange sites should take better advantage of the horizontal screen space, particularly on question pages. This removes the width restrictions on the main content part of those pages.", + "version": "1.0.0" } ] } \ No newline at end of file diff --git a/stackexchange_wide_mode.user.js b/stackexchange_wide_mode.user.js new file mode 100644 index 0000000..9d0268f --- /dev/null +++ b/stackexchange_wide_mode.user.js @@ -0,0 +1,52 @@ +// ==UserScript== +// @name StackExchange Wide Mode +// @namespace https://github.com/StaticPH +// @match https://*.stackexchange.com/* +// @match https://askubuntu.com/* +// @match https://mathoverflow.com/* +// @match https://serverfault.com/* +// @match https://stackapps.com/* +// @match https://stackexchange.com/* +// @match https://stackoverflow.com/* +// @match https://superuser.com/* +// @version 1.0.0 +// @createdAt 6/20/2024 +// @author StaticPH +// @description StackExchange sites should take better advantage of the horizontal screen space, particularly on question pages. This removes the width restrictions on the main content part of those pages. +// @license MIT +// @updateURL https://raw.githubusercontent.com/StaticPH/Userscripts/master/stackexchange_wide_mode.user.js +// @downloadURL https://raw.githubusercontent.com/StaticPH/Userscripts/master/stackexchange_wide_mode.user.js +// @homepageURL https://github.com/StaticPH/UserScripts +// @supportURL https://github.com/StaticPH/UserScripts/issues +// @icon https://cdn.sstatic.net/sites/stackexchange/Img/favicon.ico +// @grant GM.addStyle +// @grant GM_addStyle +// @noframes +// @run-at document-end +// ==/UserScript== + +(function(){ + 'use strict'; + + // Prefer asychronous Greasemonkey4-API GM.addStyle, but allow use of GM_addStyle as a fallback if necessary. + if (typeof GM == 'undefined'){ + this.GM = {}; + } + if (typeof GM['addStyle'] == 'undefined'){ + console.log('GM.addStyle is not defined. Falling back to GM_addStyle Promise.'); + GM['addStyle'] = function(...args){ + return new Promise((onResolve, onReject) => { + try{ onResolve(GM_addStyle.apply(this, args)); } + catch(err){ onReject(err); } + }); + } + } + + GM.addStyle(` + /* Page main content element */ + body > .container:not(.sillyPriorityBump){ max-width: unset; } + + /* body > .container > #content is the child element that actually contains all the questions and answers, without either sidebar. */ + body > .container > #content:not(.sillyPriorityBump){ max-width: unset; } + `); +})(); \ No newline at end of file From 6c8a404992c3a445bb1223f3f3ccbcdbf0dc9589 Mon Sep 17 00:00:00 2001 From: StaticPH <7786502+StaticPH@users.noreply.github.com> Date: Sat, 12 Jul 2025 19:35:58 -0400 Subject: [PATCH 02/38] Add help output for the shell script that generates updated the readme and manifest files. --- build/run.sh | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/build/run.sh b/build/run.sh index 62dba70..8505591 100644 --- a/build/run.sh +++ b/build/run.sh @@ -1,15 +1,31 @@ #! /bin/sh +# To "register" a new userscript, add a new object with `path` and `anchorString` values to the `scripts` array in `main_script_manifest.json`; the updater python script will do the rest. +case "$1" in + -h|--help) + printf '%s\n' \ + 'This script is used to generate updated versions of readme and manifest files.' \ + 'To "register" a new userscript for inclusion in the readme, add a new' \ + 'object with both `path` and `anchorString` values to the `scripts` array' \ + 'in `main_script_manifest.json` before running this script.' \ + 'Updated manifest and readme files will be created in the `build` directory,' \ + 'and named `newdata.json` and `output.md`, respectively.' \ + 'They can be manually copied over the originals.' + exit 0 + ;; +esac + repoRoot="$(git rev-parse --show-toplevel)" dataDir="${repoRoot}/build/data_files" templateDir="${repoRoot}/build/templates" -# To "register" a new userscript, add a new object with `path` and `anchorString` values to the `scripts` array in `main_script_manifest.json`; the updater python script will do the rest. +pushd "${repoRoot}/build" >/dev/null 2>&1 TEST_READER=1 python3 "${repoRoot}/build/update_script_manifest.py" jq -rs 'reduce .[] as $item ({}; . * $item)' "${dataDir}/general_url_references.json" "${dataDir}/legacy_scripts.json" newdata.json | \ minijinja-cli --format json "${templateDir}/primary_template.md.j2" - > output.md +popd >/dev/null 2>&1 ################ ################ # TODO: From d5bfb0b16c826f5c44f5ca65e18b1b434c26e6ed Mon Sep 17 00:00:00 2001 From: StaticPH <7786502+StaticPH@users.noreply.github.com> Date: Sat, 12 Jul 2025 19:52:49 -0400 Subject: [PATCH 03/38] Add google_search_footer_privacy.user.js; Hide the user's location and email from the page footer when using Google search. --- README.md | 11 ++++ build/data_files/main_script_manifest.json | 11 ++++ google_search_footer_privacy.user.js | 64 ++++++++++++++++++++++ 3 files changed, 86 insertions(+) create mode 100644 google_search_footer_privacy.user.js diff --git a/README.md b/README.md index 27c4057..158d8e2 100644 --- a/README.md +++ b/README.md @@ -55,6 +55,7 @@ To add a script: | [Wider Google Form Fields](#WGFF) | [install][raw-WGFF] | N/A | :heavy_check_mark: | MIT | Sep 30, 2021 | Aug 19, 2022 | | [Correct Google Form Correctness](#GFCC) | [install][raw-GFCC] | N/A | :heavy_check_mark: | MIT | Nov 9, 2021 | Nov 9, 2021 | | [Google Search Lean Query Updates](#GSLQU) | [install][raw-GSLQU] | N/A | :heavy_check_mark: | MIT | Jul 12, 2023 | Sep 28, 2024 | +| [Google Search Footer Privacy](#GSFP) | [install][raw-GSFP] | N/A | :heavy_check_mark: | MIT | Dec 30, 2023 | Dec 30, 2023 | | [Roll20 Nonscrolling Number Fields](#RNNF) | [install][raw-RNNF] | N/A | :heavy_check_mark: | MIT | Jan 23, 2021 | Apr 5, 2021 | | [Bypass Blogspot's Blogger IFrame](#BBBI) | [install][raw-BBBI] | N/A | :heavy_check_mark: | MIT | Jun 2, 2021 | May 1, 2022 | | [Foxaholic Fixes](#FoxF) | [install][raw-FoxF] | N/A | :heavy_check_mark: | MIT | Jun 2, 2021 | Aug 27, 2021 | @@ -295,6 +296,15 @@ Proof-of-concept: Prevent modifications to the Google search query in the on-pag --- + +### Google Search Footer Privacy + +Hide the "Location" part of the footer on Google Search results, and don't show the email address of the current user. + +[[Install]][raw-GSFP] + +--- + ### Roll20 Nonscrolling Number Fields @@ -588,6 +598,7 @@ Format END --> [raw-WGFF]: /wider_google_form_fields.user.js?raw=1 [raw-GFCC]: /correct_google_form_correctness.user.js?raw=1 [raw-GSLQU]: /google_search_lean_query_updates.user.js?raw=1 +[raw-GSFP]: /google_search_footer_privacy.user.js?raw=1 [raw-RNNF]: /roll20_character_sheet_no_scrolling_number_fields.user.js?raw=1 [raw-BBBI]: /bypass_blogspots_blogger_iframe.user.js?raw=1 [raw-FoxF]: /foxaholic_fixes.user.js?raw=1 diff --git a/build/data_files/main_script_manifest.json b/build/data_files/main_script_manifest.json index 01c62b4..ddb9018 100644 --- a/build/data_files/main_script_manifest.json +++ b/build/data_files/main_script_manifest.json @@ -220,6 +220,17 @@ "desc": "Proof-of-concept: Prevent modifications to the Google search query in the on-page search bar from inserting a bunch of unwanted parameters into the resulting URL.", "version": "1.3.0" }, + { + "name": "Google Search Footer Privacy", + "anchorString": "GSFP", + "path": "/google_search_footer_privacy.user.js", + "license": "MIT", + "autoUpdates": true, + "created": "Dec 30, 2023", + "updated": "Dec 30, 2023", + "desc": "Hide the \"Location\" part of the footer on Google Search results, and don't show the email address of the current user.", + "version": "1.1.0" + }, { "name": "Roll20 Nonscrolling Number Fields", "anchorString": "RNNF", diff --git a/google_search_footer_privacy.user.js b/google_search_footer_privacy.user.js new file mode 100644 index 0000000..0eac588 --- /dev/null +++ b/google_search_footer_privacy.user.js @@ -0,0 +1,64 @@ +// ==UserScript== +// @name Google Search Footer Privacy +// @namespace https://github.com/StaticPH +// @match *://google.com/search +// @match *://*.google.com/search +// @version 1.1.0 +// @createdAt 12/30/2023, 6:16:41 PM +// @author StaticPH +// @description Hide the "Location" part of the footer on Google Search results, and don't show the email address of the current user. +// @license MIT +// @updateURL https://raw.githubusercontent.com/StaticPH/Userscripts/master/google_search_footer_privacy.user.js +// @downloadURL https://raw.githubusercontent.com/StaticPH/Userscripts/master/google_search_footer_privacy.user.js +// @homepageURL https://github.com/StaticPH/UserScripts +// @supportURL https://github.com/StaticPH/UserScripts/issues +// @icon https://www.gstatic.com/images/branding/googleg/1x/googleg_standard_color_48dp.png +// @grant GM_addStyle +// @grant GM.addStyle +// @noframes +// @run-at document-end +// ==/UserScript== + +(function(){ + "use strict"; + + // Prefer asychronous Greasemonkey4-API GM.addStyle, but allow use of GM_addStyle as a fallback if necessary. + if (typeof GM == 'undefined'){ + this.GM = {}; + } + if (typeof GM['addStyle'] == 'undefined'){ + console.log('GM.addStyle is not defined. Falling back to GM_addStyle Promise.'); + GM['addStyle'] = function(...args){ + return new Promise((onResolve, onReject) => { + try{ onResolve(GM_addStyle.apply(this, args)); } + catch(err){ onReject(err); } + }); + } + } + + GM.addStyle(` + /* Hide email address of currently logged in user, if applicable */ + /* #EOlPnc > :nth-last-child(2):not(:first-child) > :first-child:not(:last-child), */ + /* Hide Location */ + #EOlPnc > .Srfpq, .dfB0uf { + display: none !important; + } + + /* Hide email address of currently logged in user, AND hide "Sign Out" link. Also hides "Sign In" link if not logged in. */ + #EOlPnc > :nth-last-child(2):not(:first-child) > span { + font-size: 0; + } + /* Unhide JUST the "Sign In" or "Sign Out" link. + * Instead of "visibility: hidden" or "opacity: 0" above, which would keep the layout intact, using "font-size: 0" will + * allow child elements with a non-zero "font-size" to realign, which re-centers the "Sign Out" link that is normally offset + * due to the presence of the email. Furthermore, this method allows hiding text nodes, such as the " - " that would + * otherwise be placed between the email and the "Sign Out" link. + * The caveat to this is that simply setting "font-size" to initial, unset, or inherit is insufficient to show specific elements + * again with their previous size, if that size is different from "font-size: initial"; in such a case, the size needs to be + * hard-coded. + */ + #EOlPnc > :nth-last-child(2):not(:first-child) > span > a { + font-size: 14px; + } + `); +})(); From e7e9030638f95439bc71f7092558b70756c3f786 Mon Sep 17 00:00:00 2001 From: StaticPH <7786502+StaticPH@users.noreply.github.com> Date: Thu, 2 May 2024 17:33:00 -0400 Subject: [PATCH 04/38] Add new userscript: izzyondroid_description_in_title.user.js --- izzyondroid_description_in_title.user.js | 29 ++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 izzyondroid_description_in_title.user.js diff --git a/izzyondroid_description_in_title.user.js b/izzyondroid_description_in_title.user.js new file mode 100644 index 0000000..6b7459f --- /dev/null +++ b/izzyondroid_description_in_title.user.js @@ -0,0 +1,29 @@ +// ==UserScript== +// @name Better IzzyOnDroid App Titles +// @namespace https://github.com/StaticPH +// @match https://apt.izzysoft.de/fdroid/index/apk/* +// @version 1.0.0 +// @createdAt 5/2/2024, 5:33:04 PM +// @author StaticPH +// @description Adds app description to page titles where possible. +// @license MIT +// @updateURL https://raw.githubusercontent.com/StaticPH/Userscripts/master/izzyondroid_description_in_title.user.js +// @downloadURL https://raw.githubusercontent.com/StaticPH/Userscripts/master/izzyondroid_description_in_title.user.js +// @homepageURL https://github.com/StaticPH/UserScripts +// @supportURL https://github.com/StaticPH/UserScripts/issues +// @icon https://apt.izzysoft.de/fdroid/izzy-on-droid.png +// @grant none +// @run-at document-end +// @noframes +// ==/UserScript== + +(function(){ + "use strict"; + + const parts = document.title.split('- IzzyOnDroid'); + const tail = parts.pop(); + let summary = document.getElementById('summary').textContent; + summary = summary[0].toLocaleUpperCase() + summary.slice(1); + parts.push('- ' + summary + ' | IzzyOnDroid' + tail); + document.title = parts.join(''); +})(); From 0e7bfe12aeab1089d566c8a5ac7410149efcbca2 Mon Sep 17 00:00:00 2001 From: StaticPH <7786502+StaticPH@users.noreply.github.com> Date: Thu, 15 Aug 2024 22:34:00 -0400 Subject: [PATCH 05/38] Update url match patterns for izzyondroid_description_in_title.user.js --- izzyondroid_description_in_title.user.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/izzyondroid_description_in_title.user.js b/izzyondroid_description_in_title.user.js index 6b7459f..ef1e519 100644 --- a/izzyondroid_description_in_title.user.js +++ b/izzyondroid_description_in_title.user.js @@ -1,8 +1,9 @@ // ==UserScript== // @name Better IzzyOnDroid App Titles // @namespace https://github.com/StaticPH -// @match https://apt.izzysoft.de/fdroid/index/apk/* -// @version 1.0.0 +// @match *://apt.izzysoft.de/fdroid/index/apk/* +// @match *://android.izzysoft.de/repo/apk/* +// @version 1.0.1 // @createdAt 5/2/2024, 5:33:04 PM // @author StaticPH // @description Adds app description to page titles where possible. From a0934b30be755ff48c653c73fc5e32bb1a4cbd7e Mon Sep 17 00:00:00 2001 From: StaticPH <7786502+StaticPH@users.noreply.github.com> Date: Thu, 22 May 2025 23:38:00 -0400 Subject: [PATCH 06/38] Update izzyondroid_description_in_title.user.js --- izzyondroid_description_in_title.user.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/izzyondroid_description_in_title.user.js b/izzyondroid_description_in_title.user.js index ef1e519..19ff31c 100644 --- a/izzyondroid_description_in_title.user.js +++ b/izzyondroid_description_in_title.user.js @@ -3,7 +3,7 @@ // @namespace https://github.com/StaticPH // @match *://apt.izzysoft.de/fdroid/index/apk/* // @match *://android.izzysoft.de/repo/apk/* -// @version 1.0.1 +// @version 1.1.0 // @createdAt 5/2/2024, 5:33:04 PM // @author StaticPH // @description Adds app description to page titles where possible. @@ -27,4 +27,8 @@ summary = summary[0].toLocaleUpperCase() + summary.slice(1); parts.push('- ' + summary + ' | IzzyOnDroid' + tail); document.title = parts.join(''); + + // Add convenient link to alternate between the two places to view app details. + const anchorUrl = 'https://' + (document.location.host.startsWith('apt') ? 'android.izzysoft.de/repo' : 'apt.izzysoft.de/fdroid/index') + '/apk/' + document.location.pathname.split('/apk/').pop(); + document.querySelector('#appdetails > h2').insertAdjacentHTML('beforeBegin', '(Switch Site View)
'); })(); From a4489e8991eab53974bd4de242aed1688ff11feb Mon Sep 17 00:00:00 2001 From: StaticPH <7786502+StaticPH@users.noreply.github.com> Date: Mon, 28 Jul 2025 20:58:17 -0400 Subject: [PATCH 07/38] Add izzyondroid_description_in_title.user.js to manifest and update readme. --- README.md | 11 +++++++++++ build/data_files/main_script_manifest.json | 11 +++++++++++ 2 files changed, 22 insertions(+) diff --git a/README.md b/README.md index 158d8e2..2c2269b 100644 --- a/README.md +++ b/README.md @@ -74,6 +74,7 @@ To add a script: | [Sublime Package Control Description in Title](#SPCDIT) | [install][raw-SPCDIT] | N/A | :heavy_check_mark: | MIT | Jan 23, 2024 | Jan 23, 2024 | | [YouTrack Use Standard Scrollbar](#YUSS) | [install][raw-YUSS] | N/A | :heavy_check_mark: | MIT | Aug 22, 2024 | Aug 22, 2024 | | [StackExchange Wide Mode](#SEWM) | [install][raw-SEWM] | N/A | :heavy_check_mark: | MIT | Jun 20, 2024 | Jun 20, 2024 | +| [Better IzzyOnDroid App Titles](#BIAT) | [install][raw-BIAT] | N/A | :heavy_check_mark: | MIT | May 2, 2024 | May 22, 2025 | @@ -481,6 +482,15 @@ StackExchange sites should take better advantage of the horizontal screen space, [[Install]][raw-SEWM] +--- + + +### Better IzzyOnDroid App Titles + +Adds app description to page titles where possible. + +[[Install]][raw-BIAT] + --- ## Legacy Workaround Scripts @@ -617,6 +627,7 @@ Format END --> [raw-SPCDIT]: /sublime_package_control_description_in_title.user.js?raw=1 [raw-YUSS]: /youtrack_use_standard_scrollbar.user.js?raw=1 [raw-SEWM]: /stackexchange_wide_mode.user.js?raw=1 +[raw-BIAT]: /izzyondroid_description_in_title.user.js?raw=1 [raw-DFSF]: /legacy_browser_workarounds/discourse_forum_scroll_fixer.user.js?raw=1 diff --git a/build/data_files/main_script_manifest.json b/build/data_files/main_script_manifest.json index ddb9018..e2346ba 100644 --- a/build/data_files/main_script_manifest.json +++ b/build/data_files/main_script_manifest.json @@ -428,6 +428,17 @@ "updated": "Jun 20, 2024", "desc": "StackExchange sites should take better advantage of the horizontal screen space, particularly on question pages. This removes the width restrictions on the main content part of those pages.", "version": "1.0.0" + }, + { + "name": "Better IzzyOnDroid App Titles", + "anchorString": "BIAT", + "path": "/izzyondroid_description_in_title.user.js", + "license": "MIT", + "autoUpdates": true, + "created": "May 2, 2024", + "updated": "May 22, 2025", + "desc": "Adds app description to page titles where possible.", + "version": "1.0.0" } ] } \ No newline at end of file From 11755ab297f0b45a5cc463d832a9e9da51371e3b Mon Sep 17 00:00:00 2001 From: StaticPH <7786502+StaticPH@users.noreply.github.com> Date: Sat, 4 Oct 2025 21:22:56 -0400 Subject: [PATCH 08/38] Fix mismatched version number in manifest --- build/data_files/main_script_manifest.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/data_files/main_script_manifest.json b/build/data_files/main_script_manifest.json index e2346ba..5900003 100644 --- a/build/data_files/main_script_manifest.json +++ b/build/data_files/main_script_manifest.json @@ -438,7 +438,7 @@ "created": "May 2, 2024", "updated": "May 22, 2025", "desc": "Adds app description to page titles where possible.", - "version": "1.0.0" + "version": "1.1.0" } ] } \ No newline at end of file From a8fbdaf50b4e95b5dbfa2503190fa31c1574ae06 Mon Sep 17 00:00:00 2001 From: StaticPH <7786502+StaticPH@users.noreply.github.com> Date: Sat, 4 Oct 2025 21:33:38 -0400 Subject: [PATCH 09/38] Minor edits to README generation. --- README.md | 38 ++++-------------------- build/templates/link_refs.md.j2 | 4 +-- build/templates/primary_template.md.j2 | 10 +++++-- build/templates/userscript_manager.md.j2 | 2 ++ build/update_script_manifest.py | 4 +-- 5 files changed, 19 insertions(+), 39 deletions(-) diff --git a/README.md b/README.md index 2c2269b..37a3ecb 100644 --- a/README.md +++ b/README.md @@ -2,17 +2,14 @@ [![HitCount](http://hits.dwyl.com/StaticPH/Userscripts.svg)](http://hits.dwyl.com/StaticPH/UserScripts)
Unless otherwise specified in their description, all userscripts have been tested with ViolentMonkey on Chromium 72 or later and on Vivaldi 3.6 or later. They may also work with GreaseMonkey, TamperMonkey, or on other browsers. +I try to specifically write code that will run on these targets, _regardless of the extent to which the page(s) they run on will remain functional under those conditions._ ### Get ViolentMonkey for your browser * [Firefox][ViolentMonkey_Firefox] * [Google Chrome and (most) Chromium-based browsers][ViolentMonkey_Chrome] * [Microsoft Edge (which people apparently use)][ViolentMonkey_Edge] * Alternatively, install ViolentMonkey from its [source][ViolentMonkey_src] - + ### Other * If you use [Pale Moon](https://www.palemoon.org), [Basilisk](https://www.basilisk-browser.org), or [K-Meleon](http://kmeleonbrowser.org), try [this fork of GreaseMonkey v3][GreaseMonkey_v3_Moonchild].
Some scripts will likely require modifications for this to work; if you do this yourself, please submit a pull request so that others may also benefit. @@ -28,10 +25,7 @@ One example of such a scenario could be opening a Twitch.tv livestream from the --- To add a script: * Install a script directly from GitHub by clicking on the "install" link in the table below. - + | Userscript
Description | Direct
Install | Sites | Supports
Auto-Update | License | Created | Updated | |------------------------------------------------|:--------------------:|:-------------------:|:-----------------------:|:-------:|:----------:|:----------:| @@ -76,22 +70,11 @@ To add a script: | [StackExchange Wide Mode](#SEWM) | [install][raw-SEWM] | N/A | :heavy_check_mark: | MIT | Jun 20, 2024 | Jun 20, 2024 | | [Better IzzyOnDroid App Titles](#BIAT) | [install][raw-BIAT] | N/A | :heavy_check_mark: | MIT | May 2, 2024 | May 22, 2025 | - - + --- - - --- @@ -576,18 +559,7 @@ Additionally, I do occasionally take requests for simple scripts, so feel free t - + [raw-HYOA]: /hide_youtube_overlay_ads.user.js?raw=1 [raw-FYPBG]: /fix_youtube_player_bottom_gradient.user.js?raw=1 [raw-YCKP]: /youtube_channel_keyboard_protector.user.js?raw=1 diff --git a/build/templates/link_refs.md.j2 b/build/templates/link_refs.md.j2 index 38fe08a..cfdcef3 100644 --- a/build/templates/link_refs.md.j2 +++ b/build/templates/link_refs.md.j2 @@ -1,5 +1,5 @@ - +Format END --> #} {%- for script in scripts %} [raw-{{ script.anchorString}}]: {{ script.path }}?raw=1 {%- endfor %} diff --git a/build/templates/primary_template.md.j2 b/build/templates/primary_template.md.j2 index 848048e..0a2e9d6 100644 --- a/build/templates/primary_template.md.j2 +++ b/build/templates/primary_template.md.j2 @@ -2,6 +2,7 @@ [![HitCount](http://hits.dwyl.com/StaticPH/Userscripts.svg)](http://hits.dwyl.com/StaticPH/UserScripts)
Unless otherwise specified in their description, all userscripts have been tested with ViolentMonkey on Chromium 72 or later and on Vivaldi 3.6 or later. They may also work with GreaseMonkey, TamperMonkey, or on other browsers. +I try to specifically write code that will run on these targets, _regardless of the extent to which the page(s) they run on will remain functional under those conditions._ {% include "userscript_manager.md.j2" ignore missing %} @@ -16,10 +17,11 @@ One example of such a scenario could be opening a Twitch.tv livestream from the --- To add a script: * Install a script directly from GitHub by clicking on the "install" link in the table below. - +--> #} | Userscript
Description | Direct
Install | Sites | Supports
Auto-Update | License | Created | Updated | |------------------------------------------------|:--------------------:|:-------------------:|:-----------------------:|:-------:|:----------:|:----------:| @@ -29,11 +31,14 @@ To add a script: | [{{ script.name }}](#{{ script.anchorString }}) | [install][raw-{{ script.anchorString }}] | N/A | {{ ":heavy_check_mark:" if script.autoUpdates == true else script.autoUpdates }} | {{ script.license }} | {{ script.created }} | {{ script.updated|default(script.created) }} | {%- endfor %} +{# +#} --- +{# +#} --- {#- Script Details go here #} diff --git a/build/templates/userscript_manager.md.j2 b/build/templates/userscript_manager.md.j2 index 7392522..d91e1e2 100644 --- a/build/templates/userscript_manager.md.j2 +++ b/build/templates/userscript_manager.md.j2 @@ -3,11 +3,13 @@ * [Google Chrome and (most) Chromium-based browsers][ViolentMonkey_Chrome] * [Microsoft Edge (which people apparently use)][ViolentMonkey_Edge] * Alternatively, install ViolentMonkey from its [source][ViolentMonkey_src] +{# +#} ### Other * If you use [Pale Moon](https://www.palemoon.org), [Basilisk](https://www.basilisk-browser.org), or [K-Meleon](http://kmeleonbrowser.org), try [this fork of GreaseMonkey v3][GreaseMonkey_v3_Moonchild].
Some scripts will likely require modifications for this to work; if you do this yourself, please submit a pull request so that others may also benefit. \ No newline at end of file diff --git a/build/update_script_manifest.py b/build/update_script_manifest.py index 5cd69ba..b9cf401 100644 --- a/build/update_script_manifest.py +++ b/build/update_script_manifest.py @@ -29,7 +29,7 @@ def mayPrint(*args, **kwargs) -> None: #noqa: ARG001,ANN002,ANN003, RUF100 # pyr defaultFileEncoding = getpreferredencoding(False) or sys.getdefaultencoding() __dateOutputFmtStr = '%b %d, %Y' # ex: Sep 08, 2024 -scriptStartTime = datetime.datetime.utcnow() +scriptStartTime = datetime.datetime.now(datetime.timezone.utc) def fmtDateForDisplay(date: datetime.datetime) -> str: dateStr = date.astimezone(datetime.timezone.utc).strftime(__dateOutputFmtStr) # Use a space to left-pad single-digit days, rather than a zero @@ -143,7 +143,7 @@ class DataUpdater: _missingLicenseValue: str = 'No license found' _missingVersionValue: str = '0.1.0' - def __init__(self): #noqa: ARG002, RUF100 + def __init__(self) -> None: #noqa: ARG002, RUF100 self.dataFileContents: Dict[str, JSON_Value_Type] = {} ## Steps to use: From e2afa770c37599987476096bc5c0492b8b1231c4 Mon Sep 17 00:00:00 2001 From: StaticPH <7786502+StaticPH@users.noreply.github.com> Date: Tue, 21 Oct 2025 00:15:01 -0400 Subject: [PATCH 10/38] Add fdroid_app_description_in_title.user.js and update manifest and readme. --- README.md | 11 +++++++ build/data_files/main_script_manifest.json | 11 +++++++ fdroid_app_description_in_title.user.js | 37 ++++++++++++++++++++++ 3 files changed, 59 insertions(+) create mode 100644 fdroid_app_description_in_title.user.js diff --git a/README.md b/README.md index 37a3ecb..c92f8d7 100644 --- a/README.md +++ b/README.md @@ -69,6 +69,7 @@ To add a script: | [YouTrack Use Standard Scrollbar](#YUSS) | [install][raw-YUSS] | N/A | :heavy_check_mark: | MIT | Aug 22, 2024 | Aug 22, 2024 | | [StackExchange Wide Mode](#SEWM) | [install][raw-SEWM] | N/A | :heavy_check_mark: | MIT | Jun 20, 2024 | Jun 20, 2024 | | [Better IzzyOnDroid App Titles](#BIAT) | [install][raw-BIAT] | N/A | :heavy_check_mark: | MIT | May 2, 2024 | May 22, 2025 | +| [Better F-Droid App Titles](#BFAT) | [install][raw-BFAT] | N/A | :heavy_check_mark: | MIT | Aug 15, 2025 | Aug 15, 2025 | --- @@ -474,6 +475,15 @@ Adds app description to page titles where possible. [[Install]][raw-BIAT] +--- + + +### Better F-Droid App Titles + +Adds app description to page titles where possible. + +[[Install]][raw-BFAT] + --- ## Legacy Workaround Scripts @@ -600,6 +610,7 @@ Additionally, I do occasionally take requests for simple scripts, so feel free t [raw-YUSS]: /youtrack_use_standard_scrollbar.user.js?raw=1 [raw-SEWM]: /stackexchange_wide_mode.user.js?raw=1 [raw-BIAT]: /izzyondroid_description_in_title.user.js?raw=1 +[raw-BFAT]: /fdroid_app_description_in_title.user.js?raw=1 [raw-DFSF]: /legacy_browser_workarounds/discourse_forum_scroll_fixer.user.js?raw=1 diff --git a/build/data_files/main_script_manifest.json b/build/data_files/main_script_manifest.json index 5900003..95058a6 100644 --- a/build/data_files/main_script_manifest.json +++ b/build/data_files/main_script_manifest.json @@ -439,6 +439,17 @@ "updated": "May 22, 2025", "desc": "Adds app description to page titles where possible.", "version": "1.1.0" + }, + { + "name": "Better F-Droid App Titles", + "anchorString": "BFAT", + "path": "/fdroid_app_description_in_title.user.js", + "license": "MIT", + "autoUpdates": true, + "created": "Aug 15, 2025", + "updated": "Aug 15, 2025", + "desc": "Adds app description to page titles where possible.", + "version": "1.0.0" } ] } \ No newline at end of file diff --git a/fdroid_app_description_in_title.user.js b/fdroid_app_description_in_title.user.js new file mode 100644 index 0000000..c53a209 --- /dev/null +++ b/fdroid_app_description_in_title.user.js @@ -0,0 +1,37 @@ +// ==UserScript== +// @name Better F-Droid App Titles +// @namespace https://github.com/StaticPH +// @match https://f-droid.org/en/packages/* +// @version 1.0.0 +// @createdAt 8/15/2025, 11:47:05 PM +// @author StaticPH +// @description Adds app description to page titles where possible. +// @license MIT +// @updateURL https://raw.githubusercontent.com/StaticPH/Userscripts/master/fdroid_app_description_in_title.user.js +// @downloadURL https://raw.githubusercontent.com/StaticPH/Userscripts/master/fdroid_app_description_in_title.user.js +// @homepageURL https://github.com/StaticPH/UserScripts +// @supportURL https://github.com/StaticPH/UserScripts/issues +// @icon https://f-droid.org/assets/favicon-32x32_Dk3aeG3k_A20gYe5zAlPSBx_CEcpJaCI89K2X2z6CFY=.png +// @grant none +// @noframes +// @run-at document-end +// ==/UserScript== + +(function(){ + "use strict"; + + const trailer = ' | F-Droid - Free and Open Source Android App Repository'; + const pkgNameEle = document.querySelector('.package-name'); + const appID = document.location.pathname.replace(/.+\/packages\//, '').replace(/\/.*/,''); + const pkgName = pkgNameEle && pkgNameEle.textContent ? pkgNameEle.textContent.trim() : appID; + const pkgSummaryEle = document.querySelector('.package-summary'); + let pkgSummary; + if (pkgSummaryEle && pkgSummaryEle.textContent){ + pkgSummary = pkgSummaryEle.textContent.trim(); + } + else { + const pkgDescEle = document.querySelector('.package-description'); + pkgSummary = pkgDescEle && pkgDescEle.firstChild && pkgDescEle.firstChild.textContent && pkgDescEle.firstChild.textContent.split(/[.!]\W/)[0].trim() || 'ERROR'; + } + document.title = `${pkgName} | ${pkgSummary}${trailer}`; +})(); From 2cde5a778cd09429fdbd849f38e7392a1cc816ea Mon Sep 17 00:00:00 2001 From: StaticPH <7786502+StaticPH@users.noreply.github.com> Date: Tue, 9 Dec 2025 11:52:46 -0500 Subject: [PATCH 11/38] Add another domain to the list of discourse-based forums to fix scrolling on. --- .../discourse_forum_scroll_fixer.user.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/legacy_browser_workarounds/discourse_forum_scroll_fixer.user.js b/legacy_browser_workarounds/discourse_forum_scroll_fixer.user.js index 66488a7..b14ca11 100644 --- a/legacy_browser_workarounds/discourse_forum_scroll_fixer.user.js +++ b/legacy_browser_workarounds/discourse_forum_scroll_fixer.user.js @@ -15,8 +15,9 @@ // @match *://forum.manjaro.org/* // @match *://forums.comodo.com/* // @match *://forums.spongepowered.org/* +// @match *://meta.discourse.org/* // @match *://talk.restarters.net/* -// @version 1.0.3 +// @version 1.0.4 // @createdAt 6/29/2024, 6:24:11 PM // @author StaticPH // @description Fix for Discourse forums breaking the ability to scroll on browsers that are too old or are blocking some script or other. From 388e08d0c8362dfdc27b272e6cfb5bb57fceab4c Mon Sep 17 00:00:00 2001 From: StaticPH <7786502+StaticPH@users.noreply.github.com> Date: Tue, 9 Dec 2025 12:06:50 -0500 Subject: [PATCH 12/38] Add another legacy workaround script for github; this one tries to show comments on issues, because github is stupid and relies on React to extract them from JSON embedded into the page. --- README.md | 10 ++ build/data_files/legacy_scripts.json | 10 ++ ...hub_show_issue_comments_workaround.user.js | 116 ++++++++++++++++++ 3 files changed, 136 insertions(+) create mode 100644 legacy_browser_workarounds/github_show_issue_comments_workaround.user.js diff --git a/README.md b/README.md index c92f8d7..e649b11 100644 --- a/README.md +++ b/README.md @@ -540,6 +540,15 @@ Multiple fixes related to user-downloadable asset files on GitHub for users of l --- + +### GitHub Show Issue Comments Workaround + +Manually display comments on Github issues using the JSON that's already on the page, which totally doesn't need React to accomplish. + +[[Install]][raw-GSICW] + +--- + ### StackExchange Legacy Comments Expander @@ -618,6 +627,7 @@ Additionally, I do occasionally take requests for simple scripts, so feel free t [raw-GNAW]: /legacy_browser_workarounds/github_notifications_archive_workaround.user.js?raw=1 [raw-GCDW]: /legacy_browser_workarounds/github_collapsed_details_workaround.user.js?raw=1 [raw-GLRAW]: /legacy_browser_workarounds/github_lazy_release_asset_workaround.user.js?raw=1 +[raw-GSICW]: /legacy_browser_workarounds/github_show_issue_comments_workaround.user.js?raw=1 [raw-SELCE]: /legacy_browser_workarounds/stackexchange_legacy_comments_expander.user.js?raw=1 diff --git a/build/data_files/legacy_scripts.json b/build/data_files/legacy_scripts.json index e7441f4..32f83fb 100644 --- a/build/data_files/legacy_scripts.json +++ b/build/data_files/legacy_scripts.json @@ -50,6 +50,16 @@ "updated": "Mar 12, 2023", "desc": "Multiple fixes related to user-downloadable asset files on GitHub for users of legacy browsers.\n- Fetch asset list for releases, as the code that should already have been responsible for that is too modern, and is thus never even attempted on legacy browsers.\n- Fix the timestamps on the release page(s), most of which are within asset lists.\n- Slightly changes normal behavior by automatically showing __all__ assets for the first release on the page, whether that's two assets or fourty assets." }, + { + "name": "GitHub Show Issue Comments Workaround", + "anchorString": "GSICW", + "path": "/legacy_browser_workarounds/github_show_issue_comments_workaround.user.js", + "license": "MIT", + "autoUpdates": ":heavy_check_mark:", + "created": "Nov 10, 2025", + "updated": "Nov 10, 2025", + "desc": "Manually display comments on Github issues using the JSON that's already on the page, which totally doesn't need React to accomplish." + }, { "name": "StackExchange Legacy Comments Expander", "anchorString": "SELCE", diff --git a/legacy_browser_workarounds/github_show_issue_comments_workaround.user.js b/legacy_browser_workarounds/github_show_issue_comments_workaround.user.js new file mode 100644 index 0000000..adcbfee --- /dev/null +++ b/legacy_browser_workarounds/github_show_issue_comments_workaround.user.js @@ -0,0 +1,116 @@ +// ==UserScript== +// @name GitHub Issue Comments Legacy Workaround +// @namespace https://github.com/StaticPH +// @match https://github.com/*/*/issues/* +// @version 1.0.0 +// @createdAt 11/10/2025, 6:17:25 PM +// @author StaticPH +// @description Manually display comments on Github issues using the JSON that's already on the page, which totally doesn't need React to accomplish. +// @license MIT +// @updateURL https://raw.githubusercontent.com/StaticPH/Userscripts/master/legacy_browser_workarounds/github_show_issue_comments_workaround.user.js +// @downloadURL https://raw.githubusercontent.com/StaticPH/Userscripts/master/legacy_browser_workarounds/github_show_issue_comments_workaround.user.js +// @homepageURL https://github.com/StaticPH/UserScripts +// @supportURL https://github.com/StaticPH/UserScripts/issues +// @icon https://github.githubassets.com/pinned-octocat.svg +// @grant none +// @noframes +// @run-at document-idle +// ==/UserScript== + +(function(){ + "use strict"; + + const reactionToolbarHTML = `` + const fixedStyles = ` + .dShPvE { + display: flex; + flex-direction: column; + gap: 8px; + border-radius: 6px; + background-color: var(--bgColor-default,var(--color-canvas-default,#ffffff)); + transition: all 0.2s ease 0s; + border-width: 1px; + border-style: solid; + border-image: initial; + border-color: var(--borderColor-default,var(--color-border-default,#d0d7de)); + padding-top: 0px; + padding-bottom: 0px; + } + .bkHoaI{ opacity: 0; } + .PphTR { + background-color: var(--bgColor-muted,var(--color-canvas-subtle,#f6f8fa)); + border-top-left-radius: 6px; + border-top-right-radius: 6px; + border-bottom-style: solid; + border-color: var(--borderColor-default,var(--color-border-default,#d0d7de)); + border-bottom-width: 1px; + padding: 4px 4px 4px 16px; + }`; + + const dataEle = document.querySelector('[data-target="react-app.embeddedData"]'); + const embeddedData = JSON.parse(dataEle.textContent); + const responses = embeddedData.payload.preloadedQueries[0].result.data.repository.issue.frontTimelineItems.edges; + // Each *COMMENT* item in responseNodesData has the following properties (non-exhaustive): {author:{avatarUrl, id, login, name, profileUrl}, bodyHTML, bodyVersion, createdAt, databaseId, id, lastEditedAt, lastUserContentEdit:{editor:{id, login, url, __typename}, id}, reactionGroups, url} + const responseNodesData = responses.map(e => e.node); + + function buildCommentNode(commentNode){ + return `\t
+ ${commentNode.author.login} +
+
+
+
+
+
+
+

${commentNode.author.login} commented

+
+ @${commentNode.author.login} +
+ +
+
+
+
+
+
+
${commentNode.bodyHTML}
${reactionToolbarHTML}
+
+
+
+
+
`; + } + + function buildTimelineNodes(){ + // TODO: handle nodes that aren't actually comments, i.e. those where __typename != 'IssueComment' + // Will probably want to use a delegating method to determine whether a given node will be a + // comment or what-have-you, which impacts the properties available on each edge.node object. + // For the time being, just handle the actual comments. + return Array.from( + responseNodesData.filter(e => e.__typename === 'IssueComment'), + buildCommentNode + ).join('\n'); + } + + function fixIssueTimeline(){ + const commentContainer = document.querySelector('div.react-comments-container > div.IssueViewer-module__commentsContainer--H8wxg'); + const frag = document.createDocumentFragment(); + const substContainer = document.createElement('div'); + substContainer.className = 'IssueViewer-module__commentsContainer--H8wxg'; + + // fix borked styles + substContainer.insertAdjacentHTML('beforeEnd', ``); + + substContainer.insertAdjacentHTML('beforeEnd', `

Activity

\n
\n${buildTimelineNodes()}\n
`); + // TODO: figure out if replacing the above with something using generators is more efficient + frag.append(substContainer); + commentContainer.replaceWith(frag); + } + fixIssueTimeline(); +})(); From 1ca382995b95ab5a3890c27333443e06760a4921 Mon Sep 17 00:00:00 2001 From: StaticPH <7786502+StaticPH@users.noreply.github.com> Date: Tue, 9 Dec 2025 12:46:13 -0500 Subject: [PATCH 13/38] Update README and supporting files. --- README.md | 8 +++- build/data_files/general_url_references.json | 17 ++++++-- build/run.sh | 45 +++++++++++++++----- build/templates/link_refs.md.j2 | 3 ++ build/templates/primary_template.md.j2 | 1 + build/templates/userscript_manager.md.j2 | 13 ++---- 6 files changed, 62 insertions(+), 25 deletions(-) diff --git a/README.md b/README.md index e649b11..608ab2c 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,8 @@ I try to specifically write code that will run on these targets, _regardless of * Alternatively, install ViolentMonkey from its [source][ViolentMonkey_src] ### Other -* If you use [Pale Moon](https://www.palemoon.org), [Basilisk](https://www.basilisk-browser.org), or [K-Meleon](http://kmeleonbrowser.org), try [this fork of GreaseMonkey v3][GreaseMonkey_v3_Moonchild].
+* If you use [Pale Moon](https://www.palemoon.org), [Basilisk](https://www.basilisk-browser.org), [K-Meleon](http://kmeleonbrowser.org), [Arctic Fox](https://github.com/rmottola/Arctic-Fox), [Serpent, New Moon](https://rtfreesoft.blogspot.com), or another browser using the Goanna browser engine, try [this fork of GreaseMonkey v3][GreaseMonkey_v3_Moonchild].
+* The [Hyperbola-fork of Iceweasel][Hyperbola_Iceweasel] has its own [fork of GreaseMonkey v3][GreaseMonkey_v3_Hyperbola_Iceweasel]
Page only available in Spanish as of November 16th, 2025 Some scripts will likely require modifications for this to work; if you do this yourself, please submit a pull request so that others may also benefit. ## Important note: @@ -566,8 +567,9 @@ Additionally, I do occasionally take requests for simple scripts, so feel free t --- ## Some of the awesome scripts I use from other authors +I make no guarantees regarding the availability, maintenance, or browser version support of these scripts<\sub> - [Wide GitHub](https://github.com/xthexder/wide-github) -- [GitHub Code Folding](https://openuserjs.org/scripts/Mottie/GitHub_Code_Folding) +- [GitHub Code Folding](https://openuserjs.org/scripts/Mottie/GitHub_Code_Folding) (Note: last working version for Chrome 72 was v1.1.2, although subsequent changes to GitHub's UI have broken parts of that, too) - [GitHub Gist Search Box](https://greasyfork.org/en/scripts/395318-github-gist-search-box) - [GitHub Search Autocomplete](https://github.com/Mottie/GitHub-userscripts/wiki/GitHub-search-autocomplete) - [GitHub - Add Path Search](https://gist.github.com/splintor/8d3f12b86962efe5dcacb28ca15aa87d) @@ -636,3 +638,5 @@ Additionally, I do occasionally take requests for simple scripts, so feel free t [ViolentMonkey_Chrome]: https://chrome.google.com/webstore/detail/violent-monkey/jinjaccalgkegednnccohejagnlnfdag [ViolentMonkey_Edge]: https://microsoftedge.microsoft.com/addons/detail/violentmonkey/eeagobfjdenkkddmbclomhiblgggliao [GreaseMonkey_v3_Moonchild]: https://github.com/janekptacijarabaci/greasemonkey/releases +[GreaseMonkey_v3_Hyperbola_Iceweasel]: https://wiki.hyperbola.info/doku.php?id=es:system:userspace:application:uxp:iceweasel-uxp_addons +[Hyperbola_Iceweasel]: https://wiki.hyperbola.info/doku.php?id=es:system:userspace:application:uxp:iceweasel-uxp diff --git a/build/data_files/general_url_references.json b/build/data_files/general_url_references.json index 985c27b..9ea7a24 100644 --- a/build/data_files/general_url_references.json +++ b/build/data_files/general_url_references.json @@ -3,7 +3,7 @@ "title": "Some of the awesome scripts I use from other authors", "scripts": [ "[Wide GitHub](https://github.com/xthexder/wide-github)", - "[GitHub Code Folding](https://openuserjs.org/scripts/Mottie/GitHub_Code_Folding)", + "[GitHub Code Folding](https://openuserjs.org/scripts/Mottie/GitHub_Code_Folding) (Note: last working version for Chrome 72 was v1.1.2, although subsequent changes to GitHub's UI have broken parts of that, too)", "[GitHub Gist Search Box](https://greasyfork.org/en/scripts/395318-github-gist-search-box)", "[GitHub Search Autocomplete](https://github.com/Mottie/GitHub-userscripts/wiki/GitHub-search-autocomplete)", "[GitHub - Add Path Search](https://gist.github.com/splintor/8d3f12b86962efe5dcacb28ca15aa87d)", @@ -13,11 +13,22 @@ "[GitHub Network Ninja](https://github.com/maliayas/github-network-ninja/blob/master/main.user.js)" ] }, + "goanna_browsers_inline_refs": [ + "[Pale Moon](https://www.palemoon.org)", + "[Basilisk](https://www.basilisk-browser.org)", + "[K-Meleon](http://kmeleonbrowser.org)", + "[Arctic Fox](https://github.com/rmottola/Arctic-Fox)", + "[Serpent, New Moon](https://rtfreesoft.blogspot.com)" + ], "script_manager_refs": [ "[ViolentMonkey_src]: https://github.com/violentmonkey/violentmonkey/releases", "[ViolentMonkey_Firefox]: https://addons.mozilla.org/firefox/addon/violentmonkey/", "[ViolentMonkey_Chrome]: https://chrome.google.com/webstore/detail/violent-monkey/jinjaccalgkegednnccohejagnlnfdag", "[ViolentMonkey_Edge]: https://microsoftedge.microsoft.com/addons/detail/violentmonkey/eeagobfjdenkkddmbclomhiblgggliao", - "[GreaseMonkey_v3_Moonchild]: https://github.com/janekptacijarabaci/greasemonkey/releases" + "[GreaseMonkey_v3_Moonchild]: https://github.com/janekptacijarabaci/greasemonkey/releases", + "[GreaseMonkey_v3_Hyperbola_Iceweasel]: https://wiki.hyperbola.info/doku.php?id=es:system:userspace:application:uxp:iceweasel-uxp_addons" + ], + "other_url_refs": [ + "[Hyperbola_Iceweasel]: https://wiki.hyperbola.info/doku.php?id=es:system:userspace:application:uxp:iceweasel-uxp" ] -} \ No newline at end of file +} diff --git a/build/run.sh b/build/run.sh index 8505591..1c18fac 100644 --- a/build/run.sh +++ b/build/run.sh @@ -1,17 +1,34 @@ #! /bin/sh # To "register" a new userscript, add a new object with `path` and `anchorString` values to the `scripts` array in `main_script_manifest.json`; the updater python script will do the rest. + +usage(){ + # shellcheck disable=SC2016 + printf '%s\n' \ + 'This script is used to generate updated versions of readme and manifest files.' \ + 'To "register" a new userscript for inclusion in the readme, add a new' \ + 'object with both `path` and `anchorString` values to the `scripts` array' \ + 'in `main_script_manifest.json` before running this script.' \ + 'Updated manifest and readme files will be created in the `build` directory,' \ + 'and named `newdata.json` and `output.md`, respectively.' \ + 'They can be manually copied over the originals.' + return 0 +} + +## If this script ever comes to require any arguments, uncomment this. +# if [ "$#" -eq 0 ]; then +# usage +# exit 1 +# fi + case "$1" in -h|--help) - printf '%s\n' \ - 'This script is used to generate updated versions of readme and manifest files.' \ - 'To "register" a new userscript for inclusion in the readme, add a new' \ - 'object with both `path` and `anchorString` values to the `scripts` array' \ - 'in `main_script_manifest.json` before running this script.' \ - 'Updated manifest and readme files will be created in the `build` directory,' \ - 'and named `newdata.json` and `output.md`, respectively.' \ - 'They can be manually copied over the originals.' - exit 0 + usage && exit + ;; + -*) + printf 'ERROR: unrecognized flag: "%s"\n' "$1" + usage + exit 1 ;; esac @@ -19,13 +36,19 @@ repoRoot="$(git rev-parse --show-toplevel)" dataDir="${repoRoot}/build/data_files" templateDir="${repoRoot}/build/templates" -pushd "${repoRoot}/build" >/dev/null 2>&1 +OLDPWD="${PWD}" +restorePWD(){ + cd "${OLDPWD}" >/dev/null 2>&1 || return +} +trap restorePWD EXIT + +# shellcheck disable=SC2164 +cd "${repoRoot}/build" >/dev/null 2>&1 TEST_READER=1 python3 "${repoRoot}/build/update_script_manifest.py" jq -rs 'reduce .[] as $item ({}; . * $item)' "${dataDir}/general_url_references.json" "${dataDir}/legacy_scripts.json" newdata.json | \ minijinja-cli --format json "${templateDir}/primary_template.md.j2" - > output.md -popd >/dev/null 2>&1 ################ ################ # TODO: diff --git a/build/templates/link_refs.md.j2 b/build/templates/link_refs.md.j2 index cfdcef3..ed52407 100644 --- a/build/templates/link_refs.md.j2 +++ b/build/templates/link_refs.md.j2 @@ -24,3 +24,6 @@ Format END --> #} {%- for item in script_manager_refs %} {{ item }} {%- endfor %} +{%- for item in other_url_refs %} +{{ item }} +{%- endfor %} diff --git a/build/templates/primary_template.md.j2 b/build/templates/primary_template.md.j2 index 0a2e9d6..424b9da 100644 --- a/build/templates/primary_template.md.j2 +++ b/build/templates/primary_template.md.j2 @@ -93,6 +93,7 @@ Additionally, I do occasionally take requests for simple scripts, so feel free t --- ## {{ recommendations.title }} +I make no guarantees regarding the availability, maintenance, or browser version support of these scripts<\sub> {%- for script in recommendations.scripts %} - {{ script }} {%- endfor %} diff --git a/build/templates/userscript_manager.md.j2 b/build/templates/userscript_manager.md.j2 index d91e1e2..d8725ed 100644 --- a/build/templates/userscript_manager.md.j2 +++ b/build/templates/userscript_manager.md.j2 @@ -3,13 +3,8 @@ * [Google Chrome and (most) Chromium-based browsers][ViolentMonkey_Chrome] * [Microsoft Edge (which people apparently use)][ViolentMonkey_Edge] * Alternatively, install ViolentMonkey from its [source][ViolentMonkey_src] -{# - -#} + ### Other -* If you use [Pale Moon](https://www.palemoon.org), [Basilisk](https://www.basilisk-browser.org), or [K-Meleon](http://kmeleonbrowser.org), try [this fork of GreaseMonkey v3][GreaseMonkey_v3_Moonchild].
-Some scripts will likely require modifications for this to work; if you do this yourself, please submit a pull request so that others may also benefit. \ No newline at end of file +* If you use {{ goanna_browsers_inline_refs|join(', ') }}, or another browser using the Goanna browser engine, try [this fork of GreaseMonkey v3][GreaseMonkey_v3_Moonchild].
+* The [Hyperbola-fork of Iceweasel][Hyperbola_Iceweasel] has its own [fork of GreaseMonkey v3][GreaseMonkey_v3_Hyperbola_Iceweasel]
Page only available in Spanish as of November 16th, 2025 +Some scripts will likely require modifications for this to work; if you do this yourself, please submit a pull request so that others may also benefit. From 37a022fcfa77c7a5eb7ef7190338d4580c0176f6 Mon Sep 17 00:00:00 2001 From: StaticPH <7786502+StaticPH@users.noreply.github.com> Date: Tue, 9 Dec 2025 12:53:18 -0500 Subject: [PATCH 14/38] Add greasyfork_better_page_titles.user.js --- README.md | 11 +++++ build/data_files/main_script_manifest.json | 11 +++++ greasyfork_better_page_titles.user.js | 50 ++++++++++++++++++++++ 3 files changed, 72 insertions(+) create mode 100644 greasyfork_better_page_titles.user.js diff --git a/README.md b/README.md index 608ab2c..968b388 100644 --- a/README.md +++ b/README.md @@ -71,6 +71,7 @@ To add a script: | [StackExchange Wide Mode](#SEWM) | [install][raw-SEWM] | N/A | :heavy_check_mark: | MIT | Jun 20, 2024 | Jun 20, 2024 | | [Better IzzyOnDroid App Titles](#BIAT) | [install][raw-BIAT] | N/A | :heavy_check_mark: | MIT | May 2, 2024 | May 22, 2025 | | [Better F-Droid App Titles](#BFAT) | [install][raw-BFAT] | N/A | :heavy_check_mark: | MIT | Aug 15, 2025 | Aug 15, 2025 | +| [Better Greasyfork Page Titles](#BGPT) | [install][raw-BGPT] | N/A | :heavy_check_mark: | MIT | Nov 15, 2025 | Nov 15, 2025 | --- @@ -485,6 +486,15 @@ Adds app description to page titles where possible. [[Install]][raw-BFAT] +--- + + +### Better Greasyfork Page Titles + +Include userscript descriptions in page titles on Greasy Fork (and Sleazy Fork) + +[[Install]][raw-BGPT] + --- ## Legacy Workaround Scripts @@ -622,6 +632,7 @@ Additionally, I do occasionally take requests for simple scripts, so feel free t [raw-SEWM]: /stackexchange_wide_mode.user.js?raw=1 [raw-BIAT]: /izzyondroid_description_in_title.user.js?raw=1 [raw-BFAT]: /fdroid_app_description_in_title.user.js?raw=1 +[raw-BGPT]: /greasyfork_better_page_titles.user.js?raw=1 [raw-DFSF]: /legacy_browser_workarounds/discourse_forum_scroll_fixer.user.js?raw=1 diff --git a/build/data_files/main_script_manifest.json b/build/data_files/main_script_manifest.json index 95058a6..544c90d 100644 --- a/build/data_files/main_script_manifest.json +++ b/build/data_files/main_script_manifest.json @@ -450,6 +450,17 @@ "updated": "Aug 15, 2025", "desc": "Adds app description to page titles where possible.", "version": "1.0.0" + }, + { + "name": "Better Greasyfork Page Titles", + "anchorString": "BGPT", + "path": "/greasyfork_better_page_titles.user.js", + "license": "MIT", + "autoUpdates": true, + "created": "Nov 15, 2025", + "updated": "Nov 15, 2025", + "desc": "Include userscript descriptions in page titles on Greasy Fork (and Sleazy Fork)", + "version": "1.0.0" } ] } \ No newline at end of file diff --git a/greasyfork_better_page_titles.user.js b/greasyfork_better_page_titles.user.js new file mode 100644 index 0000000..dd40b5d --- /dev/null +++ b/greasyfork_better_page_titles.user.js @@ -0,0 +1,50 @@ +// ==UserScript== +// @name Better Greasy Fork Page Titles +// @namespace https://github.com/StaticPH +// @match https://greasyfork.org/*/scripts/* +// @match https://sleazyfork.org/*/scripts/* +// @version 1.0.0 +// @createdAt 11/15/2025, 3:33:58 PM +// @author StaticPH +// @description Include userscript descriptions in page titles on Greasy Fork and Sleazy Fork +// @license MIT +// @updateURL https://raw.githubusercontent.com/StaticPH/Userscripts/master/greasyfork_better_page_titles.user.js +// @downloadURL https://raw.githubusercontent.com/StaticPH/Userscripts/master/greasyfork_better_page_titles.user.js +// @homepageURL https://github.com/StaticPH/UserScripts +// @supportURL https://github.com/StaticPH/UserScripts/issues +// @icon https://greasyfork.org/vite/assets/blacklogo16-DftkYuVe.png +// @grant none +// @noframes +// @run-at document-end +// ==/UserScript== + +(function(){ + "use strict"; + + // Get the description from the visible element, rather than from + // the meta tag in document.head; the latter changes based on + // which tab (Info/Code/History/Feedback/Stats) is active. + const descEle = document.getElementById('script-description'); + // Guard against a missing description element (which should never occur). + const descValue = descEle !== null ? descEle.textContent.trim() : 'No description'; + // Guard against the description element's text being only whitespace or an empty string. + const desc = descValue !== '' ? descValue : 'No description'; + + // Get the script title from the visible element, rather than from + // the existing document title; the latter changes based on + // which tab (Info/Code/History/Feedback/Stats) is active. + const scriptTitleEle = document.querySelector('#script-info > header > h2'); + // Fallback to actual page title only if necessary, which is less desirable because it makes extraKeyword seem out of place on all but the Info tab. + const scriptTitle = scriptTitleEle !== null ? scriptTitleEle.textContent.trim() : document.title; + + // For the purposes of searching through bookmarks and the like, + // ensure that the keyword "userscript" is always present in the title + const extraKeyword = scriptTitle.toLowerCase().includes('userscript') ? '' : ' userscript'; + + // If not viewing the first tab (Info), include the name of the tab in the updated title. + const tabLabelEle = document.querySelector('#script-links > .current:not(:first-of-type)'); + const tabLabel = tabLabelEle !== null ? ` (${tabLabelEle.textContent.trim().split(' ')[0]})` : ''; + + document.title = `${scriptTitle}${extraKeyword}${tabLabel} — ${desc}`; + +})(); From 873ef3ea5f6fc8845e53004acb7c9ebcdea9a373 Mon Sep 17 00:00:00 2001 From: StaticPH <7786502+StaticPH@users.noreply.github.com> Date: Tue, 16 Dec 2025 11:50:57 -0500 Subject: [PATCH 15/38] Google Search Footer Privacy: Add additional location selector --- README.md | 2 +- build/data_files/main_script_manifest.json | 4 ++-- google_search_footer_privacy.user.js | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 968b388..d11dc52 100644 --- a/README.md +++ b/README.md @@ -50,7 +50,7 @@ To add a script: | [Wider Google Form Fields](#WGFF) | [install][raw-WGFF] | N/A | :heavy_check_mark: | MIT | Sep 30, 2021 | Aug 19, 2022 | | [Correct Google Form Correctness](#GFCC) | [install][raw-GFCC] | N/A | :heavy_check_mark: | MIT | Nov 9, 2021 | Nov 9, 2021 | | [Google Search Lean Query Updates](#GSLQU) | [install][raw-GSLQU] | N/A | :heavy_check_mark: | MIT | Jul 12, 2023 | Sep 28, 2024 | -| [Google Search Footer Privacy](#GSFP) | [install][raw-GSFP] | N/A | :heavy_check_mark: | MIT | Dec 30, 2023 | Dec 30, 2023 | +| [Google Search Footer Privacy](#GSFP) | [install][raw-GSFP] | N/A | :heavy_check_mark: | MIT | Dec 30, 2023 | Dec 16, 2025 | | [Roll20 Nonscrolling Number Fields](#RNNF) | [install][raw-RNNF] | N/A | :heavy_check_mark: | MIT | Jan 23, 2021 | Apr 5, 2021 | | [Bypass Blogspot's Blogger IFrame](#BBBI) | [install][raw-BBBI] | N/A | :heavy_check_mark: | MIT | Jun 2, 2021 | May 1, 2022 | | [Foxaholic Fixes](#FoxF) | [install][raw-FoxF] | N/A | :heavy_check_mark: | MIT | Jun 2, 2021 | Aug 27, 2021 | diff --git a/build/data_files/main_script_manifest.json b/build/data_files/main_script_manifest.json index 544c90d..70662cb 100644 --- a/build/data_files/main_script_manifest.json +++ b/build/data_files/main_script_manifest.json @@ -227,9 +227,9 @@ "license": "MIT", "autoUpdates": true, "created": "Dec 30, 2023", - "updated": "Dec 30, 2023", + "updated": "Dec 16, 2025", "desc": "Hide the \"Location\" part of the footer on Google Search results, and don't show the email address of the current user.", - "version": "1.1.0" + "version": "1.1.1" }, { "name": "Roll20 Nonscrolling Number Fields", diff --git a/google_search_footer_privacy.user.js b/google_search_footer_privacy.user.js index 0eac588..2acd8fd 100644 --- a/google_search_footer_privacy.user.js +++ b/google_search_footer_privacy.user.js @@ -3,7 +3,7 @@ // @namespace https://github.com/StaticPH // @match *://google.com/search // @match *://*.google.com/search -// @version 1.1.0 +// @version 1.1.1 // @createdAt 12/30/2023, 6:16:41 PM // @author StaticPH // @description Hide the "Location" part of the footer on Google Search results, and don't show the email address of the current user. @@ -40,7 +40,7 @@ /* Hide email address of currently logged in user, if applicable */ /* #EOlPnc > :nth-last-child(2):not(:first-child) > :first-child:not(:last-child), */ /* Hide Location */ - #EOlPnc > .Srfpq, .dfB0uf { + #EOlPnc > .Srfpq, .dfB0uf, .HddGcc > .VYM29 { display: none !important; } From 4597b893d45e218d327ad5974917c004354b53aa Mon Sep 17 00:00:00 2001 From: StaticPH <7786502+StaticPH@users.noreply.github.com> Date: Tue, 16 Dec 2025 12:29:50 -0500 Subject: [PATCH 16/38] Improve README automation scripts abilities to change to the correct directory contexts for operation. --- build/run.sh | 18 ++++++++---------- build/update_script_manifest.py | 27 +++++++++++++-------------- 2 files changed, 21 insertions(+), 24 deletions(-) diff --git a/build/run.sh b/build/run.sh index 1c18fac..4be6428 100644 --- a/build/run.sh +++ b/build/run.sh @@ -32,20 +32,18 @@ case "$1" in ;; esac +## POSIX way to determine the location of an executed shell script https://stackoverflow.com/a/29835459 +thisScriptLocation="$(CDPATH= cd -- "$(dirname -- "$0")" && pwd -P)" +## Ensure this script is run in the context of it's parent directory, which is within the git repository. +if [ "$PWD" != "$thisScriptLocation" ]; then + exec env -C "$thisScriptLocation" "./${0##*/}" "$@" +fi + repoRoot="$(git rev-parse --show-toplevel)" dataDir="${repoRoot}/build/data_files" templateDir="${repoRoot}/build/templates" -OLDPWD="${PWD}" -restorePWD(){ - cd "${OLDPWD}" >/dev/null 2>&1 || return -} -trap restorePWD EXIT - -# shellcheck disable=SC2164 -cd "${repoRoot}/build" >/dev/null 2>&1 - -TEST_READER=1 python3 "${repoRoot}/build/update_script_manifest.py" +WRITE_FILES=1 python3 "${repoRoot}/build/update_script_manifest.py" jq -rs 'reduce .[] as $item ({}; . * $item)' "${dataDir}/general_url_references.json" "${dataDir}/legacy_scripts.json" newdata.json | \ minijinja-cli --format json "${templateDir}/primary_template.md.j2" - > output.md diff --git a/build/update_script_manifest.py b/build/update_script_manifest.py index b9cf401..56c6602 100644 --- a/build/update_script_manifest.py +++ b/build/update_script_manifest.py @@ -272,27 +272,26 @@ def findScriptData(self) -> None: print(adjusted) # FIXME: Do something with this value other than just print it to stdout. self.dataFileContents['scripts'] = adjusted # TEMP - def writeTest(self) -> None: # TEMP - with open('newdata.json', 'w', encoding=defaultFileEncoding) as outputFile: + def writeNew(self, toFile: str='newdata.json') -> None: + with open(toFile, 'w', encoding=defaultFileEncoding) as outputFile: json.dump(self.dataFileContents, outputFile, indent="\t") - print('Go diff main_script_manifest.json and newdata.json') # TODO: ?Decide on some process to automatically assign an anchorString? if __name__ == '__main__': - from os import getenv from functools import partial - hasDebugVar: bool = bool(getenv('DEBUG')) + hasDebugVar: bool = bool(os.getenv('DEBUG')) if hasDebugVar: mayPrint = partial(print, file=sys.stderr) #noqa: F811, RUF100 - if bool(getenv('TEST_READER')): - updater = DataUpdater() - # TODO: utilize __file__ to make these paths relative to the script, rather than the working directory - updater.readJSONFile('./data_files/main_script_manifest.json') - here = os.getcwd() - os.chdir('..') - updater.findScriptData() - os.chdir(here) - updater.writeTest() + updater = DataUpdater() + # Get the parent directory of this script. + here = os.path.dirname(__file__) + + updater.readJSONFile(here + '/data_files/main_script_manifest.json') + os.chdir(here + '/..') + updater.findScriptData() + if bool(os.getenv('WRITE_FILES')): + updater.writeNew(here + '/newdata.json') + print('Go diff main_script_manifest.json and newdata.json') From 3a955204ef72f6c734c2b5930afc7899418adaf2 Mon Sep 17 00:00:00 2001 From: StaticPH <7786502+StaticPH@users.noreply.github.com> Date: Tue, 16 Dec 2025 13:29:17 -0500 Subject: [PATCH 17/38] Fix README automation writing 2-part version strings in scripts as 3-part version strings in the manifest. --- build/update_script_manifest.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/build/update_script_manifest.py b/build/update_script_manifest.py index 56c6602..672dc83 100644 --- a/build/update_script_manifest.py +++ b/build/update_script_manifest.py @@ -83,7 +83,7 @@ def __init__(self, value: str): self.minor: int = int(minor, 10) self.patch: int = int(patch, 10) or 0 self.originalValue: str = value - self.value: str = value + '.0' if patch == '' else value + self.value: str = f'{value}.{self.patch}' if value.count('.') < 2 else value def __str__(self) -> str: return self.value @@ -228,12 +228,12 @@ def getUpdatedScriptData(self, scriptFileMeta: Dict[str, Union[str, bool]], scri scriptItem['updated'] = scriptItem['created'] elif ('version' in scriptItem) and VersionString(scriptItem['version']) < scriptFileMeta['version']: # The file's version info was increased since the last time the data file was updated by this script; - # record the new "updated" date as the current date, and update the "version" to match the script's meta block + # record the new "updated" date as the current date scriptItem['updated'] = self._missingCreatedValue if self.__needsAttrForDataFile(scriptItem, 'license'): # Get license field from script file's metadata scriptItem['license'] = scriptFileMeta['license'] or self._missingLicenseValue - # Unconditionally update the version field + # Unconditionally update the "version" field to match the script's meta block scriptItem['version'] = str(VersionString(scriptFileMeta['version'])) or self._missingVersionValue # Unconditionally update the autoUpdates field scriptItem['autoUpdates'] = scriptFileMeta['autoUpdates'] or 'false' From c324f5c7acf5924992bdb1ab52dfcbbc543fad09 Mon Sep 17 00:00:00 2001 From: StaticPH <7786502+StaticPH@users.noreply.github.com> Date: Tue, 16 Dec 2025 14:21:26 -0500 Subject: [PATCH 18/38] Add automation support for producing updated legacy_scripts manifest file. --- build/run.sh | 10 ++++++---- build/update_script_manifest.py | 19 +++++++++++++------ 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/build/run.sh b/build/run.sh index 4be6428..b98c442 100644 --- a/build/run.sh +++ b/build/run.sh @@ -7,10 +7,12 @@ usage(){ printf '%s\n' \ 'This script is used to generate updated versions of readme and manifest files.' \ 'To "register" a new userscript for inclusion in the readme, add a new' \ - 'object with both `path` and `anchorString` values to the `scripts` array' \ - 'in `main_script_manifest.json` before running this script.' \ + 'object with both `path` and `anchorString` values to the' \ '`scripts` array (or other such array where relevant)' \ + 'in `main_script_manifest.json` (and/or `legacy_scripts.json`)' \ + 'before running this script.' \ 'Updated manifest and readme files will be created in the `build` directory,' \ - 'and named `newdata.json` and `output.md`, respectively.' \ + 'and named `new_main_manifest.json`/`new_legacy_manifest.json`' \ + 'and `output.md`, respectively.' \ 'They can be manually copied over the originals.' return 0 } @@ -44,7 +46,7 @@ dataDir="${repoRoot}/build/data_files" templateDir="${repoRoot}/build/templates" WRITE_FILES=1 python3 "${repoRoot}/build/update_script_manifest.py" -jq -rs 'reduce .[] as $item ({}; . * $item)' "${dataDir}/general_url_references.json" "${dataDir}/legacy_scripts.json" newdata.json | \ +jq -rs 'reduce .[] as $item ({}; . * $item)' "${dataDir}/general_url_references.json" new_legacy_manifest.json new_main_manifest.json | \ minijinja-cli --format json "${templateDir}/primary_template.md.j2" - > output.md ################ diff --git a/build/update_script_manifest.py b/build/update_script_manifest.py index 672dc83..6ba36e7 100644 --- a/build/update_script_manifest.py +++ b/build/update_script_manifest.py @@ -239,14 +239,14 @@ def getUpdatedScriptData(self, scriptFileMeta: Dict[str, Union[str, bool]], scri scriptItem['autoUpdates'] = scriptFileMeta['autoUpdates'] or 'false' return self.sortScriptMeta(scriptItem) - def findScriptData(self) -> None: + def findScriptData(self, scriptArrayKey: str = 'scripts') -> None: # Must be called after either `readJSONFile`/`readJSONStr`/`readJSONDict` # FIXME: With the large blocks of data this function will eventually be producing and returning, # it would probably make sense to turn this into a Generator method, or at least make the # `for` loop into its own inner-function and make _that_ a Generator. adjusted: List[Dict[str, Union[str, bool]]] = [] - for scriptItem in self.dataFileContents['scripts']: + for scriptItem in self.dataFileContents[scriptArrayKey]: scriptItem: Dict[str, str] # Shut up linter wrongly complaining that scriptItem is a string. if 'path' not in scriptItem: # TODO: support automatic detection of version-controlled scripts not in a data file, @@ -270,9 +270,9 @@ def findScriptData(self) -> None: adjusted.append(self.getUpdatedScriptData(scriptFileMeta, scriptItem)) print(adjusted) # FIXME: Do something with this value other than just print it to stdout. - self.dataFileContents['scripts'] = adjusted # TEMP + self.dataFileContents[scriptArrayKey] = adjusted # TEMP - def writeNew(self, toFile: str='newdata.json') -> None: + def writeNew(self, toFile: str='new_main_manifest.json') -> None: with open(toFile, 'w', encoding=defaultFileEncoding) as outputFile: json.dump(self.dataFileContents, outputFile, indent="\t") @@ -293,5 +293,12 @@ def writeNew(self, toFile: str='newdata.json') -> None: os.chdir(here + '/..') updater.findScriptData() if bool(os.getenv('WRITE_FILES')): - updater.writeNew(here + '/newdata.json') - print('Go diff main_script_manifest.json and newdata.json') + updater.writeNew(here + '/new_main_manifest.json') + print('Go diff main_script_manifest.json and new_main_manifest.json') + + updater.readJSONFile(here + '/data_files/legacy_scripts.json') + os.chdir(here + '/..') + updater.findScriptData('legacy_scripts') + if bool(os.getenv('WRITE_FILES')): + updater.writeNew(here + '/new_legacy_manifest.json') + print('Go diff legacy_scripts.json and new_legacy_manifest.json') From 979636c2e9e85e36c321454c12135cb78f30f5e5 Mon Sep 17 00:00:00 2001 From: StaticPH <7786502+StaticPH@users.noreply.github.com> Date: Tue, 16 Dec 2025 14:23:42 -0500 Subject: [PATCH 19/38] Add file containing instructions and todo list for readme generation. --- build/ABOUT.md | 88 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 88 insertions(+) create mode 100644 build/ABOUT.md diff --git a/build/ABOUT.md b/build/ABOUT.md new file mode 100644 index 0000000..e728bb3 --- /dev/null +++ b/build/ABOUT.md @@ -0,0 +1,88 @@ +This file contains instructions for using the readme automation in this directory, and also a todo list. + +# Instructions +## Prerequisites +The following tools must be available on the `PATH`: + * Python (minimum version: 3.7) + * [MiniJinja CLI](https://github.com/mitsuhiko/minijinja) + * [jq](https://github.com/stedolan/jq) + * Bash/Zsh/Ksh/other-sh-interpreter + * git + +# What the hell do I do with any of this? +Run `./run.sh --help` for instructions on what needs to be done manually +when adding a new userscript. + +Otherwise, run `./run.sh`, then manually compare: + * `./data_files/main_script_manifest.json` <-> `./new_main_manifest.json` + * `./data_files/legacy_scripts.json` <-> `./new_legacy_manifest.json` + * `../README.md` <-> `./output.md` +If satisfied, move/copy the right-hand files to the (version-controlled) +left-hand files. + +Then add the changes and commit. + +# TODO list +1. [X] The updater script, templates, and data files should reside under a directory named something like `build` or `deploy` + +2. [X] Clear fucking instructions on how to run this shit. + + 1. [X] How should the updater know which userscript files to check for updates? + Currently it only checks files specified in the data files. + 2. [X] I don't believe the script currently understands how to read from multiple separate data files; should it? + Script now reads and updates both the main and legacy script manifests separately. + Support has been added for alternate keys to access the list of scripts in a file, + as the legacy manifest uses 'legacy_scripts', while the main manifest uses 'scripts'. + + Running `./update_script_manifest.py` with Python3.7 or later and the + non-empty environment variable `WRITE_FILES` will produce updated + `new_main_manifest.json` and `new_legacy_manifest.json` from + `data_files/main_script_manifest.json` and `data_files/legacy_scripts.json`. + The updated readme can then be written to `output.md` by running: +```bash +jq -rs 'reduce .[] as $item ({}; . * $item)' 'data_files/general_url_references.json' new_legacy_manifest.json new_main_manifest.json | +minijinja-cli --format json templates/primary_template.md.j2 - > output.md +``` + +**For convenience, simply run `./run.sh`** + +3. [ ] Automatically display (?git-?)diff of data file after running updater script. + + 1. [-] Do I want to ultimately want to write back to the original data file, or should I write to a temporary file, then compare them, + and prompt for confirmation before overwriting the original? What if I want only part of the changes? + Currently all outputs go to temporary files that must be manually checked, copied (if good), and cleaned up. + +4. [X] If the metadata block of a script doesn't contain the non-standard `@createdAt` property, + and the script doesn't already have a `created` value in the data file, + + _EITHER_ + 1. Attempt to check the creation and modified date of the script file according to the file system. Keep the older of the two. + 2. Call out to git to determine when the script was first added to the repository. + 3. Set the earlier of the two as the `created` value in the data file. + + _OR_ + + set the `created` value in the data file to the current date. + + The first scenario seems preferable, but in the interest of speed and + convenience, the second option is employed. + +5. [ ] Support automatic detection of version-controlled scripts not yet in a data file, and automatically add them to the appropriate one. + This should also handle adding the `created` date if necessary. + +6. [ ] Decide on some process to automatically assign an `anchorString`. + Consider ditching custom anchor strings entirely in favor of just using the name of the script file, sans extension. + +7. [ ] Figure out what part of `getUpdatedScriptData` can be replaced with a call to `dict.update()`. + +8. [ ] Investigate converting some part of `findScriptData` into a generator. + +9. [ ] Vendor icons into a repo (Projects/third_party/asset_archive) (Projects/Userscripts/notes/icon_index.txt) + 1. [ ] Add some kind of disclaimer section mentioning that site names and logos are property of their original owners. + +10. [ ] Group scripts under collapsible `section`/`detail` tags according to the sites they affect. + 1. [ ] Support a *manually added* `group` property in the data files to denote a named group; scripts without (a non-empty, non-null value for) this property should be under an "ungrouped" group, and appear only after all other groups. + +11. [X] Temporary local branch in which to test repository layout with new automation files included. + +12. [X] Finish/fix date parsing and conversion for the non-standard `createdAt` property in script metadata, so that it can be stored *sensibly* in the manifest. From 9ba15b7c6a53aa802a5fc3bdc2e3d801625bc982 Mon Sep 17 00:00:00 2001 From: StaticPH <7786502+StaticPH@users.noreply.github.com> Date: Tue, 16 Dec 2025 14:55:54 -0500 Subject: [PATCH 20/38] Add oxlint config --- .oxlintrc.json | 228 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 228 insertions(+) create mode 100644 .oxlintrc.json diff --git a/.oxlintrc.json b/.oxlintrc.json new file mode 100644 index 0000000..4d4c713 --- /dev/null +++ b/.oxlintrc.json @@ -0,0 +1,228 @@ +{ + "plugins": [ + "unicorn", + "typescript", + "oxc", + "jsdoc", + "promise" + ], + "categories": {}, + "rules": { + /* + "ruleName": "severity" + OR + "ruleName": ["severity", { "ruleOption": "value" (boolean and numeric values are unquoted) }] + */ + "block-scoped-var": "warn", + "for-direction": "warn", + "no-async-promise-executor": "warn", + "no-await-in-loop": "warn", + "no-caller": "warn", + "no-class-assign": "warn", + "no-compare-neg-zero": "warn", + "no-cond-assign": "warn", + "no-const-assign": "warn", + "no-constant-binary-expression": "warn", + "no-constant-condition": "warn", + "no-control-regex": "warn", + "no-debugger": "warn", + "no-delete-var": "warn", + "no-dupe-class-members": "warn", + "no-dupe-else-if": "warn", + "no-dupe-keys": "warn", + "no-duplicate-case": "warn", + "no-empty-character-class": "warn", + "no-empty-pattern": "warn", + "no-empty-static-block": "warn", + "no-eval": "warn", + "no-ex-assign": "warn", +// "no-extend-native": "warn", + "no-extra-bind": "warn", + "no-extra-boolean-cast": "warn", + "no-func-assign": "warn", + "no-global-assign": "warn", + "no-import-assign": "warn", + "no-invalid-regexp": "warn", + "no-irregular-whitespace": "warn", + "no-loss-of-precision": "warn", + "no-new": "warn", + "no-new-native-nonconstructor": "warn", + "no-nonoctal-decimal-escape": "warn", + "no-obj-calls": "warn", + "no-self-assign": "warn", + "no-setter-return": "warn", + "no-shadow-restricted-names": "warn", + "no-sparse-arrays": "warn", + "no-this-before-super": "warn", + "no-unassigned-vars": "warn", + "no-unexpected-multiline": "warn", + "no-unneeded-ternary": "warn", + "no-unsafe-finally": "warn", + "no-unsafe-negation": "warn", + "no-unsafe-optional-chaining": "warn", + "no-unused-expressions": "warn", + "no-unused-labels": "warn", + "no-unused-private-class-members": "warn", + "no-unused-vars": "warn", + "no-useless-backreference": "warn", + "no-useless-call": "warn", + "no-useless-catch": "warn", + "no-useless-concat": "warn", + "no-useless-constructor": "warn", + "no-useless-escape": "warn", + "no-useless-rename": "warn", + "no-with": "warn", + "preserve-caught-error": "warn", + "require-yield": "warn", + "use-isnan": "warn", + "valid-typeof": "warn", + "jsdoc/check-property-names": "warn", + "jsdoc/check-tag-names": "warn", + "jsdoc/implements-on-classes": "warn", + "jsdoc/no-defaults": "warn", + "jsdoc/require-property": "warn", + "jsdoc/require-property-description": "warn", + "jsdoc/require-property-name": "warn", + "jsdoc/require-property-type": "warn", + "jsdoc/require-yields": "warn", + "oxc/approx-constant": "warn", + "oxc/bad-array-method-on-arguments": "warn", + "oxc/bad-char-at-comparison": "warn", + "oxc/bad-comparison-sequence": "warn", + "oxc/bad-min-max-func": "warn", + "oxc/bad-object-literal-comparison": "warn", + "oxc/bad-replace-all-arg": "warn", + "oxc/const-comparisons": "warn", + "oxc/double-comparisons": "warn", + "oxc/erasing-op": "warn", + "oxc/misrefactored-assign-op": "warn", + "oxc/missing-throw": "warn", + "oxc/no-accumulating-spread": "warn", + "oxc/no-async-endpoint-handlers": "warn", + "oxc/number-arg-out-of-range": "warn", + "oxc/only-used-in-recursion": "warn", + "oxc/uninvoked-array-callback": "warn", + "promise/always-return": "warn", + "promise/no-callback-in-promise": "warn", + "promise/no-multiple-resolved": "warn", + "promise/no-new-statics": "warn", + "promise/no-promise-in-callback": "warn", + "promise/valid-params": "warn", + "typescript/await-thenable": "warn", + "typescript/no-array-delete": "warn", + "typescript/no-base-to-string": "warn", +// "typescript/no-confusing-non-null-assertion": "warn", + "typescript/no-duplicate-enum-values": "warn", + "typescript/no-duplicate-type-constituents": "warn", + "typescript/no-extra-non-null-assertion": "warn", +// "typescript/no-extraneous-class": "warn", + "typescript/no-floating-promises": "warn", + "typescript/no-for-in-array": "warn", + "typescript/no-implied-eval": "warn", + "typescript/no-meaningless-void-operator": "warn", + "typescript/no-misused-new": "warn", + "typescript/no-misused-spread": "warn", + "typescript/no-non-null-asserted-optional-chain": "warn", + "typescript/no-redundant-type-constituents": "warn", + "typescript/no-this-alias": "warn", +// "typescript/no-unnecessary-boolean-literal-compare": "warn", + "typescript/no-unnecessary-parameter-property-assignment": "warn", +// "typescript/no-unnecessary-template-expression": "warn", +// "typescript/no-unnecessary-type-arguments": "warn", +// "typescript/no-unnecessary-type-assertion": "warn", +// "typescript/no-unnecessary-type-constraint": "warn", + "typescript/no-unsafe-declaration-merging": "warn", +// "typescript/no-unsafe-enum-comparison": "warn", +// "typescript/no-unsafe-type-assertion": "warn", + "typescript/no-unsafe-unary-minus": "warn", + "typescript/no-useless-empty-export": "warn", + "typescript/no-wrapper-object-types": "warn", + "typescript/prefer-as-const": "warn", + "typescript/require-array-sort-compare": "warn", + "typescript/restrict-template-expressions": "warn", + "typescript/triple-slash-reference": "warn", + "typescript/unbound-method": "warn", + "unicorn/consistent-function-scoping": "warn", + "unicorn/no-accessor-recursion": "warn", + "unicorn/no-array-reverse": "warn", + "unicorn/no-array-sort": "warn", + "unicorn/no-await-in-promise-methods": "warn", + "unicorn/no-empty-file": "warn", + "unicorn/no-instanceof-builtins": "warn", + "unicorn/no-invalid-fetch-options": "warn", + "unicorn/no-invalid-remove-event-listener": "warn", + "unicorn/no-new-array": "warn", + "unicorn/no-single-promise-in-promise-methods": "warn", + "unicorn/no-thenable": "warn", + "unicorn/no-unnecessary-await": "warn", + "unicorn/no-useless-fallback-in-spread": "warn", + "unicorn/no-useless-length-check": "warn", + "unicorn/no-useless-spread": "warn", + "unicorn/prefer-add-event-listener": "warn", + "unicorn/prefer-array-find": "warn", + "unicorn/prefer-array-flat-map": "warn", + "unicorn/prefer-set-has": "warn", + "unicorn/prefer-set-size": "warn", + "unicorn/prefer-string-starts-ends-with": "warn", + "unicorn/require-module-specifiers": "warn", + "unicorn/require-post-message-target-origin": "warn" + }, + "settings": { + "jsx-a11y": { + "polymorphicPropName": null, + "components": {}, + "attributes": {} + }, + "next": { + "rootDir": [] + }, + "react": { + "formComponents": [], + "linkComponents": [] + }, + "jsdoc": { + "ignorePrivate": false, + "ignoreInternal": false, + "ignoreReplacesDocs": true, + "overrideReplacesDocs": true, + "augmentsExtendsReplacesDocs": false, + "implementsReplacesDocs": false, + "exemptDestructuredRootsFromChecks": false, + "tagNamePreference": {} + }, + "vitest": { + "typecheck": false + } + }, + "env": { + "builtin": true + }, + "globals": {}, + "ignorePatterns": [], + "extends": [ +// "localrules.json" + ], + "overrides": [ + // REFERENCE: https://eslint.org/docs/v8.x/use/configure/language-options + // REFERENCE: https://oxc.rs/docs/guide/usage/linter/config-file-reference + { // userscripts + "files": ["**/*.user.js"], + "rules": { + // Always allow console api in userscripts + "no-console": "off", + // Doesn't understand that immediately-executed-functions are only ever called once, and just whines... + "unicorn/consistent-function-scoping": "off", + }, + "env": { + "browser": true, + "greasemonkey": true, + "es2018": true, + "es2019": false + }, + "globals": { + "GM": "writable", + "unsafeWindow": "writable" + } + } + ] +} \ No newline at end of file From 37dd3e0bab8fa54b7b6ad6f37366da9c3999e608 Mon Sep 17 00:00:00 2001 From: StaticPH <7786502+StaticPH@users.noreply.github.com> Date: Wed, 28 Jan 2026 22:15:11 -0500 Subject: [PATCH 21/38] Update oxlint config --- .oxlintrc.json | 38 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 36 insertions(+), 2 deletions(-) diff --git a/.oxlintrc.json b/.oxlintrc.json index 4d4c713..4e049bb 100644 --- a/.oxlintrc.json +++ b/.oxlintrc.json @@ -4,7 +4,8 @@ "typescript", "oxc", "jsdoc", - "promise" + "promise", + "eslint" ], "categories": {}, "rules": { @@ -13,7 +14,9 @@ OR "ruleName": ["severity", { "ruleOption": "value" (boolean and numeric values are unquoted) }] */ + "accessor-pairs": "warn", "block-scoped-var": "warn", + "complexity": "warn", "for-direction": "warn", "no-async-promise-executor": "warn", "no-await-in-loop": "warn", @@ -39,17 +42,24 @@ // "no-extend-native": "warn", "no-extra-bind": "warn", "no-extra-boolean-cast": "warn", + "no-fallthrough": "warn", "no-func-assign": "warn", "no-global-assign": "warn", "no-import-assign": "warn", +// "no-implicit-coercion": "warn", "no-invalid-regexp": "warn", "no-irregular-whitespace": "warn", + "no-loop-func": "error", "no-loss-of-precision": "warn", "no-new": "warn", "no-new-native-nonconstructor": "warn", "no-nonoctal-decimal-escape": "warn", "no-obj-calls": "warn", + "no-promise-executor-return": "warn", + "no-regex-spaces": "warn", + "no-return-assign": "warn", "no-self-assign": "warn", + "no-sequences": [ "warn", { "allowInParentheses": false } ], "no-setter-return": "warn", "no-shadow-restricted-names": "warn", "no-sparse-arrays": "warn", @@ -67,6 +77,7 @@ "no-useless-backreference": "warn", "no-useless-call": "warn", "no-useless-catch": "warn", + "no-useless-computed-key": "warn", "no-useless-concat": "warn", "no-useless-constructor": "warn", "no-useless-escape": "warn", @@ -99,6 +110,7 @@ "oxc/missing-throw": "warn", "oxc/no-accumulating-spread": "warn", "oxc/no-async-endpoint-handlers": "warn", + "oxc/no-this-in-exported-function": "warn", "oxc/number-arg-out-of-range": "warn", "oxc/only-used-in-recursion": "warn", "oxc/uninvoked-array-callback": "warn", @@ -148,24 +160,40 @@ "unicorn/no-array-sort": "warn", "unicorn/no-await-in-promise-methods": "warn", "unicorn/no-empty-file": "warn", + "unicorn/no-immediate-mutation": "warn", "unicorn/no-instanceof-builtins": "warn", "unicorn/no-invalid-fetch-options": "warn", "unicorn/no-invalid-remove-event-listener": "warn", + "unicorn/no-negation-in-equality-check": "warn", "unicorn/no-new-array": "warn", "unicorn/no-single-promise-in-promise-methods": "warn", "unicorn/no-thenable": "warn", "unicorn/no-unnecessary-await": "warn", "unicorn/no-useless-fallback-in-spread": "warn", + "unicorn/no-unnecessary-array-flat-depth": "warn", + "unicorn/no-useless-collection-argument": "warn", + "unicorn/no-useless-error-capture-stack-trace": "warn", "unicorn/no-useless-length-check": "warn", "unicorn/no-useless-spread": "warn", "unicorn/prefer-add-event-listener": "warn", "unicorn/prefer-array-find": "warn", "unicorn/prefer-array-flat-map": "warn", + "unicorn/prefer-dom-node-append": "warn", + "unicorn/prefer-dom-node-dataset": "off", + "unicorn/prefer-dom-node-remove": "warn", + "unicorn/prefer-dom-node-text-content": "warn", + "unicorn/prefer-default-parameters": "warn", + "unicorn/prefer-keyboard-event-key": "warn", + "unicorn/prefer-logical-operator-over-ternary": "warn", + "unicorn/prefer-optional-catch-binding": "warn", + "unicorn/prefer-query-selector": "warn", + "unicorn/prefer-response-static-json": "warn", "unicorn/prefer-set-has": "warn", "unicorn/prefer-set-size": "warn", "unicorn/prefer-string-starts-ends-with": "warn", "unicorn/require-module-specifiers": "warn", - "unicorn/require-post-message-target-origin": "warn" + "unicorn/require-post-message-target-origin": "warn", + "unicorn/text-encoding-identifier-case": "warn" }, "settings": { "jsx-a11y": { @@ -212,6 +240,12 @@ "no-console": "off", // Doesn't understand that immediately-executed-functions are only ever called once, and just whines... "unicorn/consistent-function-scoping": "off", + // Portability + "unicorn/prefer-global-this": "warn", + // Too new + "typescript/prefer-nullish-coalescing": "off", + "typescript/prefer-optional-chain": "off", + "oxc/no-optional-chaining": [ "error", { "message": "es2018 target does not support optional chaining operator"} ] }, "env": { "browser": true, From aa92548905c4631b16befae8db65e941f095ef8c Mon Sep 17 00:00:00 2001 From: StaticPH <7786502+StaticPH@users.noreply.github.com> Date: Wed, 28 Jan 2026 22:39:32 -0500 Subject: [PATCH 22/38] Trivial linting --- fix_youtube_player_bottom_gradient.user.js | 2 +- github_repo_network_tab.user.js | 9 ++++++--- greasyfork_better_page_titles.user.js | 2 +- izzyondroid_description_in_title.user.js | 2 +- .../stackexchange_legacy_comments_expander.user.js | 2 +- mitigate_target_blank_risk.user.js | 2 +- novelupdates_reading_list_upgrades.user.js | 5 ++++- scribblehub_reading_list_upgrades.user.js | 6 ++++-- ubuntu_packages_description_in_title.user.js | 1 + 9 files changed, 20 insertions(+), 11 deletions(-) diff --git a/fix_youtube_player_bottom_gradient.user.js b/fix_youtube_player_bottom_gradient.user.js index aa99c45..52111ec 100644 --- a/fix_youtube_player_bottom_gradient.user.js +++ b/fix_youtube_player_bottom_gradient.user.js @@ -26,7 +26,7 @@ // `); setTimeout(function wait(){ - const playerBottomGradient = document.getElementById('movie_player').querySelector('.ytp-gradient-bottom'); + const playerBottomGradient = document.querySelector('#movie_player .ytp-gradient-bottom'); if (playerBottomGradient){ console.log('Fixing bottom player gradient height'); playerBottomGradient.style.removeProperty('height'); diff --git a/github_repo_network_tab.user.js b/github_repo_network_tab.user.js index b4e93df..95b3e3b 100644 --- a/github_repo_network_tab.user.js +++ b/github_repo_network_tab.user.js @@ -91,11 +91,13 @@ // Wait until the page loads in enough to have the 'Pull Requests' tab in the repository header, so that it can be used as a point of reference for element insertion if (repoPullsTab.length !== 0){ repoPullsTab[0].insertAdjacentHTML('afterend', createBigNetworkTabHTML()); - document.getElementById('bigNetworkTab') && console.debug('Added big Network tab.'); + /* oxlint-disable no-unused-expressions */ + document.querySelector('#bigNetworkTab') && console.debug('Added big Network tab.'); if (repoPullsTab.length > 1){ repoPullsTab[1].insertAdjacentHTML('afterend', createSmallNetworkTabHTML()); - document.getElementById('smallNetworkTab') && console.debug('Added small Network tab.'); + /* oxlint-disable no-unused-expressions */ + document.querySelector('#smallNetworkTab') && console.debug('Added small Network tab.'); } // setTimeout(function foo(){ @@ -112,7 +114,8 @@ const pullsDropdownItem = document.querySelector('details-menu li[data-menu-item="i2pull-requests-tab"]'); if (pullsDropdownItem){ pullsDropdownItem.insertAdjacentHTML('afterend', createNetworkTabInDropdownHTML()); - document.getElementById('networkTabDropdown') && console.debug('Added Network tab item to dropdown.'); + /* oxlint-disable no-unused-expressions */ + document.querySelector('#networkTabDropdown') && console.debug('Added Network tab item to dropdown.'); } else if (dropdownRetries >= dropdownRetryLimit){ console.log(`Number of attempts at adding Network tab to dropdown have exceeded the limit of ${dropdownRetryLimit} attempts. Giving up.`); diff --git a/greasyfork_better_page_titles.user.js b/greasyfork_better_page_titles.user.js index dd40b5d..79345c8 100644 --- a/greasyfork_better_page_titles.user.js +++ b/greasyfork_better_page_titles.user.js @@ -24,7 +24,7 @@ // Get the description from the visible element, rather than from // the meta tag in document.head; the latter changes based on // which tab (Info/Code/History/Feedback/Stats) is active. - const descEle = document.getElementById('script-description'); + const descEle = document.querySelector('#script-description'); // Guard against a missing description element (which should never occur). const descValue = descEle !== null ? descEle.textContent.trim() : 'No description'; // Guard against the description element's text being only whitespace or an empty string. diff --git a/izzyondroid_description_in_title.user.js b/izzyondroid_description_in_title.user.js index 19ff31c..7b22e9b 100644 --- a/izzyondroid_description_in_title.user.js +++ b/izzyondroid_description_in_title.user.js @@ -23,7 +23,7 @@ const parts = document.title.split('- IzzyOnDroid'); const tail = parts.pop(); - let summary = document.getElementById('summary').textContent; + let summary = document.querySelector('#summary').textContent; summary = summary[0].toLocaleUpperCase() + summary.slice(1); parts.push('- ' + summary + ' | IzzyOnDroid' + tail); document.title = parts.join(''); diff --git a/legacy_browser_workarounds/stackexchange_legacy_comments_expander.user.js b/legacy_browser_workarounds/stackexchange_legacy_comments_expander.user.js index e86bdbf..f4aab5f 100644 --- a/legacy_browser_workarounds/stackexchange_legacy_comments_expander.user.js +++ b/legacy_browser_workarounds/stackexchange_legacy_comments_expander.user.js @@ -28,7 +28,7 @@ function replaceChildrenWithNodes(parentNode, ...newChildren){ while (parentNode.lastChild){ - parentNode.removeChild(parentNode.lastChild); + parentNode.lastChild.remove(); } if (newChildren !== undefined){ const replacements = (newChildren.length === 1 && Array.isArray(newChildren[0])) ? newChildren[0] : newChildren; diff --git a/mitigate_target_blank_risk.user.js b/mitigate_target_blank_risk.user.js index 2923f66..be0b920 100644 --- a/mitigate_target_blank_risk.user.js +++ b/mitigate_target_blank_risk.user.js @@ -47,7 +47,7 @@ let splitRel; function cleanse(){ // Unsure whether to prefer getElementByTagName('a')+if target=='_blank' OR querySeletorAll('a[target="_blank"]') - Array.from(document.getElementsByTagName('a')).forEach( (link) => { + Array.from(document.querySelectorAll('a')).forEach( (link) => { if (link.target == '_blank'){ if (allowedOrigins.includes(link.origin)){ console.log('Found link with allowed origin:"' + link.origin + '" and target="_blank". The link\'s "rel" attribute will not be modified.'); diff --git a/novelupdates_reading_list_upgrades.user.js b/novelupdates_reading_list_upgrades.user.js index 0841a1a..8332f24 100644 --- a/novelupdates_reading_list_upgrades.user.js +++ b/novelupdates_reading_list_upgrades.user.js @@ -120,6 +120,7 @@ // document.querySelectorAll('.bmhide > :not(.nu_editnotes):first-child') // get not caught up // document.querySelectorAll('.bmhide > span[class*="bm_hide_me"]:first-child') // alternative to get not caught up const caughtUpHelper = { + /* oxlint-disable unicorn/prefer-query-selector */ mainTbl: document.getElementById('myTable read'), hiddenTbl: (function(){ const tbl = document.createElement('table'); @@ -216,7 +217,9 @@ // Fuck tracking and analytics document.querySelectorAll('script').forEach(s => (s.textContent.includes('urchinTracker') || s.src.includes('analytic')) && s.remove()); - settings.improvePageTitle && improveTitle(); + if (settings.improvePageTitle){ + improveTitle(); + } caughtUpHelper.init(); })(); \ No newline at end of file diff --git a/scribblehub_reading_list_upgrades.user.js b/scribblehub_reading_list_upgrades.user.js index 40166d4..dcea3f4 100644 --- a/scribblehub_reading_list_upgrades.user.js +++ b/scribblehub_reading_list_upgrades.user.js @@ -132,7 +132,7 @@ } const caughtUpHelper = { - mainTbl: document.getElementsByClassName('rl_table')[0], + mainTbl: document.querySelector('.rl_table'), hiddenTbl: (function(){ const tbl = document.createElement('table'); tbl.id = 'hiddenTbl'; @@ -225,7 +225,9 @@ // Fuck tracking and analytics document.querySelectorAll('script').forEach(s => (s.textContent.includes('urchinTracker') || s.src.includes('analytic')) && s.remove()); - settings.improvePageTitle && improveTitle(); + if (settings.improvePageTitle){ + improveTitle(); + } if (settings.ctrlEnterSavesNotes){ document.addEventListener('keyup', saveNotesKeybindHandler); setTitleForFakeButton(document.querySelector('.rlnotes_btn.savenotes'), true, '', ' (Ctrl+Enter)'); diff --git a/ubuntu_packages_description_in_title.user.js b/ubuntu_packages_description_in_title.user.js index 5e1128b..eec846a 100644 --- a/ubuntu_packages_description_in_title.user.js +++ b/ubuntu_packages_description_in_title.user.js @@ -20,6 +20,7 @@ (function(){ 'use strict'; + /* oxlint-disable unicorn/no-array-reverse */ const [pkg, repo, sourceSegment, /*lang*/] = document.location.pathname.split('/').reverse(); setTimeout(function wait(){ From e1a4cb3a545d07fcaf628ccf5779d3c01b3f4bae Mon Sep 17 00:00:00 2001 From: StaticPH <7786502+StaticPH@users.noreply.github.com> Date: Mon, 9 Feb 2026 11:05:55 -0500 Subject: [PATCH 23/38] Twitch Transparent Video Stats: Update CSS selectors and delay script injection time. Also coerce script versions in manifest file to three-segments. --- README.md | 4 +- build/data_files/main_script_manifest.json | 54 +++++++++++----------- twitch_transparent_video_stats.user.js | 7 +-- 3 files changed, 33 insertions(+), 32 deletions(-) diff --git a/README.md b/README.md index d11dc52..108f3bb 100644 --- a/README.md +++ b/README.md @@ -36,7 +36,7 @@ To add a script: | [Twitch Hide Content Disclosure](#THCD) | [install][raw-THCD] | N/A | :heavy_check_mark: | MIT | Jun 29, 2023 | Dec 12, 2024 | | [Twitch Hide Channel Leaderboard](#THCL) | [install][raw-THCL] | N/A | :heavy_check_mark: | MIT | Jun 19, 2020 | Dec 12, 2024 | | [Twitch Hide Overlay Ads](#THOA) | [install][raw-THOA] | N/A | :heavy_check_mark: | MIT | Dec 14, 2023 | Dec 12, 2024 | -| [Twitch Transparent Video Stats](#TTVS) | [install][raw-TTVS] | N/A | :heavy_check_mark: | MIT | May 19, 2021 | Dec 12, 2024 | +| [Twitch Transparent Video Stats](#TTVS) | [install][raw-TTVS] | N/A | :heavy_check_mark: | MIT | May 19, 2021 | Feb 9, 2026 | | [GitHub Repo Network Tab](#GRNT) | [install][raw-GRNT] | N/A | :heavy_check_mark: | MIT | Apr 6, 2020 | Feb 1, 2024 | | [Bigger GitHub Network Graph](#BGNG) | [install][raw-BGNG] | N/A | :heavy_check_mark: | MIT | Apr 12, 2020 | Oct 28, 2021 | | [GitHub Notification Page Tweaks](#GNPT) | [install][raw-GNPT] | N/A | :heavy_check_mark: | MIT | Oct 22, 2020 | Aug 3, 2021 | @@ -335,7 +335,7 @@ e.g. Setting `customAllowedOrigins` to `'http://wordpress.com https://stackexcha ### MSYS2 Package Description In Title -Include the package description on the tab title for a package's page on packages.msys2.org/packages +Include the package description on the tab title for a package's page on packages.msys2.org [[Install]][raw-MDIT] diff --git a/build/data_files/main_script_manifest.json b/build/data_files/main_script_manifest.json index 70662cb..21b4abb 100644 --- a/build/data_files/main_script_manifest.json +++ b/build/data_files/main_script_manifest.json @@ -9,7 +9,7 @@ "created": "Apr 4, 2020", "updated": "Oct 27, 2020", "desc": "**This script should no longer be needed after Google's removal of overlay ads on April 6th, 2023.**
\n
\nYou know those little overlay advertisements that pop up on the bottom center of YouTube videos? If those really annoy you, this simple userscript (really just a userstyle wrapped into a userscript) will help by simply preventing them from rendering.
\nNote that this _does not_ affect other ads.", - "version": "1.0" + "version": "1.0.0" }, { "name": "Fix YouTube Player Bottom Gradient", @@ -20,7 +20,7 @@ "created": "Feb 26, 2021", "updated": "Mar 30, 2021", "desc": "This \"fixes\" the excessively large bottom gradient area that sometimes appears on the YouTube video player when the mouse cursor is within the player frame.
\n**So far, I've only seen the phenomenon that led me to write this while using Vivaldi.**", - "version": "1.0" + "version": "1.0.0" }, { "name": "YouTube Channel Keyboard Protection", @@ -31,7 +31,7 @@ "created": "Nov 13, 2021", "updated": "May 1, 2022", "desc": "Prevents YouTube from hijacking the Up/Down arrow keys on channel pages, as it likes to do sometimes (Left and Right arrow keys are okay though, because those don't control page scrolling).", - "version": "1.1" + "version": "1.1.0" }, { "name": "Twitch Hide Content Disclosure", @@ -73,9 +73,9 @@ "license": "MIT", "autoUpdates": true, "created": "May 19, 2021", - "updated": "Dec 12, 2024", + "updated": "Feb 9, 2026", "desc": "Makes the video stats overlay on Twitch.tv video player partially transparent, so as to avoid obscuring the stream so much.", - "version": "1.1.1" + "version": "1.1.2" }, { "name": "GitHub Repo Network Tab", @@ -97,7 +97,7 @@ "created": "Apr 12, 2020", "updated": "Oct 28, 2021", "desc": "Makes the timeline on the Network page of GitHub repositories utilize more of that available whitespace on the sides.
\nStill can't seem to make it use all the space on the right side though...
\n
\nEssentially a subset of [Wide GitHub](https://github.com/xthexder/wide-github) which, of course, I only realized after I'd written this.
\nOh well, someone will probably find this useful.", - "version": "1.0" + "version": "1.0.0" }, { "name": "GitHub Notification Page Tweaks", @@ -108,7 +108,7 @@ "created": "Oct 22, 2020", "updated": "Aug 3, 2021", "desc": "Why does GitHub's beta notifications inbox use a \"More\" dropdown when there's more than enough space for the 2 elements within?
\nI don't know, and I dislike having to open a dropdown just to mark something as \"read\", so I did something about it.", - "version": "1.1" + "version": "1.1.0" }, { "name": "GitHub Sticky Editor Header", @@ -119,7 +119,7 @@ "created": "Nov 24, 2021", "updated": "Nov 24, 2021", "desc": "Makes the header of the (text) file editor on GitHub sticky.
\nWritten because I got sick and tired of having to move up and down the page to change to and from the preview while editing this README.", - "version": "1.0" + "version": "1.0.0" }, { "name": "GitLab Description In Title", @@ -130,7 +130,7 @@ "created": "May 22, 2021", "updated": "Aug 3, 2021", "desc": "Attempts to improve the page titles on GitLab by including the contents of the page's description, if one is provided.
\nThis also replaces instances of Unicode character 0x00B7, \"Middle Dot\", in the title, as I've found that particular character\nhas strangely led some editors to erroneously read and write the text in undesired encodings, such as GB2312, instead of UTF-8.", - "version": "1.1" + "version": "1.1.0" }, { "name": "Prettier Lib.rs Preformatted Code", @@ -141,7 +141,7 @@ "created": "Jul 5, 2020", "updated": "Mar 30, 2021", "desc": "Makes `
` blocks on lib.rs look more like they do on crates.io; lib.rs is so much faster thanks to reduced JS use, but it's not as pretty.",
-			"version": "1.0"
+			"version": "1.0.0"
 		},
 		{
 			"name": "Lib.rs Description In Title",
@@ -152,7 +152,7 @@
 			"created": "Apr 28, 2021",
 			"updated": "May 11, 2021",
 			"desc": "Replace the unhelpful part of the tab title on a lib.rs crate's page with the short description of the crate, if one is provided.
\nConvenient for bookmarking and tab-saving extensions, as pages are typically stored according to their titles.", - "version": "1.0" + "version": "1.0.0" }, { "name": "Crates.io Description In Title", @@ -174,7 +174,7 @@ "created": "Jun 19, 2020", "updated": "Apr 5, 2021", "desc": "Do you hate that Gmail shows a toast notification that blocks functional regions of the UI after you do something to any email? Me too!
\nThis little change should help mitigate the problem by moving the toast notification to the bottom center of the screen.", - "version": "1.0" + "version": "1.0.0" }, { "name": "Google Meet Ignore Hardware Disabled", @@ -185,7 +185,7 @@ "created": "Mar 3, 2023", "updated": "Mar 3, 2023", "desc": "A.K.A \"I know my hardware is disabled, Google\"
\nThanks Google, but I'm well aware that my browser hasn't given you permission to access my hardware; I don't need you showing a prompt that can't be closed with a keypress.", - "version": "1.0" + "version": "1.0.0" }, { "name": "Wider Google Form Fields", @@ -196,7 +196,7 @@ "created": "Sep 30, 2021", "updated": "Aug 19, 2022", "desc": "Widens the input fields in google forms from 50% to 100% of the question element (minus padding).", - "version": "1.1" + "version": "1.1.0" }, { "name": "Correct Google Form Correctness", @@ -207,7 +207,7 @@ "created": "Nov 9, 2021", "updated": "Nov 9, 2021", "desc": "Make fields that have been manually marked as correct take on the same styling as fields that exactly matched the preset correct answer.", - "version": "1.0" + "version": "1.0.0" }, { "name": "Google Search Lean Query Updates", @@ -240,7 +240,7 @@ "created": "Jan 23, 2021", "updated": "Apr 5, 2021", "desc": "This should disable changing the value of any numeric fields on Roll20 character sheets by scrolling.
\nTODO: Replace the use of setTimeout with a MutationObserver.", - "version": "1.0" + "version": "1.0.0" }, { "name": "Bypass Blogspot's Blogger IFrame", @@ -251,7 +251,7 @@ "created": "Jun 2, 2021", "updated": "May 1, 2022", "desc": "Unhide the page body and hide obstructive injected iframes on some Blogspot pages, which use those methods for reasons like discouraging ad blocking.", - "version": "1.1" + "version": "1.1.0" }, { "name": "Foxaholic Fixes", @@ -262,7 +262,7 @@ "created": "Jun 2, 2021", "updated": "Aug 27, 2021", "desc": "Fix Foxaholic's deliberate breaking of context menus, keypresses, and text selection.", - "version": "1.0" + "version": "1.0.0" }, { "name": "Mitigate Target \\_blank Risk", @@ -273,7 +273,7 @@ "created": "Aug 27, 2021", "updated": "Nov 23, 2021", "desc": "Appends `rel=\"noopener noreferrer\"` to every link (HTMLAnchorElement, not to be confused with HTMLLinkElement) that has `target=\"_blank\"`, preventing a possible security risk.
\nThis **_will_** break links to some sites, likely any links that would otherwise have opened in a new tab by default.
\nUsers may choose to ignore links from additional url origins, by setting the `customAllowedOrigins` key in the script's value storage to a list of origins, delimited by a single space character, `' '`.
\ne.g. Setting `customAllowedOrigins` to `'http://wordpress.com https://stackexchange.com https://novelupdates.com'` will prevent this script from modifying links to those origins.", - "version": "1.1" + "version": "1.1.0" }, { "name": "MSYS2 Package Description In Title", @@ -295,7 +295,7 @@ "created": "Apr 20, 2022", "updated": "Jun 18, 2022", "desc": "Modifies the format of the page title for some of CurseForge's Minecraft pages.", - "version": "1.1" + "version": "1.1.0" }, { "name": "Another \"Open In Steam\" Button", @@ -306,7 +306,7 @@ "created": "Nov 25, 2022", "updated": "Nov 25, 2022", "desc": "As the name should imply, this is my own version of a script which adds a new button on Steam's steampowered and steamcommunity sites to open the current page in the Steam app.
\nSome of the CSS used was borrowed from https://greasyfork.org/en/scripts/454372-open-steam-url after I spent well over an hour fiddling with my own CSS in the pre-dawn hours, and decided I wasn't going to manage much better.", - "version": "1.0" + "version": "1.0.0" }, { "name": "Ubuntu Packages Description In Title", @@ -317,7 +317,7 @@ "created": "May 11, 2023", "updated": "May 11, 2023", "desc": "Try to provide a minimal, yet meaningful, page title that includes the package description on Ubuntu's package search/archive website.", - "version": "1.0" + "version": "1.0.0" }, { "name": "Quietly Reject StackExchange Cookies", @@ -328,7 +328,7 @@ "created": "May 14, 2023", "updated": "May 14, 2023", "desc": "Hide the pesky cookie permission requests on StackExchange sites, which don't actually appear to set even \"necessary\" cookies until the user responds to the permission prompt.
\nAlso hides a few other little things that just don't warrant another tiny script.", - "version": "1.0" + "version": "1.0.0" }, { "name": "PyPI Description In Title", @@ -339,7 +339,7 @@ "created": "May 31, 2023", "updated": "Aug 15, 2024", "desc": "Rewrite the page title for a PyPI package to include a brief summary, when available.
\n
\nAlso doesn't use that centered dot character as a separator.", - "version": "1.0" + "version": "1.0.0" }, { "name": "Simple URL Tracker Cleaner", @@ -361,7 +361,7 @@ "created": "Apr 8, 2022", "updated": "Jul 2, 2023", "desc": "Hide posts from arbitrary subreddits (unless specifically looking at them, of course).
\n
\nOnly works for old.reddit.com, not www.reddit.com, because not only does the latter use a DOM structure that makes it unsuitable for applying styles to entire post-elements by the CSS selector of the child element holding the subreddit, it _also_ commits the desktop (and frankly, even mobile) user-experience war-crime of infinite pagination (endless scrolling). **TLDR: Modern Reddit UI sucks, and supporting it would take more effort than I'm willing to put in to this for my own use.**", - "version": "1.1" + "version": "1.1.0" }, { "name": "ScribbleHub Reading List Upgrades", @@ -372,7 +372,7 @@ "created": "Oct 7, 2022", "updated": "Jan 19, 2024", "desc": "Allows hiding novels the user is caught up on from their reading lists, adds the current reading list name to the page title, and more planned.", - "version": "1.2" + "version": "1.2.0" }, { "name": "NovelUpdates Reading List Upgrades", @@ -383,7 +383,7 @@ "created": "Jul 8, 2022", "updated": "Nov 16, 2022", "desc": "Allows hiding novels the user is caught up on from their reading lists, adds the current reading list name to the page title, and more planned.", - "version": "1.0" + "version": "1.0.0" }, { "name": "Softpedia Improvements", diff --git a/twitch_transparent_video_stats.user.js b/twitch_transparent_video_stats.user.js index 6090678..1ad2e4f 100644 --- a/twitch_transparent_video_stats.user.js +++ b/twitch_transparent_video_stats.user.js @@ -13,7 +13,7 @@ // @exclude-match https://www.twitch.tv/settings* // @exclude-match https://www.twitch.tv/turbo* // @exclude-match https://www.twitch.tv/annual-recap -// @version 1.1.1 +// @version 1.1.2 // @createdAt 5/19/2021 // @author StaticPH // @description Makes the video stats overlay 50% transparent @@ -25,7 +25,7 @@ // @icon https://brand.twitch.tv/assets/logos/svg/glitch/purple.svg // @grant GM.addStyle // @grant GM_addStyle -// @run-at document-start +// @run-at document-idle // ==/UserScript== (function(){ @@ -46,7 +46,8 @@ } GM.addStyle(` - div.video-player__overlay div.simplebar-scroll-content > div.simplebar-content > div { + div.video-player__overlay div.simplebar-scroll-content > div.simplebar-content > div, + [data-a-target="player-overlay-video-stats"] { opacity: 0.5; } `); From d72eac633a0736ff58c41746fcaca1ed5c538e3e Mon Sep 17 00:00:00 2001 From: StaticPH <7786502+StaticPH@users.noreply.github.com> Date: Mon, 9 Feb 2026 11:10:01 -0500 Subject: [PATCH 24/38] MSYS2 Package Description In Title: Add support for Base Package pages --- README.md | 2 +- build/data_files/main_script_manifest.json | 6 +++--- msys2_package_description_in_title.user.js | 17 +++++++++++------ 3 files changed, 15 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 108f3bb..ae294cd 100644 --- a/README.md +++ b/README.md @@ -55,7 +55,7 @@ To add a script: | [Bypass Blogspot's Blogger IFrame](#BBBI) | [install][raw-BBBI] | N/A | :heavy_check_mark: | MIT | Jun 2, 2021 | May 1, 2022 | | [Foxaholic Fixes](#FoxF) | [install][raw-FoxF] | N/A | :heavy_check_mark: | MIT | Jun 2, 2021 | Aug 27, 2021 | | [Mitigate Target \_blank Risk](#MTBR) | [install][raw-MTBR] | N/A | :heavy_check_mark: | MIT | Aug 27, 2021 | Nov 23, 2021 | -| [MSYS2 Package Description In Title](#MDIT) | [install][raw-MDIT] | N/A | :heavy_check_mark: | MIT | Apr 28, 2021 | Sep 28, 2024 | +| [MSYS2 Package Description In Title](#MDIT) | [install][raw-MDIT] | N/A | :heavy_check_mark: | MIT | Apr 28, 2021 | Feb 9, 2026 | | [Minecraft CurseForge Title Tweaks](#MCTT) | [install][raw-MCTT] | N/A | :heavy_check_mark: | MIT | Apr 20, 2022 | Jun 18, 2022 | | [Another "Open In Steam" Button](#OISB) | [install][raw-OISB] | N/A | :heavy_check_mark: | MIT | Nov 25, 2022 | Nov 25, 2022 | | [Ubuntu Packages Description In Title](#UPDIT) | [install][raw-UPDIT] | N/A | :heavy_check_mark: | MIT | May 11, 2023 | May 11, 2023 | diff --git a/build/data_files/main_script_manifest.json b/build/data_files/main_script_manifest.json index 21b4abb..af33274 100644 --- a/build/data_files/main_script_manifest.json +++ b/build/data_files/main_script_manifest.json @@ -282,9 +282,9 @@ "license": "MIT", "autoUpdates": true, "created": "Apr 28, 2021", - "updated": "Sep 28, 2024", - "desc": "Include the package description on the tab title for a package's page on packages.msys2.org/packages", - "version": "1.2.0" + "updated": "Feb 9, 2026", + "desc": "Include the package description on the tab title for a package's page on packages.msys2.org", + "version": "1.2.1" }, { "name": "Minecraft CurseForge Title Tweaks", diff --git a/msys2_package_description_in_title.user.js b/msys2_package_description_in_title.user.js index 2072e8e..28db64e 100644 --- a/msys2_package_description_in_title.user.js +++ b/msys2_package_description_in_title.user.js @@ -1,12 +1,13 @@ // ==UserScript== // @name MSYS Packages Description In Title // @namespace https://github.com/StaticPH +// @include http*://packages.msys2.org/base/* // @include http*://packages.msys2.org/package/* // @include http*://packages.msys2.org/packages/* -// @version 1.2.0 +// @version 1.2.1 // @createdAt 4/28/2021 // @author StaticPH -// @description Include the package description on the tab title for a package's page on packages.msys2.org/packages. +// @description Include the package description on the tab title for a package's page on packages.msys2.org. // @license MIT // @updateURL https://raw.githubusercontent.com/StaticPH/Userscripts/master/msys2_package_description_in_title.user.js // @downloadURL https://raw.githubusercontent.com/StaticPH/Userscripts/master/msys2_package_description_in_title.user.js @@ -22,12 +23,16 @@ setTimeout(function wait(){ const pkgName = document.querySelector('h4.card-title'); - const pkgDesc = document.querySelector('h6.card-subtitle, .card-body > dl > dd:nth-child(6)'); - - //TODO: Modify script to also indicate which pkg subpage is currently loaded (if it isnt the readme subpage) + let pkgDesc = null; + if (document.location.pathname.startsWith('/base/')){ + pkgDesc = document.querySelector('.card-body > dl > dd:nth-child(2)'); + } + else{ + pkgDesc = document.querySelector('h6.card-subtitle, .card-body > dl > dd:nth-child(6)'); + } if (pkgName && pkgDesc){ - document.title=`${pkgName.textContent.trim()} — ${pkgDesc.textContent.trim()}`; + document.title = `${pkgName.textContent.trim()} — ${pkgDesc.textContent.trim()}`; } else{ setTimeout(wait, 100); // Continue trying every 100ms until success From c5611ec46fdba3900444156474151c666bbdba22 Mon Sep 17 00:00:00 2001 From: StaticPH <7786502+StaticPH@users.noreply.github.com> Date: Fri, 27 Feb 2026 17:31:22 -0500 Subject: [PATCH 25/38] Github Repo Network Tab: Thanks for making it more annoying to find or work with meaningful elements using CSS selectors in a modern browser, GitHub. /s --- README.md | 2 +- build/data_files/main_script_manifest.json | 4 +- github_repo_network_tab.user.js | 95 +++++++++++++++++----- 3 files changed, 79 insertions(+), 22 deletions(-) diff --git a/README.md b/README.md index ae294cd..b8bc053 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ To add a script: | [Twitch Hide Channel Leaderboard](#THCL) | [install][raw-THCL] | N/A | :heavy_check_mark: | MIT | Jun 19, 2020 | Dec 12, 2024 | | [Twitch Hide Overlay Ads](#THOA) | [install][raw-THOA] | N/A | :heavy_check_mark: | MIT | Dec 14, 2023 | Dec 12, 2024 | | [Twitch Transparent Video Stats](#TTVS) | [install][raw-TTVS] | N/A | :heavy_check_mark: | MIT | May 19, 2021 | Feb 9, 2026 | -| [GitHub Repo Network Tab](#GRNT) | [install][raw-GRNT] | N/A | :heavy_check_mark: | MIT | Apr 6, 2020 | Feb 1, 2024 | +| [GitHub Repo Network Tab](#GRNT) | [install][raw-GRNT] | N/A | :heavy_check_mark: | MIT | Apr 6, 2020 | Feb 27, 2026 | | [Bigger GitHub Network Graph](#BGNG) | [install][raw-BGNG] | N/A | :heavy_check_mark: | MIT | Apr 12, 2020 | Oct 28, 2021 | | [GitHub Notification Page Tweaks](#GNPT) | [install][raw-GNPT] | N/A | :heavy_check_mark: | MIT | Oct 22, 2020 | Aug 3, 2021 | | [GitHub Sticky Editor Header](#GSEH) | [install][raw-GSEH] | N/A | :heavy_check_mark: | MIT | Nov 24, 2021 | Nov 24, 2021 | diff --git a/build/data_files/main_script_manifest.json b/build/data_files/main_script_manifest.json index af33274..5926c55 100644 --- a/build/data_files/main_script_manifest.json +++ b/build/data_files/main_script_manifest.json @@ -84,9 +84,9 @@ "license": "MIT", "autoUpdates": true, "created": "Apr 6, 2020", - "updated": "Feb 1, 2024", + "updated": "Feb 27, 2026", "desc": "Adds a navigation tab for faster access to the 'Network' page of a repository.
\n
\nKnown bugs:\n- Occasionally the tab fails to be added, with no clear explanation or pattern. If this occurs, simply reload the page.\n- When switching between repository tabs, the network tab sometimes disappears, and something about the way GitHub does page navigation within a repository doesn't cause this script to be re-injected. Short of constantly checking state on a sub-second timer, or using a mutation observer, I don't know how else to solve this.", - "version": "1.7.2" + "version": "1.8.0" }, { "name": "Bigger GitHub Network Graph", diff --git a/github_repo_network_tab.user.js b/github_repo_network_tab.user.js index 95b3e3b..0d8a5b3 100644 --- a/github_repo_network_tab.user.js +++ b/github_repo_network_tab.user.js @@ -25,7 +25,7 @@ // @exclude-match https://github.com/topics* // @exclude-match https://github.com/trending* // @exclude-match https://github.com/users/*/projects/* -// @version 1.7.2 +// @version 1.8.0 // @createdAt 4/06/2020 // @author StaticPH // @description Adds a navigation tab for faster access to the 'Network' page of a repository. @@ -48,16 +48,16 @@ return location.pathname.split('/', 3).slice(1).join('/'); })(); + const networkIconSvgHTML = ''; + /* Honestly, I feel like creating the HTML directly is less of a hassle than creating all the elements with JavaScript */ function createBigNetworkTabHTML(){ // Exclude analytical "data-ga-click" and "data-selected-links" attributes return '\n' + - ' \n' + + '\t' + networkIconSvgHTML + '\n' + ' \n' + ' Network\n' + - ' \n' + + ' \n' + '\n'; //TODO: Intelligently determine if the link element should have 'style="visibility:hidden;"' to start with? } @@ -81,6 +81,53 @@ '
  • '; } + function maybeFixHighlightedTab(){ + if (location.pathname.endsWith(here + '/network') || location.pathname.endsWith(here + '/network/')){ + let networkTab = document.querySelector('[data-tab-item="i2_1network-tab"]'); + let insightsTab = document.querySelector('[data-tab-item="i7insights-tab"]'); + + if (insightsTab /*&& insightsTab.hasAttribute('aria-current')*/){ + insightsTab.removeAttribute('aria-current'); + insightsTab.classList.remove('selected'); + } + if (networkTab){ + networkTab.setAttribute('aria-current', 'page'); + networkTab.classList.add('selected'); + } + } + } + + function doesNeedModernTabVariant(){ + // Thanks for making it more annoying to find or work with meaningful elements using CSS selectors, GitHub. /s + return document.querySelector('nav[class*="prc-components-UnderlineWrapper"]') !== null; + } + + function modernUIAddNetworkTab(){ + const prTabLink = document.querySelector(`li.prc-UnderlineNav-UnderlineNavItem-syRjR > a[href="/${here}/pulls"]`); + if (!prTabLink){ return false; } // Not ready yet... or GitHub changed shit again. + + const dataAttrs = 'data-turbo-frame="repo-content-turbo-frame" data-discover="true"'; + const isActiveTab = (location.pathname.endsWith('/network') || location.pathname.endsWith('/network/')); + const tabHTML = '
  • \n' + + `\n` + + ` ${networkIconSvgHTML}\n` + + // May want to skip adding actual text manually due to css attr magic setting value from data-content + ' Network\n' + + '\n' + + '
  • '; + prTabLink.parentElement.insertAdjacentHTML('afterend', tabHTML); + + const networkTab = document.querySelector('#bigNetworkTab'); + if (isActiveTab){ + const falseActiveTab = document.querySelector('li.prc-UnderlineNav-UnderlineNavItem-syRjR > a[aria-current]'); + if (falseActiveTab){ + falseActiveTab.removeAttribute('aria-current'); + } + networkTab.setAttribute('aria-current', 'page'); + } + return networkTab; + } + //TODO: Consider insertion at Nth element position, rather than relative to PR tab. setTimeout(function wait(){ /* Find the 'Pull Requests' tab; inserting the new Network tab immediately after it ensures consistent placement. */ @@ -120,29 +167,39 @@ else if (dropdownRetries >= dropdownRetryLimit){ console.log(`Number of attempts at adding Network tab to dropdown have exceeded the limit of ${dropdownRetryLimit} attempts. Giving up.`); } - else{ + else { console.log(`Waiting ${(dropdownRetries * 500) + 500}ms for page to load further before attempting insertion of dropdown-item.`); dropdownRetries++; setTimeout(waitmore, (dropdownRetries * 500) + 500); } }); - if (location.pathname.endsWith(here + '/network') || location.pathname.endsWith(here + '/network/')){ - let networkTab = document.querySelector('[data-tab-item="i2_1network-tab"]'); - let insightsTab = document.querySelector('[data-tab-item="i7insights-tab"]'); - - if (insightsTab /*&& insightsTab.hasAttribute('aria-current')*/){ - insightsTab.removeAttribute('aria-current'); - insightsTab.classList.remove('selected'); - } - if (networkTab){ - networkTab.classList.add('selected'); - } + maybeFixHighlightedTab(); + } + else if (doesNeedModernTabVariant()){ + if (modernUIAddNetworkTab()){ + console.log('Added Network tab to modern nagivation menu.'); + (async function(){ + return await setInterval(function babysit(){ + // Compensate for React's DOM fuckery often regenerating the navigation tabs (and who knows what else) shortly after document-idle; + // check back every 5 seconds. + if (!document.querySelector('#bigNetworkTab')){ + console.log('Compensating for React DOM fuckery regenerating the navigation tabs. Re-adding Network tab'); + if (modernUIAddNetworkTab()){ + console.log('Network tab re-added to modern navigation menu.'); + }; + } + }, 5000); + })(); + } + else { + console.log('Modern UI required; waiting 300ms for page to load further.'); + return setTimeout(wait, 300); } } - else{ + else { console.log('Waiting 300ms for page to load further.'); - setTimeout(wait, 300); + return setTimeout(wait, 300); } }); })(); From a41832113ef924b5a7e10f713ed2a82fa8a9ec58 Mon Sep 17 00:00:00 2001 From: StaticPH <7786502+StaticPH@users.noreply.github.com> Date: Sat, 28 Feb 2026 00:55:15 -0500 Subject: [PATCH 26/38] GitHub Issue Comments Legacy Workaround: Relax a selector. GitHub Collapsed Details Legacy Workaround: Unconditionally remove and add a CSS class instead of attempting to replace and falling back to adding. GitHub Lazy Release Assets Legacy Workaround: Made a selector more strict. --- build/data_files/legacy_scripts.json | 37 +++++++++++-------- ...ithub_collapsed_details_workaround.user.js | 13 ++++--- ...thub_lazy_release_asset_workaround.user.js | 4 +- ...hub_show_issue_comments_workaround.user.js | 7 ++-- 4 files changed, 35 insertions(+), 26 deletions(-) diff --git a/build/data_files/legacy_scripts.json b/build/data_files/legacy_scripts.json index 32f83fb..b287537 100644 --- a/build/data_files/legacy_scripts.json +++ b/build/data_files/legacy_scripts.json @@ -5,70 +5,77 @@ "anchorString": "DFSF", "path": "/legacy_browser_workarounds/discourse_forum_scroll_fixer.user.js", "license": "MIT", - "autoUpdates": ":heavy_check_mark:", + "autoUpdates": true, "created": "Jun 29, 2024", "updated": "Mar 23, 2025", - "desc": "Fix for Discourse forums breaking the ability to scroll on browsers that are too old or are blocking some script or other." + "desc": "Fix for Discourse forums breaking the ability to scroll on browsers that are too old or are blocking some script or other.", + "version": "1.0.4" }, { "name": "GitHub Line Hyperlink Workaround", "anchorString": "GLHW", "path": "/legacy_browser_workarounds/github_line_hyperlink_workaround.user.js", "license": "MIT", - "autoUpdates": ":heavy_check_mark:", + "autoUpdates": true, "created": "Aug 10, 2022", "updated": "Nov 18, 2022", - "desc": "Add simple onclick handlers to the line numbers when viewing files on GitHub, as the normal behavior of linking directly to a clicked line number seems to have broken on legacy browsers as a result of some change to the implementation." + "desc": "Add simple onclick handlers to the line numbers when viewing files on GitHub, as the normal behavior of linking directly to a clicked line number seems to have broken on legacy browsers as a result of some change to the implementation.", + "version": "1.1.0" }, { "name": "GitHub Notifications Archive Workaround", "anchorString": "GNAW", "path": "/legacy_browser_workarounds/github_notifications_archive_workaround.user.js", "license": "MIT", - "autoUpdates": ":heavy_check_mark:", + "autoUpdates": true, "created": "Jul 10, 2022", "updated": "Mar 12, 2023", - "desc": "Quick and simple redirect to work around strange behavior of being sent to github.com/notifications/beta/archive when marking notifications as done." + "desc": "Quick and simple redirect to work around strange behavior of being sent to github.com/notifications/beta/archive when marking notifications as done.", + "version": "1.1.0" }, { "name": "GitHub Collapsed Details Workaround", "anchorString": "GCDW", "path": "/legacy_browser_workarounds/github_collapsed_details_workaround.user.js", "license": "MIT", - "autoUpdates": ":heavy_check_mark:", + "autoUpdates": true, "created": "Sep 30, 2022", "updated": "Jun 10, 2023", - "desc": "Add simple onclick handlers to the collapsed details of commits on GitHub, as the normal behavior of expanding the ellipses to the full commit message when clicked seems to have broken on legacy browsers as a result of some change to the implementation." + "desc": "Add simple onclick handlers to the collapsed details of commits on GitHub, as the normal behavior of expanding the ellipses to the full commit message when clicked seems to have broken on legacy browsers as a result of some change to the implementation.", + "version": "1.2.1" }, { "name": "GitHub Lazy Release Asset Workaround", "anchorString": "GLRAW", "path": "/legacy_browser_workarounds/github_lazy_release_asset_workaround.user.js", "license": "MIT", - "autoUpdates": ":heavy_check_mark:", + "autoUpdates": true, "created": "Oct 8, 2022", "updated": "Mar 12, 2023", - "desc": "Multiple fixes related to user-downloadable asset files on GitHub for users of legacy browsers.\n- Fetch asset list for releases, as the code that should already have been responsible for that is too modern, and is thus never even attempted on legacy browsers.\n- Fix the timestamps on the release page(s), most of which are within asset lists.\n- Slightly changes normal behavior by automatically showing __all__ assets for the first release on the page, whether that's two assets or fourty assets." + "desc": "Multiple fixes related to user-downloadable asset files on GitHub for users of legacy browsers.\n- Fetch asset list for releases, as the code that should already have been responsible for that is too modern, and is thus never even attempted on legacy browsers.\n- Fix the timestamps on the release page(s), most of which are within asset lists.\n- Slightly changes normal behavior by automatically showing __all__ assets for the first release on the page, whether that's two assets or fourty assets.", + "version": "1.1.1" }, { "name": "GitHub Show Issue Comments Workaround", "anchorString": "GSICW", "path": "/legacy_browser_workarounds/github_show_issue_comments_workaround.user.js", "license": "MIT", - "autoUpdates": ":heavy_check_mark:", + "autoUpdates": true, "created": "Nov 10, 2025", "updated": "Nov 10, 2025", - "desc": "Manually display comments on Github issues using the JSON that's already on the page, which totally doesn't need React to accomplish." + "desc": "Manually display comments on Github issues using the JSON that's already on the page, which totally doesn't need React to accomplish.", + "version": "1.0.1" }, { "name": "StackExchange Legacy Comments Expander", "anchorString": "SELCE", "path": "/legacy_browser_workarounds/stackexchange_legacy_comments_expander.user.js", "license": "MIT", - "autoUpdates": ":heavy_check_mark:", + "autoUpdates": true, "created": "Nov 6, 2022", "updated": "Nov 2, 2023", - "desc": "Replace 'Show X more comments' handler for StackExchange sites to better support older browsers; in particular, this enables showing all comments when using Chromium 72." + "desc": "Replace 'Show X more comments' handler for StackExchange sites to better support older browsers; in particular, this enables showing all comments when using Chromium 72.", + "version": "1.1.0" } ] -} +} \ No newline at end of file diff --git a/legacy_browser_workarounds/github_collapsed_details_workaround.user.js b/legacy_browser_workarounds/github_collapsed_details_workaround.user.js index ba3a2ff..4916e23 100644 --- a/legacy_browser_workarounds/github_collapsed_details_workaround.user.js +++ b/legacy_browser_workarounds/github_collapsed_details_workaround.user.js @@ -25,7 +25,7 @@ // @exclude-match https://github.com/topics* // @exclude-match https://github.com/trending* // @exclude-match https://github.com/users/*/projects/* -// @version 1.2 +// @version 1.2.1 // @createdAt 9/30/2022, 9:32:58 PM // @author StaticPH // @description Add simple onclick handlers to the collapsed details of commits on GitHub, as the normal behavior of expanding the ellipses to the full commit message when clicked seems to have broken on legacy browsers as a result of some change to the implementation. Also fixes some other instances of non-functioning collapsing elements. @@ -64,9 +64,12 @@ // let commitRow = evnt.target.closest('.Details').querySelector('p+*'); let commitRow = evnt.target.closest('.Details').querySelector('.Details-content--hidden, .Details-content--on') || evnt.target.closest('.Details').querySelector('.text-small').parentElement; commitRow.classList.toggle('Details-content--hidden'); - hasRefinedGithub && commitRow.closest('.rgh-dim-bot').classList.toggle('Details--on'); + if (hasRefinedGithub){ + commitRow.closest('.rgh-dim-bot').classList.toggle('Details--on'); + } } + /* oxlint-disable-next-line unicorn/prefer-add-event-listener */ document.querySelectorAll('.hidden-text-expander > button.ellipsis-expander.js-details-target').forEach(expander => expander.onclick = toggleShowDetails); if (urlRelativeToRepoDefault.startsWith('/wiki')){ @@ -110,9 +113,9 @@ evnt.target.parentElement.querySelector('[data-target="annotation-message.showLessButton"]').toggleAttribute('hidden'); } else { // Normally implies that classList contains 'annotation--expanded' - // replace 'annotation--expanded' with 'annotation--contracted' if the former exists, otherwise just add the latter; - // the second case is a fallback in case the class was previously just removed entirely, rather than replaced. - annotationBody.classList.replace('annotation--expanded', 'annotation--contracted') || annotationBody.classList.add('annotation--contracted'); + // Always attempt to remove the `annotation--expanded` class from annotationBody, and ensure it always has the `annotation--contracted` class. + annotationBody.classList.remove('annotation--expanded'); + annotationBody.classList.add('annotation--contracted'); evnt.target.toggleAttribute('hidden'); evnt.target.parentElement.querySelector('[data-target="annotation-message.showMoreButton"]').toggleAttribute('hidden'); } diff --git a/legacy_browser_workarounds/github_lazy_release_asset_workaround.user.js b/legacy_browser_workarounds/github_lazy_release_asset_workaround.user.js index e23c952..f9157e1 100644 --- a/legacy_browser_workarounds/github_lazy_release_asset_workaround.user.js +++ b/legacy_browser_workarounds/github_lazy_release_asset_workaround.user.js @@ -2,7 +2,7 @@ // @name GitHub Lazy Release Assets Legacy Workaround // @namespace https://github.com/StaticPH // @match https://github.com/*/*/releases* -// @version 1.1 +// @version 1.1.1 // @createdAt 10/8/2022, 4:40:25 PM // @author StaticPH // @description Fixes a number of things related to user-downloadable asset files on GitHub for users of legacy browsers. @@ -67,7 +67,7 @@ }); } - document.querySelectorAll('[data-view-component] include-fragment[loading="lazy"][src]:not([src=""])').forEach(async function(lazyPageFrag){ + document.querySelectorAll('[data-view-component] include-fragment[loading="lazy"][src]:not([src=""]):not([data-target="select-panel.includeFragment"])').forEach(async function(lazyPageFrag){ try{ await fetch(lazyPageFrag.getAttribute('src'), requestTemplate).then( resp => resp.text().then( diff --git a/legacy_browser_workarounds/github_show_issue_comments_workaround.user.js b/legacy_browser_workarounds/github_show_issue_comments_workaround.user.js index adcbfee..867cd21 100644 --- a/legacy_browser_workarounds/github_show_issue_comments_workaround.user.js +++ b/legacy_browser_workarounds/github_show_issue_comments_workaround.user.js @@ -2,7 +2,7 @@ // @name GitHub Issue Comments Legacy Workaround // @namespace https://github.com/StaticPH // @match https://github.com/*/*/issues/* -// @version 1.0.0 +// @version 1.0.1 // @createdAt 11/10/2025, 6:17:25 PM // @author StaticPH // @description Manually display comments on Github issues using the JSON that's already on the page, which totally doesn't need React to accomplish. @@ -99,10 +99,9 @@ } function fixIssueTimeline(){ - const commentContainer = document.querySelector('div.react-comments-container > div.IssueViewer-module__commentsContainer--H8wxg'); + const commentContainer = document.querySelector('div.react-comments-container > div[class*="IssueViewer-module__commentsContainer"]'); const frag = document.createDocumentFragment(); - const substContainer = document.createElement('div'); - substContainer.className = 'IssueViewer-module__commentsContainer--H8wxg'; + const substContainer = commentContainer.cloneNode(); // fix borked styles substContainer.insertAdjacentHTML('beforeEnd', ``); From 4ea72155688fbcf25526e3423d18c3eb11177e76 Mon Sep 17 00:00:00 2001 From: StaticPH <7786502+StaticPH@users.noreply.github.com> Date: Sat, 28 Feb 2026 19:29:07 -0500 Subject: [PATCH 27/38] GitHub Issue Comments Legacy Workaround: Slightly simplify the non-functional reactions button, and hardcode a tooltip. It's not like anyone but me will use this, and I know what to expect in the first place. --- ...hub_show_issue_comments_workaround.user.js | 20 +++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/legacy_browser_workarounds/github_show_issue_comments_workaround.user.js b/legacy_browser_workarounds/github_show_issue_comments_workaround.user.js index 867cd21..d90aee4 100644 --- a/legacy_browser_workarounds/github_show_issue_comments_workaround.user.js +++ b/legacy_browser_workarounds/github_show_issue_comments_workaround.user.js @@ -2,7 +2,7 @@ // @name GitHub Issue Comments Legacy Workaround // @namespace https://github.com/StaticPH // @match https://github.com/*/*/issues/* -// @version 1.0.1 +// @version 1.0.2 // @createdAt 11/10/2025, 6:17:25 PM // @author StaticPH // @description Manually display comments on Github issues using the JSON that's already on the page, which totally doesn't need React to accomplish. @@ -20,7 +20,9 @@ (function(){ "use strict"; - const reactionToolbarHTML = `` + const reactionIconHTML = ''; + const reactionToolbarHTML = ``; + const fixedStyles = ` .dShPvE { display: flex; @@ -112,4 +114,18 @@ commentContainer.replaceWith(frag); } fixIssueTimeline(); + + /* + document.querySelectorAll('[aria-label="Reactions"]').forEach(function(ele){ + const btn = ele.querySelector('button[aria-labelledby=":rr:"]'); + if (!btn || btn.title){ return; } // No need to substitute a tooltip + if (btn.ariaDescribedBy === ':rq:-loading-announcement){ + btn.removeAttribute('aria-describedby'); + } + const oldLabelEle = ele.querySelector('[id=":rr:"]'); + if (!oldLabelEle){ return; } // No need to substitute a tooltip + btn.title = oldLabelEle.textContent; + oldLabelEle.remove(); // Will likely break the reaction menu popover, if I ever got around to fixing it in a way that resembles the modern standard behavior. + }); + */ // Hardcoded simplification, since the dummy reactions buttons are just constant raw HTML being applied by this script anyways. })(); From 4af43b64601cafa3e424c6b3f958445db59d1724 Mon Sep 17 00:00:00 2001 From: StaticPH <7786502+StaticPH@users.noreply.github.com> Date: Sat, 28 Feb 2026 19:41:03 -0500 Subject: [PATCH 28/38] GitHub Issue Comments Legacy Workaround: Add tooltips for long descriptions to Issue labels. While not strictly within the scope of the script, it seemed like expanding upon this later might help cover some bases. --- ...hub_show_issue_comments_workaround.user.js | 52 ++++++++++++++++++- 1 file changed, 51 insertions(+), 1 deletion(-) diff --git a/legacy_browser_workarounds/github_show_issue_comments_workaround.user.js b/legacy_browser_workarounds/github_show_issue_comments_workaround.user.js index d90aee4..c0ba037 100644 --- a/legacy_browser_workarounds/github_show_issue_comments_workaround.user.js +++ b/legacy_browser_workarounds/github_show_issue_comments_workaround.user.js @@ -2,7 +2,7 @@ // @name GitHub Issue Comments Legacy Workaround // @namespace https://github.com/StaticPH // @match https://github.com/*/*/issues/* -// @version 1.0.2 +// @version 1.1.0 // @createdAt 11/10/2025, 6:17:25 PM // @author StaticPH // @description Manually display comments on Github issues using the JSON that's already on the page, which totally doesn't need React to accomplish. @@ -113,7 +113,57 @@ frag.append(substContainer); commentContainer.replaceWith(frag); } + + function redoIssueLabelTooltips(){ + // Add tooltips for long descriptions to Issue labels. + /* + document.querySelectorAll('[aria-describedby*="-tooltip"]').forEach(function(ele){ + const tooltipIDSelector = ele.getAttribute('aria-describedby').split(' ').map(s => `[id="${s}"]`).join(','); + // Even if there may be multiple IDs, as the spec permits, take whatever is found first. + const descriptor = document.querySelector(tooltipIDSelector); + + if(!descriptor){ + console.warn(`ERROR: unable to find an element matching the selector "${tooltipIDSelector}"`); + return; + } + ele.title = descriptor.textContent.trim(); + descriptor.remove(); + ele.removeAttribute('aria-describedby'); + }); + */ + + // Has a similar overall effect, but less explicit DOM manipulation, I guess? + document.head.insertAdjacentHTML('beforeEnd', ` + `); + // The attribute `role="tooltip"` isn't already added by GitHub, even though aria-describedby is. + // Not sure what was expected to happen like that. + document.querySelectorAll('.sr-only[id*="-tooltip"]').forEach(e => e.setAttribute('role', 'tooltip')); + } + fixIssueTimeline(); + redoIssueLabelTooltips(); /* document.querySelectorAll('[aria-label="Reactions"]').forEach(function(ele){ From 1d4ed11505c00d34bec6005c877ab137368f4a50 Mon Sep 17 00:00:00 2001 From: StaticPH <7786502+StaticPH@users.noreply.github.com> Date: Sat, 28 Feb 2026 20:44:09 -0500 Subject: [PATCH 29/38] GitHub Issue Comments Legacy Workaround: Use friendly, localized, absolute timestamps because GitHub's relative-time-element isn't loading for some reason, which results in the custom element not showing any time. --- build/data_files/legacy_scripts.json | 4 ++-- ...hub_show_issue_comments_workaround.user.js | 19 +++++++++++++++---- 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/build/data_files/legacy_scripts.json b/build/data_files/legacy_scripts.json index b287537..dc30e2f 100644 --- a/build/data_files/legacy_scripts.json +++ b/build/data_files/legacy_scripts.json @@ -62,9 +62,9 @@ "license": "MIT", "autoUpdates": true, "created": "Nov 10, 2025", - "updated": "Nov 10, 2025", + "updated": "Mar 1, 2026", "desc": "Manually display comments on Github issues using the JSON that's already on the page, which totally doesn't need React to accomplish.", - "version": "1.0.1" + "version": "1.1.1" }, { "name": "StackExchange Legacy Comments Expander", diff --git a/legacy_browser_workarounds/github_show_issue_comments_workaround.user.js b/legacy_browser_workarounds/github_show_issue_comments_workaround.user.js index c0ba037..535fc41 100644 --- a/legacy_browser_workarounds/github_show_issue_comments_workaround.user.js +++ b/legacy_browser_workarounds/github_show_issue_comments_workaround.user.js @@ -2,7 +2,7 @@ // @name GitHub Issue Comments Legacy Workaround // @namespace https://github.com/StaticPH // @match https://github.com/*/*/issues/* -// @version 1.1.0 +// @version 1.1.1 // @createdAt 11/10/2025, 6:17:25 PM // @author StaticPH // @description Manually display comments on Github issues using the JSON that's already on the page, which totally doesn't need React to accomplish. @@ -55,8 +55,19 @@ // Each *COMMENT* item in responseNodesData has the following properties (non-exhaustive): {author:{avatarUrl, id, login, name, profileUrl}, bodyHTML, bodyVersion, createdAt, databaseId, id, lastEditedAt, lastUserContentEdit:{editor:{id, login, url, __typename}, id}, reactionGroups, url} const responseNodesData = responses.map(e => e.node); + const friendlyTimeFormatter = new Intl.DateTimeFormat(navigator.language, { numberingSystem: 'ltn', calendar: 'gregory', year: 'numeric', month: 'long', day: 'numeric', hour: 'numeric', hour12: true, minute: 'numeric', second: 'numeric' }); + + function buildTimeElement(timestamp){ + return `${ + // Until I come up with a way to make relative-time-element load + // (instead of being skipped due to earlier parsing errors), + // just use the absolute time in a friendly format + friendlyTimeFormatter.format(new Date(timestamp)) + }`; + } + function buildCommentNode(commentNode){ - return `\t
    + return `\t
    ${commentNode.author.login}
    @@ -65,14 +76,14 @@
    -

    ${commentNode.author.login} commented

    +

    ${commentNode.author.login} commented ${buildTimeElement(commentNode.createdAt)}

    @${commentNode.author.login}
    From 40bde333dea49f3bb32950891a3b38b25b834cec Mon Sep 17 00:00:00 2001 From: StaticPH <7786502+StaticPH@users.noreply.github.com> Date: Wed, 11 Mar 2026 18:33:03 -0400 Subject: [PATCH 30/38] GitHub Lazy Release Assets Legacy Workaround: Convert all times to locale's absolute time, so that there's at least a time and a year on everything that needs it. StackExchange Legacy Comments Expander: Re-implement expanding comments on answers, because that's somehow different from comments on the question itself. Add an entry to the exclusions list for Github Repo Network Tab and GitHub Collapsed Details Legacy Workaround. --- github_repo_network_tab.user.js | 1 + ...ithub_collapsed_details_workaround.user.js | 1 + ...thub_lazy_release_asset_workaround.user.js | 29 +++-- ...kexchange_legacy_comments_expander.user.js | 116 +++++++++++++++++- 4 files changed, 133 insertions(+), 14 deletions(-) diff --git a/github_repo_network_tab.user.js b/github_repo_network_tab.user.js index 0d8a5b3..a230395 100644 --- a/github_repo_network_tab.user.js +++ b/github_repo_network_tab.user.js @@ -9,6 +9,7 @@ // @exclude-match https://github.com/enterprise* // @exclude-match https://github.com/explore* // @exclude-match https://github.com/features* +// @exclude-match https://github.com/github-copilot/* // @exclude-match https://github.com/login/* // @exclude-match https://github.com/marketplace* // @exclude-match https://github.com/new* diff --git a/legacy_browser_workarounds/github_collapsed_details_workaround.user.js b/legacy_browser_workarounds/github_collapsed_details_workaround.user.js index 4916e23..a71559e 100644 --- a/legacy_browser_workarounds/github_collapsed_details_workaround.user.js +++ b/legacy_browser_workarounds/github_collapsed_details_workaround.user.js @@ -9,6 +9,7 @@ // @exclude-match https://github.com/enterprise* // @exclude-match https://github.com/explore* // @exclude-match https://github.com/features* +// @exclude-match https://github.com/github-copilot/* // @exclude-match https://github.com/login/* // @exclude-match https://github.com/marketplace* // @exclude-match https://github.com/new* diff --git a/legacy_browser_workarounds/github_lazy_release_asset_workaround.user.js b/legacy_browser_workarounds/github_lazy_release_asset_workaround.user.js index f9157e1..738d91c 100644 --- a/legacy_browser_workarounds/github_lazy_release_asset_workaround.user.js +++ b/legacy_browser_workarounds/github_lazy_release_asset_workaround.user.js @@ -2,7 +2,7 @@ // @name GitHub Lazy Release Assets Legacy Workaround // @namespace https://github.com/StaticPH // @match https://github.com/*/*/releases* -// @version 1.1.1 +// @version 1.1.2 // @createdAt 10/8/2022, 4:40:25 PM // @author StaticPH // @description Fixes a number of things related to user-downloadable asset files on GitHub for users of legacy browsers. @@ -40,11 +40,12 @@ 'method': 'GET', 'mode': 'cors' }; - const timestampPreset = { month: 'short', year: 'numeric', day: 'numeric', hour: 'numeric', minute: 'numeric' }; + const timestampPreset = new Intl.DateTimeFormat(navigator.language, { numberingSystem: 'ltn', calendar: 'gregory', year: 'numeric', month: 'short', day: 'numeric', hour: 'numeric', hour12: true, minute: 'numeric' }); async function localizeTimestamp(dateObj){ - return await dateObj.toLocaleString(navigator.language, timestampPreset); + return await timestampPreset.format(dateObj); } + /* // While on the topic of fixing things, fix all the timestamps on the page that don't seem to want to display. // Use the same format as GitHub would be, by utilizing the attributes of the local-time elements. async function fixDate(ele){ @@ -56,16 +57,20 @@ }); } document.querySelectorAll('section local-time:first-of-type').forEach(fixDate); + */ // Similar to fixDate, but tailored for relative-time rather than local-time // FIXME: the format for relative times should probably be different. Check and confirm. async function fixTime(ele){ - ele.textContent = await new Date(ele.getAttribute('datetime')).toLocaleString(navigator.language, { - month: ele.getAttribute('month') || undefined, - day: ele.getAttribute('day') || undefined, - year: ele.getAttribute('year') || undefined - }); + // ele.textContent = await new Date(ele.getAttribute('datetime')).toLocaleString(navigator.language, { + // month: ele.getAttribute('month') || undefined, + // day: ele.getAttribute('day') || undefined, + // year: ele.getAttribute('year') || undefined + // }); + //// Screw it, just use absolute time for the locale. + ele.textContent = await localizeTimestamp(new Date(ele.getAttribute('datetime'))); } + document.querySelectorAll('section relative-time:first-of-type').forEach(fixTime); document.querySelectorAll('[data-view-component] include-fragment[loading="lazy"][src]:not([src=""]):not([data-target="select-panel.includeFragment"])').forEach(async function(lazyPageFrag){ try{ @@ -73,8 +78,8 @@ resp => resp.text().then( async function(html){ await lazyPageFrag.replaceChildren(...parser.parseFromString(html, 'text/html').querySelectorAll('body > [data-view-component]')); - await lazyPageFrag.querySelectorAll('local-time').forEach(await fixDate); - await lazyPageFrag.querySelectorAll('relative-time').forEach(await fixTime); // FIXME: the format for relative times should probably be different. + // await lazyPageFrag.querySelectorAll('local-time').forEach(await fixDate); + await lazyPageFrag.querySelectorAll('relative-time').forEach(await fixTime); }, err => console.warn('There was a problem retrieving the response text', err) ), @@ -91,8 +96,8 @@ resp => resp.text().then( async function(html){ await deferredPageFrag.replaceChildren(...parser.parseFromString(html, 'text/html').querySelectorAll('body > [data-view-component]')); - await deferredPageFrag.querySelectorAll('local-time').forEach(await fixDate); - await deferredPageFrag.querySelectorAll('relative-time').forEach(await fixTime); // FIXME: the format for relative times should probably be different. + // await deferredPageFrag.querySelectorAll('local-time').forEach(await fixDate); + await deferredPageFrag.querySelectorAll('relative-time').forEach(await fixTime); }, err => console.warn('There was a problem retrieving the response text', err) ), diff --git a/legacy_browser_workarounds/stackexchange_legacy_comments_expander.user.js b/legacy_browser_workarounds/stackexchange_legacy_comments_expander.user.js index f4aab5f..5411852 100644 --- a/legacy_browser_workarounds/stackexchange_legacy_comments_expander.user.js +++ b/legacy_browser_workarounds/stackexchange_legacy_comments_expander.user.js @@ -8,7 +8,7 @@ // @match https://stackexchange.com/* // @match https://*.stackoverflow.com/* // @match https://*.stackexchange.com/* -// @version 1.1 +// @version 1.2.0 // @createdAt 11/6/2022, 1:17:14 AM // @author StaticPH // @description Replace 'Show X more comments' handler for StackExchange sites to better support older browsers; in particular, this enables showing all comments when using Chromium 72. @@ -20,7 +20,7 @@ // @icon https://cdn.sstatic.net/Sites/stackoverflow/Img/favicon.ico // @grant none // @noframes -// @run-at document-load +// @run-at document-idle // ==/UserScript== (function(){ @@ -44,6 +44,87 @@ return replaceChildrenWithNodes(parentEle, ...responseHtml.querySelectorAll('li')); } + function replaceCommentsListFromFetched(insertInto, data){ + const parser = new DOMParser(); + const responseHtml = parser.parseFromString(`
      ${data}
    `, 'text/html'); + return replaceChildrenWithNodes(insertInto, responseHtml.body.firstElementChild); + } + + const replySVG = ''; + const commentUpvoteSVG = ''; + const ellipsesSVG = ''; + + async function buildReplyTemplate(reply, postID){ + return await `
    +
    +
    +
    + + + +
    +
    +
    +
    + +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    ${reply.htmlBody}
    + +
    +
    +
    +
    + + + + +
    +
    +
    +
    +
    +
    +
    +
    `; + } + function onExpandComments(evnt){ if (evnt.target.matches('.answer a.js-show-link, .question a.js-show-link')){ evnt.stopImmediatePropagation(); @@ -70,7 +151,38 @@ */ .then(data => replaceChildrenWithFetched(insertInto, data) && evnt.target.parentElement.remove(), insertInto.setAttribute('data-remaining-comments-count', '0')); } + else if (evnt.target.matches('.answer button.comments-link:not([data-so-test*="parent-answer"])')){ + evnt.stopImmediatePropagation(); + evnt.preventDefault(); + const answer = evnt.target.closest('.answer'); + const postID = answer.getAttribute('data-answerid') || answer.getAttribute('data-questionid'); + const followupScriptEle = answer.querySelector('script[type="application/json"]'); + const followupData = JSON.parse(followupScriptEle.textContent); + const insertInto = answer.querySelector(`#${followupData.containerElementId} [role="list"]`); + // for (reply of followupData.replies){ + // insertInto.insertAdjacentHTML('beforeEnd', buildReplyTemplate(reply, postID)); // Doesn't fix the order to be chronological, and that seems like a hassle. + //} + + fetch(`${document.location.origin}/posts/${postID}/comments`, { + 'headers': { + 'accept': 'text/html, */*; q=0.01', + }, + 'referrerPolicy': 'strict-origin-when-cross-origin', + 'body': null, + 'method': 'GET', + 'mode': 'cors', + 'credentials': 'include' + }).then(resp => resp.text()) + .then(data => requestAnimationFrame(function(){ + replaceCommentsListFromFetched(insertInto, data) && evnt.target.parentElement.remove(); + insertInto.setAttribute('data-remaining-comments-count', '0'); + })); + } } + + // Relevant if using buildReplyTemplate + // document.head.insertAdjacentHTML('beforeEnd', ''); + document.addEventListener('click', onExpandComments); })(); From 7a8aece2f33c5f1a99148a23c28587898c63ce6e Mon Sep 17 00:00:00 2001 From: StaticPH <7786502+StaticPH@users.noreply.github.com> Date: Sat, 28 Mar 2026 14:37:22 -0400 Subject: [PATCH 31/38] Fix inverted comparison operator in manifest updater script. Tweak spacing in readme. --- README.md | 1 + build/ABOUT.md | 3 +++ build/templates/primary_template.md.j2 | 2 +- build/update_script_manifest.py | 2 +- 4 files changed, 6 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index b8bc053..a782adc 100644 --- a/README.md +++ b/README.md @@ -24,6 +24,7 @@ One example of such a scenario could be opening a Twitch.tv livestream from the --- + To add a script: * Install a script directly from GitHub by clicking on the "install" link in the table below. diff --git a/build/ABOUT.md b/build/ABOUT.md index e728bb3..3a7fec1 100644 --- a/build/ABOUT.md +++ b/build/ABOUT.md @@ -72,6 +72,7 @@ minijinja-cli --format json templates/primary_template.md.j2 - > output.md 6. [ ] Decide on some process to automatically assign an `anchorString`. Consider ditching custom anchor strings entirely in favor of just using the name of the script file, sans extension. + `pandoc` might be of use here, depending on the exact behavior of [extension: `auto_identifiers`](https://pandoc.org/MANUAL.html#extension-auto_identifiers) 7. [ ] Figure out what part of `getUpdatedScriptData` can be replaced with a call to `dict.update()`. @@ -86,3 +87,5 @@ minijinja-cli --format json templates/primary_template.md.j2 - > output.md 11. [X] Temporary local branch in which to test repository layout with new automation files included. 12. [X] Finish/fix date parsing and conversion for the non-standard `createdAt` property in script metadata, so that it can be stored *sensibly* in the manifest. + +13. [ ] Although I'm not using `pandoc` at this time, apparently it's default markdown variant expects a blank line before headings (other than at the start of the document). Might want to try changing the format of script details in the readme template, which currently has a named anchor on the line before each script's heading. See [`pandoc` markdown extension: `blank_before_header`](https://pandoc.org/MANUAL.html#extension-blank_before_header) diff --git a/build/templates/primary_template.md.j2 b/build/templates/primary_template.md.j2 index 424b9da..8a443bc 100644 --- a/build/templates/primary_template.md.j2 +++ b/build/templates/primary_template.md.j2 @@ -13,8 +13,8 @@ If your browsing habit doesn't involve much opening things in new tabs, you'll l One example of such a scenario could be opening a Twitch.tv livestream from the directory view. - --- + To add a script: * Install a script directly from GitHub by clicking on the "install" link in the table below. {# + -
    -
    -
    +
    +
    +
    -
    ${commentNode.bodyHTML}
    ${reactionToolbarHTML}
    +
    ${commentNode.bodyHTML}
    ${reactionToolbarHTML}
    From 89bcd94bd3687f5b6d3f0bf8346b1eedf49e6cf9 Mon Sep 17 00:00:00 2001 From: StaticPH <7786502+StaticPH@users.noreply.github.com> Date: Sun, 5 Apr 2026 17:06:00 -0400 Subject: [PATCH 34/38] A little more linting --- github_sticky_editor_header.user.js | 19 ++++++++++++++----- simple_url_tracker_cleaner.user.js | 17 ++++++++--------- 2 files changed, 22 insertions(+), 14 deletions(-) diff --git a/github_sticky_editor_header.user.js b/github_sticky_editor_header.user.js index 2df3b4c..bbff278 100644 --- a/github_sticky_editor_header.user.js +++ b/github_sticky_editor_header.user.js @@ -3,7 +3,7 @@ // @namespace https://github.com/StaticPH // @match http*://github.com/*/*/edit/* // include /https?:\/\/github\.com\/[^\/]+\/[^\/]+\/edit\/.+\.(md|MD|Md|adoc|asciidoc|rst)/ -// @version 1.0 +// @version 1.0.1 // @createdAt 11/24/2021, 1:50:21 AM // @author StaticPH // @description Makes the header of the (text) file editor on GitHub sticky. @@ -22,11 +22,20 @@ (function(){ "use strict"; - if (!(GM && GM.addStyle)){ - console.log('GM.addStyle is not defined. Falling back to GM_addStyle.'); - GM = GM ? GM : {}; - GM.addStyle = GM.addStyle ? GM.addStyle : GM_addStyle; + // Prefer asychronous Greasemonkey4-API GM.addStyle, but allow use of GM_addStyle as a fallback if necessary. + if (typeof GM === 'undefined'){ + this.GM = {}; } + if (GM['addStyle'] === undefined){ + console.log('GM.addStyle is not defined. Falling back to GM_addStyle Promise.'); + GM['addStyle'] = function(...args){ + return new Promise((onResolve, onReject) => { + try{ onResolve(GM_addStyle.apply(this, args)); } + catch(err){ onReject(err); } + }); + } + } + GM.addStyle(` .js-code-editor.container-preview > .file-header { top: 0%; diff --git a/simple_url_tracker_cleaner.user.js b/simple_url_tracker_cleaner.user.js index 39aa86a..a5361aa 100644 --- a/simple_url_tracker_cleaner.user.js +++ b/simple_url_tracker_cleaner.user.js @@ -2,7 +2,7 @@ // @name Simple URL Tracker Cleaner // @namespace https://github.com/StaticPH // @match *://*/* -// @version 1.6.2 +// @version 1.6.3 // @createdAt 8/10/2021 // @author StaticPH // @description Scrub various common tracker parameters from URLs. @@ -26,13 +26,13 @@ const queryIndex = args.findIndex(s => s.startsWith('q=')); args[0] = args[0].replace('search?', `search?${args[queryIndex]}&`); delete args[queryIndex]; - return args.filter(s => s).join('&'); + return args.filter(Boolean).join('&'); } async function cleanURLs(){ - Array.from(document.links).forEach(async function(link){ + for(link of document.links){ let fixed = null; - if (link.href.match(/google\.[^/]+\/url\?.*/)){ + if (/google\.[^/]+\/url\?.*/.test(link.href)){ const url = new URL(link.href); if (url.searchParams.has('url')){ fixed = url.searchParams.get('url'); @@ -60,13 +60,13 @@ console.warn('Could not find expected "url" or "q" parameter for link: ' + link.href); } } - if (link.href.match(/(?:[?&])(amp;)?(utm_(source|medium|campaign|term|content)|(fb|g)clid)=[^&?#]*[&?#]?/)){ + if (/(?:[?&])(amp;)?(utm_(source|medium|campaign|term|content)|(fb|g)clid)=[^&?#]*[&?#]?/.test(link.href)){ fixed = link.href.replace(/(?:[?&])(amp;)?(utm_(source|medium|campaign|term|content)|(fb|g)clid)=[^&?#]*/g, '').replace(/[?&]*#/, '#').replace(/[?&]*$/, ''); console.log( link.href + ' --> ' + fixed ); link.href = fixed; } // if (link.href.match(/google\.[^/]+\/search\?q=.+/)){ - if (link.href.match(/google\.[^/]+\/search.*?[&?](ei|sa|ved|bi[wh]|spell|oq|gs_lcp|sclient|uact)=[^&?#]*/)){ + if (/google\.[^/]+\/search.*?[&?](ei|sa|ved|bi[wh]|spell|oq|gs_lcp|sclient|uact)=[^&?#]*/.test(link.href)){ // fixed = link.href.replace(/&(ei|sa|ved|bi[wh]|spell|oq|gs_lcp|sclient|uact)=[^&?#]*/g, ''); // fixed = link.href.replace(/\?([^&#=]+=[^&#]*((&[^&#=]+=[^&#]*)+)?&)(q=[^&?#]*)(.*)/, '?$4&$1$5').replace('&&','&'); // This *CAN'T* be the optimal way to handle scenarios where 'q' isn't the first search parameter... fixed = queryParamFirst(link.href); @@ -81,13 +81,12 @@ } // TODO: AMAZON URLS // On Amazon product pages in particular, you can remove keywords, ref, dchild, pd*, pf*, qid, and sr - if (link.href.match(/amazon\.[^/]+\/[^/]+\/dp\/[^/]+\/[^?&]+[?&]/)){ + if (/amazon\.[^/]+\/[^/]+\/dp\/[^/]+\/[^?&]+[?&]/.test(link.href)){ fixed = link.href.replace(/[&?].+$/, ''); console.log( link.href + ' --> ' + fixed ); link.href = fixed; } - }); - return; + } } cleanURLs(); From 1e2dd16311ef7f150fc0616904d856c7faf9299b Mon Sep 17 00:00:00 2001 From: StaticPH <7786502+StaticPH@users.noreply.github.com> Date: Sun, 5 Apr 2026 19:18:34 -0400 Subject: [PATCH 35/38] Google Search Lean Query Updates: Use slightly smarter polyfill for String.prototype.replaceAll --- README.md | 11 +++++----- build/data_files/legacy_scripts.json | 12 +++++------ build/data_files/main_script_manifest.json | 20 +++++++++---------- google_search_lean_query_updates.user.js | 8 ++++++-- ...thub_lazy_release_asset_workaround.user.js | 6 +++++- 5 files changed, 32 insertions(+), 25 deletions(-) diff --git a/README.md b/README.md index a782adc..3dd8a0d 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,6 @@ If your browsing habit doesn't involve much opening things in new tabs, you'll l One example of such a scenario could be opening a Twitch.tv livestream from the directory view. - --- To add a script: @@ -41,7 +40,7 @@ To add a script: | [GitHub Repo Network Tab](#GRNT) | [install][raw-GRNT] | N/A | :heavy_check_mark: | MIT | Apr 6, 2020 | Feb 27, 2026 | | [Bigger GitHub Network Graph](#BGNG) | [install][raw-BGNG] | N/A | :heavy_check_mark: | MIT | Apr 12, 2020 | Oct 28, 2021 | | [GitHub Notification Page Tweaks](#GNPT) | [install][raw-GNPT] | N/A | :heavy_check_mark: | MIT | Oct 22, 2020 | Aug 3, 2021 | -| [GitHub Sticky Editor Header](#GSEH) | [install][raw-GSEH] | N/A | :heavy_check_mark: | MIT | Nov 24, 2021 | Nov 24, 2021 | +| [GitHub Sticky Editor Header](#GSEH) | [install][raw-GSEH] | N/A | :heavy_check_mark: | MIT | Nov 24, 2021 | Apr 5, 2026 | | [GitLab Description In Title](#GDIT) | [install][raw-GDIT] | N/A | :heavy_check_mark: | MIT | May 22, 2021 | Aug 3, 2021 | | [Prettier Lib.rs Preformatted Code](#PLPC) | [install][raw-PLPC] | N/A | :heavy_check_mark: | MIT | Jul 5, 2020 | Mar 30, 2021 | | [Lib.rs Description In Title](#LDIT) | [install][raw-LDIT] | N/A | :heavy_check_mark: | MIT | Apr 28, 2021 | May 11, 2021 | @@ -50,19 +49,19 @@ To add a script: | [Google Meet Ignore Hardware Disabled](#GMIHD) | [install][raw-GMIHD] | N/A | :heavy_check_mark: | MIT | Mar 3, 2023 | Mar 3, 2023 | | [Wider Google Form Fields](#WGFF) | [install][raw-WGFF] | N/A | :heavy_check_mark: | MIT | Sep 30, 2021 | Aug 19, 2022 | | [Correct Google Form Correctness](#GFCC) | [install][raw-GFCC] | N/A | :heavy_check_mark: | MIT | Nov 9, 2021 | Nov 9, 2021 | -| [Google Search Lean Query Updates](#GSLQU) | [install][raw-GSLQU] | N/A | :heavy_check_mark: | MIT | Jul 12, 2023 | Sep 28, 2024 | +| [Google Search Lean Query Updates](#GSLQU) | [install][raw-GSLQU] | N/A | :heavy_check_mark: | MIT | Jul 12, 2023 | Apr 5, 2026 | | [Google Search Footer Privacy](#GSFP) | [install][raw-GSFP] | N/A | :heavy_check_mark: | MIT | Dec 30, 2023 | Dec 16, 2025 | | [Roll20 Nonscrolling Number Fields](#RNNF) | [install][raw-RNNF] | N/A | :heavy_check_mark: | MIT | Jan 23, 2021 | Apr 5, 2021 | | [Bypass Blogspot's Blogger IFrame](#BBBI) | [install][raw-BBBI] | N/A | :heavy_check_mark: | MIT | Jun 2, 2021 | May 1, 2022 | | [Foxaholic Fixes](#FoxF) | [install][raw-FoxF] | N/A | :heavy_check_mark: | MIT | Jun 2, 2021 | Aug 27, 2021 | | [Mitigate Target \_blank Risk](#MTBR) | [install][raw-MTBR] | N/A | :heavy_check_mark: | MIT | Aug 27, 2021 | Nov 23, 2021 | | [MSYS2 Package Description In Title](#MDIT) | [install][raw-MDIT] | N/A | :heavy_check_mark: | MIT | Apr 28, 2021 | Feb 9, 2026 | -| [Minecraft CurseForge Title Tweaks](#MCTT) | [install][raw-MCTT] | N/A | :heavy_check_mark: | MIT | Apr 20, 2022 | Jun 18, 2022 | -| [Another "Open In Steam" Button](#OISB) | [install][raw-OISB] | N/A | :heavy_check_mark: | MIT | Nov 25, 2022 | Nov 25, 2022 | +| [Minecraft CurseForge Title Tweaks](#MCTT) | [install][raw-MCTT] | N/A | :heavy_check_mark: | MIT | Apr 20, 2022 | Apr 5, 2026 | +| [Another "Open In Steam" Button](#OISB) | [install][raw-OISB] | N/A | :heavy_check_mark: | MIT | Nov 25, 2022 | Apr 5, 2026 | | [Ubuntu Packages Description In Title](#UPDIT) | [install][raw-UPDIT] | N/A | :heavy_check_mark: | MIT | May 11, 2023 | May 11, 2023 | | [Quietly Reject StackExchange Cookies](#QRSC) | [install][raw-QRSC] | N/A | :heavy_check_mark: | MIT | May 14, 2023 | May 14, 2023 | | [PyPI Description In Title](#PDIT) | [install][raw-PDIT] | N/A | :heavy_check_mark: | MIT | May 31, 2023 | Aug 15, 2024 | -| [Simple URL Tracker Cleaner](#SUTC) | [install][raw-SUTC] | N/A | :heavy_check_mark: | MIT | Aug 10, 2021 | Jan 28, 2024 | +| [Simple URL Tracker Cleaner](#SUTC) | [install][raw-SUTC] | N/A | :heavy_check_mark: | MIT | Aug 10, 2021 | Apr 5, 2026 | | [Old Reddit Hide Posts By Sub](#ORHS) | [install][raw-ORHS] | N/A | :heavy_check_mark: | MIT | Apr 8, 2022 | Jul 2, 2023 | | [ScribbleHub Reading List Upgrades](#SRLU) | [install][raw-SRLU] | N/A | :heavy_check_mark: | MIT | Oct 7, 2022 | Jan 19, 2024 | | [NovelUpdates Reading List Upgrades](#NRLU) | [install][raw-NRLU] | N/A | :heavy_check_mark: | MIT | Jul 8, 2022 | Nov 16, 2022 | diff --git a/build/data_files/legacy_scripts.json b/build/data_files/legacy_scripts.json index dc30e2f..ad3babc 100644 --- a/build/data_files/legacy_scripts.json +++ b/build/data_files/legacy_scripts.json @@ -51,9 +51,9 @@ "license": "MIT", "autoUpdates": true, "created": "Oct 8, 2022", - "updated": "Mar 12, 2023", + "updated": "Apr 5, 2026", "desc": "Multiple fixes related to user-downloadable asset files on GitHub for users of legacy browsers.\n- Fetch asset list for releases, as the code that should already have been responsible for that is too modern, and is thus never even attempted on legacy browsers.\n- Fix the timestamps on the release page(s), most of which are within asset lists.\n- Slightly changes normal behavior by automatically showing __all__ assets for the first release on the page, whether that's two assets or fourty assets.", - "version": "1.1.1" + "version": "1.1.2" }, { "name": "GitHub Show Issue Comments Workaround", @@ -62,9 +62,9 @@ "license": "MIT", "autoUpdates": true, "created": "Nov 10, 2025", - "updated": "Mar 1, 2026", + "updated": "Apr 5, 2026", "desc": "Manually display comments on Github issues using the JSON that's already on the page, which totally doesn't need React to accomplish.", - "version": "1.1.1" + "version": "1.1.2" }, { "name": "StackExchange Legacy Comments Expander", @@ -73,9 +73,9 @@ "license": "MIT", "autoUpdates": true, "created": "Nov 6, 2022", - "updated": "Nov 2, 2023", + "updated": "Apr 5, 2026", "desc": "Replace 'Show X more comments' handler for StackExchange sites to better support older browsers; in particular, this enables showing all comments when using Chromium 72.", - "version": "1.1.0" + "version": "1.2.0" } ] } \ No newline at end of file diff --git a/build/data_files/main_script_manifest.json b/build/data_files/main_script_manifest.json index 5926c55..f57a1a7 100644 --- a/build/data_files/main_script_manifest.json +++ b/build/data_files/main_script_manifest.json @@ -117,9 +117,9 @@ "license": "MIT", "autoUpdates": true, "created": "Nov 24, 2021", - "updated": "Nov 24, 2021", + "updated": "Apr 5, 2026", "desc": "Makes the header of the (text) file editor on GitHub sticky.
    \nWritten because I got sick and tired of having to move up and down the page to change to and from the preview while editing this README.", - "version": "1.0.0" + "version": "1.0.1" }, { "name": "GitLab Description In Title", @@ -216,9 +216,9 @@ "license": "MIT", "autoUpdates": true, "created": "Jul 12, 2023", - "updated": "Sep 28, 2024", + "updated": "Apr 5, 2026", "desc": "Proof-of-concept: Prevent modifications to the Google search query in the on-page search bar from inserting a bunch of unwanted parameters into the resulting URL.", - "version": "1.3.0" + "version": "1.3.1" }, { "name": "Google Search Footer Privacy", @@ -293,9 +293,9 @@ "license": "MIT", "autoUpdates": true, "created": "Apr 20, 2022", - "updated": "Jun 18, 2022", + "updated": "Apr 5, 2026", "desc": "Modifies the format of the page title for some of CurseForge's Minecraft pages.", - "version": "1.1.0" + "version": "1.1.1" }, { "name": "Another \"Open In Steam\" Button", @@ -304,9 +304,9 @@ "license": "MIT", "autoUpdates": true, "created": "Nov 25, 2022", - "updated": "Nov 25, 2022", + "updated": "Apr 5, 2026", "desc": "As the name should imply, this is my own version of a script which adds a new button on Steam's steampowered and steamcommunity sites to open the current page in the Steam app.
    \nSome of the CSS used was borrowed from https://greasyfork.org/en/scripts/454372-open-steam-url after I spent well over an hour fiddling with my own CSS in the pre-dawn hours, and decided I wasn't going to manage much better.", - "version": "1.0.0" + "version": "1.0.1" }, { "name": "Ubuntu Packages Description In Title", @@ -348,9 +348,9 @@ "license": "MIT", "autoUpdates": true, "created": "Aug 10, 2021", - "updated": "Jan 28, 2024", + "updated": "Apr 5, 2026", "desc": "Scrub various common tracker parameters from URLs. Even if you don't mind being tracked, parameters like these often make URLs rather long; why copy, share, or save a 200 character URL when you could get the exact same content by removing 160 of those characters, without routing traffic through some URL shortening service?
    \n
    \nPrimarily targets parameters related to Google, Amazon, and Facebook.
    \n
    \n\nIcon from: Fly Swatter free icon created by Freepik - Flaticon\n", - "version": "1.6.2" + "version": "1.6.3" }, { "name": "Old Reddit Hide Posts By Sub", diff --git a/google_search_lean_query_updates.user.js b/google_search_lean_query_updates.user.js index a68f098..619401e 100644 --- a/google_search_lean_query_updates.user.js +++ b/google_search_lean_query_updates.user.js @@ -2,7 +2,7 @@ // @name Google Search Lean Query Updates // @namespace https://github.com/StaticPH // @match https://www.google.com/search -// @version 1.3.0 +// @version 1.3.1 // @createdAt 7/12/2023, 2:08:47 PM // @author StaticPH // @description Proof-of-concept: Prevent modifications to the Google search query in the on-page search bar from inserting a bunch of unwanted parameters into the resulting URL. @@ -24,7 +24,11 @@ Object.defineProperty(String.prototype, 'replaceAll', { writable: true, enumerable: false, configurable: true, value: function replaceAll(searchValue, newValue){ - return this.replace( new RegExp(searchValue, 'g'), newValue ); + let flags = searchValue.flags || 'g'; + if (!flags.includes('g')){ + flags += 'g'; + } + return this.replace( new RegExp(searchValue, flags), newValue ); } }); } diff --git a/legacy_browser_workarounds/github_lazy_release_asset_workaround.user.js b/legacy_browser_workarounds/github_lazy_release_asset_workaround.user.js index 738d91c..28aafc8 100644 --- a/legacy_browser_workarounds/github_lazy_release_asset_workaround.user.js +++ b/legacy_browser_workarounds/github_lazy_release_asset_workaround.user.js @@ -40,7 +40,11 @@ 'method': 'GET', 'mode': 'cors' }; - const timestampPreset = new Intl.DateTimeFormat(navigator.language, { numberingSystem: 'ltn', calendar: 'gregory', year: 'numeric', month: 'short', day: 'numeric', hour: 'numeric', hour12: true, minute: 'numeric' }); + const timestampPreset = new Intl.DateTimeFormat(navigator.language, { + numberingSystem: 'ltn', calendar: 'gregory', + year: 'numeric', month: 'short', day: 'numeric', + hour: 'numeric', hour12: true, minute: 'numeric', second: 'numeric' + }); async function localizeTimestamp(dateObj){ return await timestampPreset.format(dateObj); } From 4035cbd9937a00ae4c6c0cdac48327231ea0aa01 Mon Sep 17 00:00:00 2001 From: StaticPH <7786502+StaticPH@users.noreply.github.com> Date: Sun, 5 Apr 2026 19:21:29 -0400 Subject: [PATCH 36/38] Legacy Discussion Forum Scroll Fixer: Support more websites --- build/data_files/legacy_scripts.json | 4 ++-- .../discourse_forum_scroll_fixer.user.js | 9 ++++++++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/build/data_files/legacy_scripts.json b/build/data_files/legacy_scripts.json index ad3babc..adbef6d 100644 --- a/build/data_files/legacy_scripts.json +++ b/build/data_files/legacy_scripts.json @@ -7,9 +7,9 @@ "license": "MIT", "autoUpdates": true, "created": "Jun 29, 2024", - "updated": "Mar 23, 2025", + "updated": "Apr 5, 2026", "desc": "Fix for Discourse forums breaking the ability to scroll on browsers that are too old or are blocking some script or other.", - "version": "1.0.4" + "version": "1.0.5" }, { "name": "GitHub Line Hyperlink Workaround", diff --git a/legacy_browser_workarounds/discourse_forum_scroll_fixer.user.js b/legacy_browser_workarounds/discourse_forum_scroll_fixer.user.js index 4b2bc2c..c4501c3 100644 --- a/legacy_browser_workarounds/discourse_forum_scroll_fixer.user.js +++ b/legacy_browser_workarounds/discourse_forum_scroll_fixer.user.js @@ -2,9 +2,14 @@ // @name Legacy Discussion Forum Scroll Fixer // @namespace https://github.com/StaticPH // @match *://community.blokada.org/* +// @match *://community.brave.app/* // @match *://community.cloudflare.com/* +// @match *://community.latenode.com/* +// @match *://community.osr.com/* +// @match *://community.retool.com/* // @match *://community.syncromsp.com/* // @match *://discourse.cmake.org/* +// @match *://discuss.dev.twitch.com/* // @match *://discuss.gradle.org/* // @match *://discuss.python.org/* // @match *://discussions.unity.com/* @@ -13,11 +18,13 @@ // @match *://forum.graphviz.org/* // @match *://forum.kee.pm/* // @match *://forum.manjaro.org/* +// @match *://forum.obsidian.md/* // @match *://forums.comodo.com/* // @match *://forums.spongepowered.org/* +// @match *://forum.freecodecamp.org/* // @match *://meta.discourse.org/* // @match *://talk.restarters.net/* -// @version 1.0.4 +// @version 1.0.5 // @createdAt 6/29/2024, 6:24:11 PM // @author StaticPH // @description Fix for Discourse forums breaking the ability to scroll on browsers that are too old or are blocking some script or other. From 0350078831059ef25f62491761f1fa2c5b3e5a82 Mon Sep 17 00:00:00 2001 From: StaticPH <7786502+StaticPH@users.noreply.github.com> Date: Sun, 5 Apr 2026 19:52:45 -0400 Subject: [PATCH 37/38] Simple URL Tracker Cleaner: Fix bug inserting "undefined" into some Google search URLs. Query parameter can now theoretically be repositioned for all URLs, instead of just those with a path ending in "search". Minor refactor. --- build/data_files/main_script_manifest.json | 2 +- simple_url_tracker_cleaner.user.js | 55 +++++++++++++++------- 2 files changed, 38 insertions(+), 19 deletions(-) diff --git a/build/data_files/main_script_manifest.json b/build/data_files/main_script_manifest.json index f57a1a7..d4c3539 100644 --- a/build/data_files/main_script_manifest.json +++ b/build/data_files/main_script_manifest.json @@ -350,7 +350,7 @@ "created": "Aug 10, 2021", "updated": "Apr 5, 2026", "desc": "Scrub various common tracker parameters from URLs. Even if you don't mind being tracked, parameters like these often make URLs rather long; why copy, share, or save a 200 character URL when you could get the exact same content by removing 160 of those characters, without routing traffic through some URL shortening service?
    \n
    \nPrimarily targets parameters related to Google, Amazon, and Facebook.
    \n
    \n\nIcon from: Fly Swatter free icon created by Freepik - Flaticon\n", - "version": "1.6.3" + "version": "1.6.4" }, { "name": "Old Reddit Hide Posts By Sub", diff --git a/simple_url_tracker_cleaner.user.js b/simple_url_tracker_cleaner.user.js index a5361aa..e8d7c41 100644 --- a/simple_url_tracker_cleaner.user.js +++ b/simple_url_tracker_cleaner.user.js @@ -2,7 +2,7 @@ // @name Simple URL Tracker Cleaner // @namespace https://github.com/StaticPH // @match *://*/* -// @version 1.6.3 +// @version 1.6.4 // @createdAt 8/10/2021 // @author StaticPH // @description Scrub various common tracker parameters from URLs. @@ -24,21 +24,41 @@ // Put the damn query parameter first so it's predictable const args = href.split('&'); const queryIndex = args.findIndex(s => s.startsWith('q=')); - args[0] = args[0].replace('search?', `search?${args[queryIndex]}&`); + if (queryIndex === -1){ + return href; + } + const argStart = href.indexOf('?'); + const pathTail = href.slice(href.lastIndexOf('/', argStart), argStart); + args[0] = args[0].replace(`${pathTail}?`, `${pathTail}?${args[queryIndex]}&`); delete args[queryIndex]; return args.filter(Boolean).join('&'); } - async function cleanURLs(){ - for(link of document.links){ + function fixDanglingQuery(href){ + return href.replace(/[?&]*#/, '#').replace(/[?&]*$/, ''); + } + + const commonRegex = { + stripAll: /[&?].+$/, + stripSearch: /[&?][^#]+/, + findUniversal: /(?:[?&])(amp;)?(utm_(source|medium|campaign|term|content)|(fb|g)clid)=[^&?#]*[&?#]?/, + stripUniversal: /(?:[?&])(amp;)?(utm_(source|medium|campaign|term|content)|(fb|g)clid)=[^&?#]*/g, + findGoogleUrlRedir: /google\.[^/]+\/url\?.*/, + findGSearchClutter: /google\.[^/]+\/search.*?[&?](ei|sa|ved|bi[wh]|spell|oq|gs_lcp|sclient|uact)=[^&?#]*/, + stripGSearchClutter: /&(ei|sa|ved|bi[wh]|spell|oq|gs_lcp|sclient|uact)=[^&?#]*/g, + findAmazonProduct: /amazon\.[^/]+\/[^/]+\/dp\/[^/]+\/[^?&]+[?&]/, + }; + + function cleanURLs(){ + for (const link of document.links){ let fixed = null; - if (/google\.[^/]+\/url\?.*/.test(link.href)){ + if (commonRegex.findGoogleUrlRedir.test(link.href)){ const url = new URL(link.href); if (url.searchParams.has('url')){ fixed = url.searchParams.get('url'); if (!fixed || fixed.length === 0){ console.warn('Found empty "url" parameter in link: ' + link.href); } else{ - console.log( link.href + ' --> ' + fixed ); + console.log(`${link.href} --> ${fixed}`); link.href = fixed; } } @@ -49,7 +69,7 @@ if (url.searchParams.has('tbs')){ // This is one of the parameters actually worth keeping, as it controls some of the "advanced" filtering fixed = fixed + '&' + url.searchParams.get('tbs'); } - console.log( link.href + ' --> ' + fixed ); + console.log(`${link.href} --> ${fixed}`); link.href = fixed; } else{ @@ -60,30 +80,29 @@ console.warn('Could not find expected "url" or "q" parameter for link: ' + link.href); } } - if (/(?:[?&])(amp;)?(utm_(source|medium|campaign|term|content)|(fb|g)clid)=[^&?#]*[&?#]?/.test(link.href)){ - fixed = link.href.replace(/(?:[?&])(amp;)?(utm_(source|medium|campaign|term|content)|(fb|g)clid)=[^&?#]*/g, '').replace(/[?&]*#/, '#').replace(/[?&]*$/, ''); - console.log( link.href + ' --> ' + fixed ); + if (commonRegex.findUniversal.test(link.href)){ + fixed = fixDanglingQuery(link.href.replace(commonRegex.stripUniversal, '')); + console.log(`${link.href} --> ${fixed}`); link.href = fixed; } - // if (link.href.match(/google\.[^/]+\/search\?q=.+/)){ - if (/google\.[^/]+\/search.*?[&?](ei|sa|ved|bi[wh]|spell|oq|gs_lcp|sclient|uact)=[^&?#]*/.test(link.href)){ + if (commonRegex.findGSearchClutter.test(link.href)){ // fixed = link.href.replace(/&(ei|sa|ved|bi[wh]|spell|oq|gs_lcp|sclient|uact)=[^&?#]*/g, ''); // fixed = link.href.replace(/\?([^&#=]+=[^&#]*((&[^&#=]+=[^&#]*)+)?&)(q=[^&?#]*)(.*)/, '?$4&$1$5').replace('&&','&'); // This *CAN'T* be the optimal way to handle scenarios where 'q' isn't the first search parameter... fixed = queryParamFirst(link.href); - fixed = fixed.replace(/&(ei|sa|ved|bi[wh]|spell|oq|gs_lcp|sclient|uact)=[^&?#]*/g, ''); + fixed = fixed.replace(commonRegex.stripGSearchClutter, ''); /* Compare performance against: const oldUrl = new URL(link.href); ['ei','sa','ved','biw','bih','spell','oq','gs_lcp','sclient','uact'].forEach(oldUrl.searchParams.delete); fixed = oldUrl.href; */ - console.log( link.href + ' --> ' + fixed ); + console.log(`${link.href} --> ${fixed}`); link.href = fixed; } - // TODO: AMAZON URLS + // TODO: More AMAZON URLS // On Amazon product pages in particular, you can remove keywords, ref, dchild, pd*, pf*, qid, and sr - if (/amazon\.[^/]+\/[^/]+\/dp\/[^/]+\/[^?&]+[?&]/.test(link.href)){ - fixed = link.href.replace(/[&?].+$/, ''); - console.log( link.href + ' --> ' + fixed ); + if (commonRegex.findAmazonProduct.test(link.href)){ + fixed = link.href.replace(commonRegex.stripAll, ''); + console.log(`${link.href} --> ${fixed}`); link.href = fixed; } } From 95782a831faa7f6d1d3d0a09a3943df96bf48250 Mon Sep 17 00:00:00 2001 From: StaticPH <7786502+StaticPH@users.noreply.github.com> Date: Sun, 5 Apr 2026 22:07:04 -0400 Subject: [PATCH 38/38] Fix typo in readme --- README.md | 2 +- build/templates/primary_template.md.j2 | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 3dd8a0d..e70307e 100644 --- a/README.md +++ b/README.md @@ -577,7 +577,7 @@ Additionally, I do occasionally take requests for simple scripts, so feel free t --- ## Some of the awesome scripts I use from other authors -I make no guarantees regarding the availability, maintenance, or browser version support of these scripts<\sub> +I make no guarantees regarding the availability, maintenance, or browser version support of these scripts - [Wide GitHub](https://github.com/xthexder/wide-github) - [GitHub Code Folding](https://openuserjs.org/scripts/Mottie/GitHub_Code_Folding) (Note: last working version for Chrome 72 was v1.1.2, although subsequent changes to GitHub's UI have broken parts of that, too) - [GitHub Gist Search Box](https://greasyfork.org/en/scripts/395318-github-gist-search-box) diff --git a/build/templates/primary_template.md.j2 b/build/templates/primary_template.md.j2 index 8a443bc..4b1370c 100644 --- a/build/templates/primary_template.md.j2 +++ b/build/templates/primary_template.md.j2 @@ -93,7 +93,7 @@ Additionally, I do occasionally take requests for simple scripts, so feel free t --- ## {{ recommendations.title }} -I make no guarantees regarding the availability, maintenance, or browser version support of these scripts<\sub> +I make no guarantees regarding the availability, maintenance, or browser version support of these scripts {%- for script in recommendations.scripts %} - {{ script }} {%- endfor %}