├── .eslintignore [DEPRECATED] ├── .eslintrc.js [DEPRECATED] ├── .eslintrc.json [DEPRECATED] ├── .gitattributes ├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.yml │ ├── config.yml │ ├── feature_request.md.old │ └── feature_request.yml ├── dependabot.yml └── workflows │ ├── dependency-review.yml │ ├── evergreen.yml │ └── lint.yml ├── .gitignore ├── 1337X_-_convert_torrent_timestamps_to_relative_format ├── 1337X_-_convert_torrent_timestamps_to_relative_format.user.js ├── README.md ├── moment-timezone-with-data-10-year-range.min.js └── moment.min.js ├── 1337x_-_torrent_and_magnet_links ├── 1337x_-_torrent_and_magnet_links.user.js └── README.md ├── Blabbermouth_-_generate_timestamps_and_add_link_to_the_FB_comments_area ├── Blabbermouth_-_generate_timestamps_and_add_link_to_the_FB_comments_area.user.js └── README.md ├── BugMeNot ├── BugMeNot.user.js └── README.md ├── Bugzilla_-_reveal_the_Depends,_Blocks,_See_Also_and_Duplicates_bug_titles ├── Bugzilla_-_reveal_the_Depends,_Blocks,_See_Also_and_Duplicates_bug_titles.user.js ├── README.md ├── jquery-ui.min.js └── keypress.min.js ├── CONTRIBUTING.md ├── Firefox_for_desktop_-_list_fixed_bugs_in_Mercurial ├── Firefox_for_desktop_-_list_fixed_bugs_in_Mercurial.user.js ├── README.md ├── jquery-2.1.4.min.js └── jquery-ui.min.js ├── Firefox_for_desktop_-_list_fixed_bugs_in_Mercurial_as_sortable_table ├── Firefox_for_desktop_-_list_fixed_bugs_in_Mercurial_as_sortable_table.user.js ├── README.md ├── date.min.js ├── jquery-2.1.4.min.js ├── jquery-ui.min.js ├── jquery.tablesorter.min.js ├── jstz.min.js ├── keypress.min.js ├── moment-timezone-with-data.min.js └── moment-with-locales.min.js ├── Firefox_for_desktop_-_list_modified_bugs_in_Mercurial_as_sortable_table ├── Firefox_for_desktop_-_list_modified_bugs_in_Mercurial_as_sortable_table.user.js ├── README.md ├── date.min.js ├── jquery-2.1.4.min.js ├── jquery-ui.min.js ├── jquery.tablesorter.min.js ├── jstz.min.js ├── keypress.min.js ├── moment-timezone-with-data.min.js └── moment-with-locales.min.js ├── GitHub_Confirmations_before_submitting_issues_and_comments ├── GitHub_Confirmations_before_submitting_issues_and_comments.user.js └── README.md ├── Google_youtube_search_link ├── Google_youtube_search_link.user.js └── README.md ├── GreasyFork_-_add_a_send_PM_to_user_button_in_Greasyfork_profile_pages ├── GreasyFork_-_add_a_send_PM_to_user_button_in_Greasyfork_profile_pages.user.js ├── README.md └── ZU0xS0c.jpg ├── GreasyFork_-_filter_discussions_on_scripts_by_review_type_and_author ├── GreasyFork_-_filter_discussions_on_scripts_by_review_type_and_author.user.js ├── README.md ├── jquery-3.1.1.min.js ├── jquery-ui.css └── jquery-ui.js ├── GreasyFork_-_filter_libraries_in_profiles ├── GreasyFork_-_filter_libraries_in_profiles.user.js └── README.md ├── GreasyFork_Bullshit_Filter ├── GreasyFork_Bullshit_Filter.user.js ├── README.md └── large.png ├── GreasyFork_Bullshit_Filter_-_for_TS_Citrus_Gfork ├── GreasyFork_Bullshit_Filter_-_for_TS_Citrus_Gfork.user.js ├── README.md └── large.png ├── IMDb_user_reviews_pages_-_ten_star_ratings ├── IMDb_user_reviews_pages_-_ten_star_ratings.user.js └── README.md ├── Instagram_-_visible_images_counter ├── Instagram_-_visible_images_counter.user.js ├── README.md ├── arrivejs.js └── jquery-3.0.0.min.js ├── KAT_-_add_APPROVE_ALL_and_APPROVE_SELECTED_buttons_to_Feedback_popup ├── KAT_-_add_APPROVE_ALL_and_APPROVE_SELECTED_buttons_to_Feedback_popup.user.js └── README.md ├── Markdown_toolbar_for_GreasyFork ├── 66x40-solid.png ├── Markdown_toolbar_for_GreasyFork.user.js └── README.md ├── Markdown_toolbar_for_reddit.com ├── 66x40-solid.png ├── Markdown_toolbar_for_redditcom.user.js └── README.md ├── Metal_Archives_discography_pages_-_Reviews_column_split_and_sortable_tables ├── Metal_Archives_discography_pages_-_Reviews_column_split_and_sortable_tables.user.js ├── Mutation_Summary.js ├── README.md └── TableSorter.js ├── OpenSubtitles_-_direct_download_links ├── OpenSubtitles_-_direct_download_links.user.js └── README.md ├── OpenUserJS_Bullshit_Filter ├── OpenUserJS_Bullshit_Filter.user.js ├── README.md └── large.png ├── ProtonMail_-_remove_forced_signature ├── ProtonMail_-_remove_forced_signature.user.js └── README.md ├── RARBG_-_convert_torrent_timestamps_to_relative_format ├── RARBG_-_convert_torrent_timestamps_to_relative_format.user.js ├── README.md └── moment.min.js ├── RARBG_-_torrent_and_magnet_links ├── RARBG_-_torrent_and_magnet_links.user.js ├── README.md └── arrive.js ├── RARBG_-_various_tweaks ├── RARBG_-_various_tweaks.user.js └── README.md ├── README.md ├── Reddit_Infinite_Scrolling ├── README.md ├── Reddit_Infinite_Scrolling.user.js ├── jScroll.js └── jquery-2.1.4.min.js ├── Rotten_Tomatoes_Decimal_Rating ├── README.md └── Rotten_Tomatoes_Decimal_Rating.user.js ├── StackExchange_sites_-_convert_dates_to_local_timezone ├── README.md ├── StackExchange_sites_-_convert_dates_to_local_timezone.user.js ├── jstz.min.js ├── moment-timezone-with-data.min.js └── moment.min.js ├── SunXDCC_-_normalize_values ├── Mutation_Summary.js ├── README.md └── SunXDCC_-_normalize_values.user.js ├── Twitter_-_add_unread_notifications_count_in_the_tab_title ├── README.md ├── Twitter_-_add_unread_notifications_count_in_the_tab_title.user.js └── arrivejs.js ├── Userstyles_-_filter_deleted_styles_in_your_profile ├── README.md └── Userstyles_-_filter_deleted_styles_in_your_profile.user.js ├── Userstyles_Bullshit_Filter ├── README.md ├── Userstyles_Bullshit_Filter.user.js └── large.png ├── eslint.config.js ├── ixIRC_-_sortable_search_results ├── README.md ├── date.js ├── ixIRC_-_sortable_search_results.user.js ├── jquery-3.2.1.min.js ├── jquery.tablesorter.min.js ├── math.min.js └── parser-metric.js ├── kuehlschrank scripts icon - backup └── Bullshit_Filter.png ├── mozillaZine_Forums_-_insert_titles_to_bug_links ├── 3Y8dqYZ.gif ├── README.md └── mozillaZine_Forums_-_insert_titles_to_bug_links.user.js ├── package.json ├── renovate.json ├── thepiratebay_-_add_a_sortable_Ratio_column ├── README.md ├── TableSorter.js └── thepiratebay_-_add_a_sortable_Ratio_column.user.js ├── thepiratebay_helper ├── GM_config.js ├── README.md ├── jquery-3.2.0.min.js ├── jquery.tablesorter.min.js ├── keypress.min.js ├── moment.min.js └── thepiratebay_helper.user.js └── userstyles.org_css_highlighter ├── README.md ├── arrivejs.js └── userstylesorg_css_highlighter.user.js /.eslintignore [DEPRECATED]: -------------------------------------------------------------------------------- 1 | **/*.min.js 2 | -------------------------------------------------------------------------------- /.eslintrc.js [DEPRECATED]: -------------------------------------------------------------------------------- 1 | /* eslint-disable quotes */ 2 | 3 | module.exports = { 4 | "root": true, 5 | 6 | "env": { 7 | "browser": true, 8 | "es6": true, 9 | "greasemonkey": true, 10 | "jquery": true, 11 | // "node": true 12 | }, 13 | 14 | "parserOptions": { 15 | // "ecmaVersion": 12, 16 | "ecmaVersion": "latest", 17 | "sourceType": "script", 18 | "ecmaFeatures": { 19 | "globalReturn ": true, 20 | "impliedStrict": true, 21 | // "jsx": true, 22 | }, 23 | }, 24 | 25 | // "extends": "eslint:all", 26 | // "extends": "eslint:recommended", 27 | "extends": [ 28 | "eslint:recommended", 29 | // "eslint:all", 30 | "plugin:css/recommended", 31 | "plugin:jsonc/recommended-with-json", 32 | // "plugin:no-jquery/recommended", 33 | "plugin:no-jquery/deprecated", 34 | // "plugin:no-jquery/slim", 35 | // "plugin:no-jquery/all", 36 | // "plugin:clean-regex/recommended" 37 | "plugin:regexp/recommended", 38 | // "plugin:regexp/all", 39 | ], 40 | 41 | "plugins": [ 42 | "css", 43 | "jsonc", 44 | // "clean-regex", 45 | "no-jquery", 46 | "regexp", 47 | ], 48 | 49 | "rules": { 50 | "complexity": ["warn", 20], 51 | "eqeqeq": "warn", 52 | "func-style": "off", 53 | // "indent": ["warn","tab" ], 54 | // "indent": ["warn","tab", { "SwitchCase": 1 } ], 55 | // "indent": ["warn","tab", { "ignoreComments": true, "SwitchCase": 1 } ], 56 | "indent": ["warn","tab", { "ignoreComments": false, "SwitchCase": 1 } ], 57 | "linebreak-style": ["warn","unix"], 58 | "max-len": "off", 59 | "max-statements-per-line": "off", 60 | "new-cap": "off", 61 | "no-alert": "warn", 62 | "no-console": "warn", 63 | "no-dupe-keys": "warn", 64 | "no-extra-semi": "warn", 65 | "no-inline-comments": "off", 66 | "no-magic-numbers": "off", 67 | "no-misleading-character-class": "warn", 68 | "no-mixed-spaces-and-tabs": "warn", 69 | // "no-var": "off", 70 | "no-multiple-empty-lines": "off", 71 | "no-tabs": "off", 72 | "no-unused-labels": "warn", 73 | "no-unused-vars": ["warn", {"vars": "all", "args": "after-used"}], 74 | "no-useless-escape": "warn", 75 | "padded-blocks": "off", 76 | "quotes": ["warn", "single", { "allowTemplateLiterals": true }] , 77 | "require-jsdoc": "off", 78 | "require-unicode-regexp": "off", 79 | "semi": ["warn","always"], 80 | // "strict": ["error", "global"], 81 | "space-before-function-paren": "off", 82 | // "space-in-parens": ["warn", "always"], 83 | "unicode-bom": ["warn", "never"], 84 | }, 85 | 86 | "reportUnusedDisableDirectives": true 87 | 88 | }; 89 | -------------------------------------------------------------------------------- /.eslintrc.json [DEPRECATED]: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | "env": { 4 | "browser": true, 5 | "es6": true, 6 | "greasemonkey": true, 7 | "jquery": true 8 | }, 9 | "parserOptions": { 10 | "ecmaVersion": "latest", 11 | "sourceType": "script", 12 | "ecmaFeatures": { 13 | "globalReturn ": true, 14 | "impliedStrict": true 15 | } 16 | }, 17 | "extends": [ 18 | "eslint:recommended", 19 | "plugin:css/recommended", 20 | "plugin:jsonc/recommended-with-json", 21 | "plugin:no-jquery/deprecated", 22 | "plugin:regexp/recommended" 23 | ], 24 | "plugins": [ 25 | "css", 26 | "jsonc", 27 | "no-jquery", 28 | "regexp" 29 | ], 30 | "rules": { 31 | "complexity": ["warn", 20], 32 | "eqeqeq": "warn", 33 | "func-style": "off", 34 | "indent": ["warn","tab", { "ignoreComments": false, "SwitchCase": 1 } ], 35 | "linebreak-style": ["warn","unix"], 36 | "max-len": "off", 37 | "max-statements-per-line": "off", 38 | "new-cap": "off", 39 | "no-alert": "warn", 40 | "no-console": "warn", 41 | "no-dupe-keys": "warn", 42 | "no-extra-semi": "warn", 43 | "no-inline-comments": "off", 44 | "no-magic-numbers": "off", 45 | "no-misleading-character-class": "warn", 46 | "no-mixed-spaces-and-tabs": "warn", 47 | "no-multiple-empty-lines": "off", 48 | "no-tabs": "off", 49 | "no-unused-labels": "warn", 50 | "no-unused-vars": ["warn", {"vars": "all", "args": "after-used"}], 51 | "no-useless-escape": "warn", 52 | "padded-blocks": "off", 53 | "quotes": ["warn", "single", { "allowTemplateLiterals": true }] , 54 | "require-jsdoc": "off", 55 | "require-unicode-regexp": "off", 56 | "semi": ["warn","always"], 57 | "space-before-function-paren": "off", 58 | "unicode-bom": ["warn", "never"] 59 | }, 60 | "reportUnusedDisableDirectives": true 61 | } 62 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto eol=lf 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | 7 | # Standard to msysgit 8 | *.doc diff=astextplain 9 | *.DOC diff=astextplain 10 | *.docx diff=astextplain 11 | *.DOCX diff=astextplain 12 | *.dot diff=astextplain 13 | *.DOT diff=astextplain 14 | *.pdf diff=astextplain 15 | *.PDF diff=astextplain 16 | *.rtf diff=astextplain 17 | *.RTF diff=astextplain 18 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.yml: -------------------------------------------------------------------------------- 1 | name: 🐛 Report a bug 2 | description: File a bug report 3 | title: "[script title] " 4 | labels: bug 5 | body: 6 | - type: markdown 7 | attributes: 8 | value: | 9 | # Thanks for reporting a bug! ⛰ 10 | 11 | Help us replicate the issue by filling in this form. 12 | - type: checkboxes 13 | id: terms 14 | attributes: 15 | label: "Please ensure:" 16 | options: 17 | - label: "I included in the issue title the script name I'm referring to." 18 | required: true 19 | - label: I performed a search of the [issue tracker](https://github.com/darkred/Userscripts/issues) and in the relevant Greasyfork [feedback page](https://greasyfork.org/en/users/2160-darkred?sort=updated) to avoid opening a duplicate issue. 20 | required: true 21 | - label: The bug is caused by the script itself. It doesn't happen if I disable the script, or in a fresh browser profile. 22 | required: true 23 | - type: checkboxes 24 | attributes: 25 | label: 'Include in this issue:' 26 | options: 27 | - label: Screenshots/video/gif demonstrating the bug, if it’s visual 28 | - label: Console errors, if any 29 | - type: textarea 30 | id: the-problem 31 | attributes: 32 | label: Describe the problem and how to replicate it 33 | validations: 34 | required: true 35 | - type: input 36 | id: example-url 37 | attributes: 38 | label: Example URL 39 | description: A REAL URL where the bug appears. 40 | placeholder: https://example.com/page1.htm 41 | validations: 42 | required: true 43 | - type: input 44 | id: script-manager 45 | attributes: 46 | label: Script Manager 47 | description: (Tampermonkey and Violentmonkey are supported - Greasemonkey is NOT supported) 48 | placeholder: e.g. Tampermonkey 4.14 49 | validations: 50 | required: true 51 | - type: input 52 | id: browsers 53 | attributes: 54 | label: Browser(s) used 55 | description: (make sure it is the latest version - old versions are NOT supported) 56 | placeholder: e.g. Chrome 92 57 | validations: 58 | required: true 59 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md.old: -------------------------------------------------------------------------------- 1 | --- 2 | name: 🆕 Suggest an improvement or new feature 3 | about: ——— 4 | title: '' 5 | labels: enhancement, under discussion 6 | assignees: '' 7 | 8 | --- 9 | 10 | 17 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.yml: -------------------------------------------------------------------------------- 1 | name: 🆕 Suggest an improvement or new feature 2 | description: ——— 3 | title: "[script title] " 4 | labels: enhancement, under discussion 5 | body: 6 | - type: checkboxes 7 | id: terms 8 | attributes: 9 | label: "Please ensure:" 10 | options: 11 | - label: "I included in the issue title the script name I'm referring to." 12 | required: true 13 | - label: "Before you request from me to write a new script for you, check in https://greasyfork.org/en/scripts and https://openuserjs.org/ : what you ask might be there already." 14 | required: false 15 | - type: textarea 16 | attributes: 17 | label: Description 18 | description: "Try to be as specific as possible, don't make me have to guess what your suggested improvement or feature is." 19 | validations: 20 | required: true 21 | - type: textarea 22 | attributes: 23 | label: Screenshot 24 | description: You can provide screenshots/mockups to better visualize your idea. Files can be dropped in this field 25 | - type: input 26 | attributes: 27 | label: Example URL 28 | description: Include a REAL URL where the feature should appear. Paste a link here 29 | placeholder: https://example.com/index.html 30 | value: https:// 31 | validations: 32 | required: true 33 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # To get started with Dependabot version updates, you'll need to specify which 2 | # package ecosystems to update and where the package manifests are located. 3 | # Please see the documentation for all configuration options: 4 | # https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates 5 | 6 | version: 2 7 | updates: 8 | - package-ecosystem: "npm" # See documentation for possible values 9 | directory: "/" # Location of package manifests 10 | schedule: 11 | interval: "daily" 12 | 13 | - package-ecosystem: "github-actions" 14 | directory: "/" 15 | schedule: 16 | interval: "weekly" # Check for updates to GitHub Actions every week 17 | -------------------------------------------------------------------------------- /.github/workflows/dependency-review.yml: -------------------------------------------------------------------------------- 1 | name: 'Dependency Review' 2 | on: [pull_request] 3 | 4 | permissions: 5 | contents: read 6 | 7 | jobs: 8 | dependency-review: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - name: 'Checkout Repository' 12 | uses: actions/checkout@v4 13 | - name: 'Dependency Review' 14 | uses: actions/dependency-review-action@v4 15 | -------------------------------------------------------------------------------- /.github/workflows/evergreen.yml: -------------------------------------------------------------------------------- 1 | name: Weekly dependabot checks 2 | 3 | on: 4 | workflow_dispatch: 5 | schedule: 6 | - cron: '3 2 1 * *' 7 | 8 | permissions: 9 | issues: write 10 | pull-requests: write 11 | 12 | jobs: 13 | evergreen: 14 | name: evergreen 15 | runs-on: ubuntu-latest 16 | 17 | steps: 18 | - name: Run evergreen action 19 | uses: github/evergreen@v1 20 | env: 21 | GH_TOKEN: ${{ secrets.EVERGREEN_ACTION }} 22 | REPOSITORY: darkred 23 | -------------------------------------------------------------------------------- /.github/workflows/lint.yml: -------------------------------------------------------------------------------- 1 | # from https://github.com/tophf/mpiv/blob/master/.github/workflows/lint.yml 2 | # and https://github.com/stefanoeb/eslint-action/blob/master/README.md 3 | 4 | name: ESLint 5 | 6 | on: 7 | push: 8 | branches: [ master ] 9 | paths-ignore: 10 | - '.github/**' # this yml is also excluded so you need to re-run it explicitly if necessary 11 | - .editorconfig 12 | - LICENSE 13 | - README.md 14 | pull_request: 15 | branches: [ master ] 16 | paths-ignore: 17 | - '.github/**' # this yml is also excluded so you need to re-run it explicitly if necessary 18 | - .editorconfig 19 | - LICENSE 20 | - README.md 21 | # Allows you to run this workflow manually from the Actions tab 22 | workflow_dispatch: 23 | jobs: 24 | lint: 25 | runs-on: ubuntu-latest 26 | steps: 27 | - uses: actions/checkout@v4 28 | - name: Install modules 29 | run: npm install 30 | - name: Run ESLint 31 | run: npx eslint . --ext .user.js 32 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Windows image file caches 2 | Thumbs.db 3 | ehthumbs.db 4 | 5 | # Folder config file 6 | Desktop.ini 7 | 8 | # Recycle Bin used on file shares 9 | $RECYCLE.BIN/ 10 | 11 | # Windows Installer files 12 | *.cab 13 | *.msi 14 | *.msm 15 | *.msp 16 | 17 | # Windows shortcuts 18 | *.lnk 19 | 20 | # ========================= 21 | # Operating System Files 22 | # ========================= 23 | 24 | # OSX 25 | # ========================= 26 | 27 | .DS_Store 28 | .AppleDouble 29 | .LSOverride 30 | 31 | # Thumbnails 32 | ._* 33 | 34 | # Files that might appear in the root of a volume 35 | .DocumentRevisions-V100 36 | .fseventsd 37 | .Spotlight-V100 38 | .TemporaryItems 39 | .Trashes 40 | .VolumeIcon.icns 41 | 42 | # Directories potentially created on remote AFP share 43 | .AppleDB 44 | .AppleDesktop 45 | Network Trash Folder 46 | Temporary Items 47 | .apdisk 48 | 49 | 50 | node_modules/ 51 | 52 | # lockfiles 53 | package-lock.json 54 | -------------------------------------------------------------------------------- /1337X_-_convert_torrent_timestamps_to_relative_format/1337X_-_convert_torrent_timestamps_to_relative_format.user.js: -------------------------------------------------------------------------------- 1 | // ==UserScript== 2 | // @name 1337X - convert torrent timestamps to relative format 3 | // @namespace darkred 4 | // @version 2021.7.14.1 5 | // @description Converts torrent upload timestamps to relative format 6 | // @author darkred 7 | // @license MIT 8 | // @include /^https:\/\/(www\.)?1337x\.(to|st|ws|eu|se|is|gd|unblocked\.dk)((?!\/torrent)).*$/ 9 | // @grant none 10 | // @require https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.1/moment.min.js 11 | // @require https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.31/moment-timezone-with-data-10-year-range.min.js 12 | // @supportURL https://github.com/darkred/Userscripts/issues 13 | // ==/UserScript== 14 | 15 | // Official mirrors list: https://1337x.to/about 16 | 17 | 'use strict'; 18 | /* global moment */ 19 | 20 | 21 | 22 | 23 | 24 | // 11:59am ---> h:hha 25 | // 10am Oct. 30th ---> haA MMM. Do 26 | // 11pm Nov. 4th 27 | // Oct. 31st '20 28 | 29 | 30 | 31 | // Based on the timestamp on the footer of each RARBG page --> "Sat, 01 May 2020 20:14:56 +0200", 32 | // the script takes that the server time is GMT+2 and that it doesn't take DST. 33 | // Also, the script uses the 'moment-timezone' library as it takes DST offsets into account when converting the timestamps to user/local timezone. 34 | 35 | // This is no typo: 36 | // const serverTimezone = 'Etc/GMT+2'; // -02:00 -02:00 (=no DST) 37 | // const serverTimezone = 'Etc/GMT-2'; // +02:00 +02:00 (=no DST) 38 | const serverTimezone = 'Etc/GMT-1'; // +01:00 +01:00 (=no DST) 39 | 40 | // const serverTimezone = 'Etc/GMT-1'; 41 | 42 | const localTimezone = moment.tz.guess(); // In my case ----> +02:00 +03:00 (DST) 43 | 44 | // const format = 'MM/DD/YYYY HH:mm:ss'; 45 | // const format = 'YYYY-MM-DD HH:mm:ss'; 46 | moment.locale('en'); 47 | const format = ['h:mma', 'ha MMM. Do', 'MMM. Do \'YY']; 48 | const formatTooltip1 = 'h:mma'; // the 1st element of the above array. 49 | const formatTooltip2 = 'ha MMM. Do'; // the 2st element of the array (there can be no 3rd format, e.g. Oct. 31st '20 is only date, not time ). 50 | 51 | // Customize the strings in the locale to display "1 minute ago" instead of "a minute ago" (https://github.com/moment/moment/issues/3764#issuecomment-279928245) 52 | moment.updateLocale('en', { 53 | relativeTime: { 54 | future: 'in %s', 55 | past: '%s ago', 56 | s: 'seconds', 57 | m: '1 minute', 58 | mm: '%d minutes', 59 | h: '1 hour', 60 | hh: '%d hours', 61 | d: '1 day', 62 | dd: '%d days', 63 | M: '1 month', 64 | MM: '%d months', 65 | y: '1 year', 66 | yy: '%d years' 67 | } 68 | }); 69 | 70 | 71 | function convertToLocalTimezone(timestamps) { 72 | for (let i = 0; i < timestamps.length; i++) { 73 | let initialTimestamp = timestamps[i].textContent; 74 | if (moment(initialTimestamp, format, true).isValid()) { // As of moment.js v2.3.0, you may specify a boolean for the last argument to make Moment use strict parsing. Strict parsing requires that the format and input match exactly, including delimeters. 75 | let convertedToLocalTimezone = moment.tz(initialTimestamp, format, serverTimezone).tz(localTimezone); 76 | timestamps[i].textContent = convertedToLocalTimezone.fromNow(); 77 | 78 | // timestamps[i].title = initialTimestamp; 79 | if (moment(initialTimestamp, formatTooltip1, true).isValid()) { 80 | timestamps[i].title = convertedToLocalTimezone.format(formatTooltip1); 81 | } else if (moment(initialTimestamp, formatTooltip2, true).isValid()) { 82 | timestamps[i].title = convertedToLocalTimezone.format(formatTooltip2); 83 | // timestamps[i].title = convertedToLocalTimezone.toISOString(); // Display timestamps in tooltips in ISO 8601 format, combining date and time (https://stackoverflow.com/questions/25725019/how-do-i-format-a-date-as-iso-8601-in-moment-js/) 84 | } 85 | } 86 | } 87 | 88 | 89 | // recalculate the relative dates every 1 min 90 | (function(){ 91 | for (let i = 0; i < timestamps.length; i++) { 92 | // timestamps[i].textContent = moment(timestamps[i].title).fromNow(); 93 | 94 | if (timestamps[i].title !== '') { 95 | let tooltipValue = timestamps[i].title; 96 | let convertedToLocalTimezone = moment(tooltipValue, format); // no need to reconvert, it's already in local timezone 97 | timestamps[i].textContent = convertedToLocalTimezone.fromNow(); 98 | } 99 | 100 | } 101 | // setTimeout(arguments.callee, 10 * 1000); // 10 * 1000 msec = 10 sec = 1/6 min 102 | setTimeout(arguments.callee, 60 * 1000); // 60 * 1000 msec = 1 min 103 | })(); 104 | 105 | 106 | } 107 | 108 | // const timestamps = document.querySelectorAll('tr.lista2 td:nth-child(3)'); 109 | const timestamps = document.querySelectorAll('tbody .coll-date'); 110 | convertToLocalTimezone(timestamps); 111 | -------------------------------------------------------------------------------- /1337X_-_convert_torrent_timestamps_to_relative_format/README.md: -------------------------------------------------------------------------------- 1 | This script applies to 1337X torrent lists. 2 | - it converts torrent timestamps to relative format in local timezone. Also, it recalculates them every 1 min. 3 | - The initial timestamps are still available as tooltips (on mouse hover), also converted to local timezone. 4 | 5 | It uses [moment.js](http://momentjs.com/) and [moment-timezone.js](http://momentjs.com/timezone/). 6 | 7 | Screenshot comparison: 8 | Initial: 9 | ![](https://i.imgur.com/ZcEdXNI.jpg) 10 | With the script: 11 | ![](https://i.imgur.com/1I027xL.jpg) 12 | 13 | [Hosted in GitHub](https://github.com/darkred/Userscripts) 14 | -------------------------------------------------------------------------------- /1337x_-_torrent_and_magnet_links/1337x_-_torrent_and_magnet_links.user.js: -------------------------------------------------------------------------------- 1 | // ==UserScript== 2 | // @name 1337x - torrent and magnet links 3 | // @namespace darkred 4 | // @version 2021.8.17 5 | // @description Adds a column with torrent and magnet links in lists 6 | // @author darkred 7 | // @contributor NotNeo, barn852 8 | // @license MIT 9 | // @include /^https:\/\/(www\.)?1337x\.(to|st|ws|eu|se|is|gd|unblocked\.dk)((?!\/torrent)).*$/ 10 | // @grant GM_addStyle 11 | // @run-at document-idle 12 | // 13 | // Thanks to: 14 | // - NotNeo: most of the CSS used is taken from this script: https://greasyfork.org/en/scripts/373230-1337x-magnet-torrent-links-everywhere . 15 | // - barn852 for his contribution here: https://greasyfork.org/en/scripts/420754-1337x-torrent-and-magnet-links/discussions/96026 16 | // 17 | // Official mirrors list: https://1337x.to/about 18 | // 19 | // ==/UserScript== 20 | 21 | 22 | 23 | GM_addStyle(` 24 | 25 | main.container, div.container { 26 | /* max-width: 1600px; */ 27 | max-width: 1450px; 28 | } 29 | 30 | .list-button-magnet > i.flaticon-magnet { 31 | font-size: 13px; 32 | color: #da3a04 33 | } 34 | 35 | .list-button-dl > i.flaticon-torrent-download { 36 | font-size: 13px; 37 | color: #89ad19; 38 | } 39 | 40 | table.table-list td.dl-buttons { 41 | border-left: 1px solid #f6f6f6; 42 | border-right: 1px solid #c0c0c0; 43 | padding-left: 2.5px; 44 | padding-right: 2.5px; 45 | text-align: center !important; 46 | position: relative; 47 | display: table-cell !important; /* proper height of cell on multiple row torrent name */ 48 | width: 6%; 49 | } 50 | 51 | td.dl-buttons > a, 52 | td.dl-buttons > a:hover, 53 | td.dl-buttons > a:visited, 54 | td.dl-buttons > a:link, 55 | td.dl-buttons > a:active { 56 | color: inherit; 57 | text-decoration: none; 58 | cursor: pointer; 59 | display: inline-block !important; 60 | /* margin: 0 1.5px; */ 61 | margin: 0 2px; 62 | } 63 | 64 | table.table-list td.coll-1b { 65 | border-right: 1px solid silver; 66 | } 67 | 68 | .table-list > thead > tr > th:nth-child(2), 69 | .table-list > thead > tr > td:nth-child(2) { 70 | text-align: center; 71 | } 72 | 73 | `); 74 | 75 | 76 | function appendColumn() { 77 | 78 | const allTables = document.querySelectorAll('.table-list-wrap'); // for pages with multiple tables e.g. https://1337x.to/home/ 79 | const isSeries = window.location.href.includes('/series/'); // for pages with tables that have no header e.g. https://1337x.to/series/a-to-z/1/13/ 80 | const title = 'ml dl'; 81 | 82 | 83 | allTables.forEach((table) => { 84 | 85 | const headersCellsInitial = table.querySelectorAll(`.table-list > thead > tr:not(.blank) > th:nth-child(1), 86 | .table-list > tbody > tr:not(.blank) > td:nth-child(1)`); 87 | headersCellsInitial.forEach((cell, index) => { 88 | if (index === 0 && !isSeries) { 89 | cell.insertAdjacentHTML('afterend', `` + title + ``); 90 | } else { 91 | cell.insertAdjacentHTML('afterend', `` + title + ``); 92 | } 93 | }); 94 | 95 | const headersCellsNew = table.querySelectorAll(`.table-list > thead > tr:not(.blank) > th:nth-child(2), 96 | .table-list > tbody > tr:not(.blank) > td:nth-child(2)`); 97 | headersCellsNew.forEach((cell, index) => { 98 | cell.classList.add('coll-1b'); 99 | if (index === 0 && !isSeries) { 100 | cell.innerHTML = title; 101 | } else { 102 | cell.classList.add('dl-buttons'); 103 | 104 | let href; 105 | if (!isSeries){ 106 | href = headersCellsInitial[index].firstElementChild.nextElementSibling.href; 107 | } else { 108 | href = headersCellsInitial[index].firstElementChild.href; 109 | } 110 | 111 | cell.innerHTML = ``; 112 | cell.innerHTML += ``; 113 | } 114 | }); 115 | 116 | 117 | }); 118 | 119 | 120 | } 121 | 122 | 123 | 124 | function addClickListeners(links, type){ 125 | 126 | links.forEach((link) => { 127 | 128 | link.addEventListener('click', function(){ 129 | 130 | let href = this.getAttribute('href'); 131 | if (href === 'javascript:void(0)') { 132 | let tLink = this.getAttribute('data-href'); 133 | 134 | var xhr = new XMLHttpRequest(); 135 | xhr.open('GET', tLink, true); // XMLHttpRequest.open(method, url, async) 136 | xhr.onload = function () { 137 | 138 | let container = document.implementation.createHTMLDocument().documentElement; 139 | container.innerHTML = xhr.responseText; 140 | 141 | let retrievedLink = (type === 'ml') ? container.querySelector('a[href^="magnet:"]') : container.querySelector('.dropdown-menu > li > a'); 142 | 143 | if (retrievedLink) { 144 | link.setAttribute('href', retrievedLink.href.replace('http:', 'https:')); // the links are http and as such are blocked in Chrome 145 | link.click(); 146 | } 147 | 148 | 149 | }; 150 | xhr.send(); 151 | 152 | } 153 | 154 | }, false); 155 | 156 | }); 157 | 158 | } 159 | 160 | 161 | 162 | function createColumn(){ 163 | appendColumn(); 164 | addClickListeners(document.querySelectorAll('.list-button-magnet'), 'ml' ); 165 | addClickListeners(document.querySelectorAll('.list-button-dl'), 'dl' ); 166 | } 167 | 168 | 169 | createColumn(); 170 | -------------------------------------------------------------------------------- /1337x_-_torrent_and_magnet_links/README.md: -------------------------------------------------------------------------------- 1 | Adds a column with torrent and magnet links in 1337x lists: 2 | ![](https://i.imgur.com/goYAFQH.jpg) 3 | 4 | Notes: 5 | 6 | - The script generates all links via XHR: 7 | - The DL/ML links will have: 8 | - as tooltip: "`ml/dl via xhr`". 9 | - as destination (href): 10 | - initially: `javascript:void(0)` *(to avoid taking the user back to the top of the page, which occurred if having `#`, instead)*, 11 | - as you click a ml/dl icon, the relevant target URL will be retrieved via XHR in the background. 12 | - Thanks to: 13 | - NotNeo: most of the CSS is from his [1337X - Magnet/Torrent links everywhere](https://greasyfork.org/en/scripts/373230-1337x-magnet-torrent-links-everywhere) script, 14 | - barn852 for [this](https://greasyfork.org/en/scripts/420754-1337x-torrent-and-magnet-links/discussions/96026) contribution . 15 | - Tampermonkey and Violentmonkey are supported - Greasemonkey is NOT supported. 16 | 17 | [Hosted at GitHub](https://github.com/darkred/Userscripts) 18 | -------------------------------------------------------------------------------- /Blabbermouth_-_generate_timestamps_and_add_link_to_the_FB_comments_area/README.md: -------------------------------------------------------------------------------- 1 | This script applies to blabbermouth.net. 2 | 3 | Blabbermouth only displays timestamps (just the date) in news listings and pages. 4 | **It doesn't display timestamps in cd/dvd reviews pages at all.** 5 | The script generates timestamps in relative format, in all cases. 6 | 7 | In details: 8 | 9 | - in **news** and **cd/dvd reviews** pages: 10 | 11 | It generates timestamps *(making use of the existing `published_time` data from inside the pages, e.g. `2020-02-20T19:10:22.000Z`)* 12 | in relative format. Also, it recalculates them every 1 minute. 13 | _(the initial retrieved timestamps -converted to local timezone's offset- are tooltips: just hover mouse on a relative date to view)_ 14 | 15 | It also shows a link to the Facebook comments next to the generated timestamp, 16 | with **the comment count from that fb iframe** 1 (i.e. `6 Comments`, not just "Comments" ). 17 | 18 | 19 | - in **news** listings: 20 | 21 | As you scroll down each page, it retrieves the relevant target news page in the background in order to get the relevant `published_time` data from the page, and then generates timestamps (like before) in relative format. 22 | 23 | Since v1.2 now the script also works in paginated news pages. 24 |   25 | 26 | 1 Compatibility note regarding that feature: 27 | 28 | - Violentmonkey: the script works in ok with VM in its default settings. 29 | - Tampermonkey: in order to work with TM, you have to remove the `*://www.facebook.com/plugins/*` pattern from TM blacklist (it's blacklisted in TM settings by default). 30 | - Greasemonkey: not supported. 31 | 32 | --- 33 | 34 | The script uses [moment.js](http://momentjs.com/). 35 | 36 | [Hosted in GitHub](https://github.com/darkred/Userscripts) 37 | -------------------------------------------------------------------------------- /BugMeNot/README.md: -------------------------------------------------------------------------------- 1 | This userscript is an improved version of [BugMeNot](http://userscripts-mirror.org/scripts/show/23074) dated from 2009, by 'hosts' 2 | _(which in turn was based on code found at http://www.oreillynet.com/pub/h/4171)_. 3 | 4 | This applies in both HTTP and HTTPS sites. 5 | 6 | Many sites (e.g. online newspapers) require you to register with the site before being able to read content. This registration is annoying, invasive, and a serious privacy risk. (Several newspaper publishing companies have been caught selling their registration information to spammers.) A site called BugMeNot.com (http://www.bugmenot.com) has sprung up to aggregate fake logins for such sites. This script takes BugMeNot one step further by integrating it into the login page itself. 7 | It retrieves all possible logins from bugmenot.com, shows their count, and you can try each one on every clicking of 'Get login from BugMeNot'. 8 | 9 | Extra features/changes to the initial version: 10 | - During the 1st attempt all found logins are temporarily stored for using them in the next login attempts. 11 | - Only 1 connection is done to bugmenot.com. 12 | - The script now works even when the `Username` \ element has `type="email"` (i.e. not only `type="text"`) 13 | - Added the `// @noframes` imperative. 14 | - Sometimes, when you open a login page, the `Username` field would have focus by default. 15 | This would cause the following issue: 16 | clicking inside the field, would only Firefox's autocomplete entries - not the script's entries. 17 | To workaround this, the script causes an unfocus on the `Username` field on page load, 18 | to make sure that the options will appear when you click(focus) inside the field. 19 | 20 | Tested in Greasemonkey. 21 | 22 |
23 | 24 | **How to use:** 25 | 26 | After installing this script, go to any page that requires sign in. 27 | Click on either the `Username` or the `Password` textbox. This is what will appear: 28 | ![image](https://i.imgur.com/bMyO0Un.jpg) 29 | (the `1/-` means the 1st login out of yet unknown available logins) 30 | Note: in login pages where where the sign in form appears as a hovering/expanding element, 31 | just open the login link in a new tab: now the script will work. 32 | 33 | By clicking `Get login from BugMeNot` the script will contact bugmenot.com, and, 34 | if it finds login(s), it will temporarily store all found logins for the current browser session via GM_setValue, 35 | and then it will autofill the login form with the 1st found login, as shown below: 36 | ![image](https://i.imgur.com/E7ccv8O.jpg) 37 | *Note: you may view all found logins in Web Console.* 38 | 39 | Try to sign in with that 1st found login. 40 | If the login is invalid, you may navigate again to the sign-in page 41 | and try each one of the rest logins by clicking again on either the `Username` or the `Password` textbox 42 | and then to `Try next login from BugMeNot`, i.e. 43 | ![image](https://i.imgur.com/pqZ0Rz7.jpg) 44 | Notice the `2/3`? It means the 2nd login out of 3 available logins. 45 | *Note that only 1 connection is done to bugmenot.com - all login attempts are done using the stored logins from the 1st attempt* *(you may view all stored logins in Web Console).* 46 | Also, now you may use the entry `Reset login attempt counter` if needed. 47 | 48 | Also, during this, if the Username or Password textbox are already filed with the previous login, 49 | you'll get a prompt to `Overwrite the current login entry`: (just press OK to continue). 50 | ![image](https://i.imgur.com/ismAlzx.jpg) 51 | 52 | 53 | If there were no logins found you'll get this alert box: 54 | ![image](https://i.imgur.com/ayDyxaR.jpg) 55 | meaning that you can either (see the 1st screenshot for reference): 56 | - press `More Options` to open(in a new tab) the relevant bugmenot page, or 57 | - just press `Visit BugMeNot` which will open(in a new tab) http://bugmenot.com . 58 | 59 | Note: you may reset the attempt(=login) count: 60 | - either by clicking on the `Reset login attempt counter`, 61 | - or by opening/refreshing any irrelevant page to the current one, 62 | i.e. just navigate to an irrelevant page, then switch to the login page. 63 | 64 |
65 | 66 | Thanks to 'hosts' for his version of a very useful script! -------------------------------------------------------------------------------- /Bugzilla_-_reveal_the_Depends,_Blocks,_See_Also_and_Duplicates_bug_titles/Bugzilla_-_reveal_the_Depends,_Blocks,_See_Also_and_Duplicates_bug_titles.user.js: -------------------------------------------------------------------------------- 1 | // ==UserScript== 2 | // @name Bugzilla - reveal the Depends, Blocks, See Also and Duplicates bug titles 3 | // @namespace darkred 4 | // @version 2017.16.11 5 | // @description Reveal the Depends, Blocks, See Also and Duplicates bug titles in bugzilla.mozilla.org via keyboard shortcuts 6 | // @license MIT 7 | // @include https://bugzilla.mozilla.org/show_bug.cgi?id=* 8 | // @grant none 9 | // @require https://code.jquery.com/jquery-3.2.1.min.js 10 | // @require https://cdnjs.cloudflare.com/ajax/libs/jquery-scrollTo/2.1.2/jquery.scrollTo.min.js 11 | // @require https://cdnjs.cloudflare.com/ajax/libs/keypress/2.1.3/keypress.min.js 12 | // @supportURL https://github.com/darkred/Userscripts/issues 13 | // ==/UserScript== 14 | 15 | /* eslint-disable no-unused-vars */ 16 | 17 | // Case 1: when you press ` (in order to toggle Depends, BLocks and See Also) 18 | 19 | var flag1 = 1; 20 | var listener1 = new window.keypress.Listener(); 21 | var listener2 = new window.keypress.Listener(); 22 | var depends, blocks, combinedRefs, seeAlsoRefs, duplicatesRefs; 23 | 24 | var combinedInners = [], seeAlsoInners = [], duplicatesInners = []; 25 | 26 | listener1.simple_combo('`', function() { 27 | // console.log('You pressed `'); 28 | 29 | depends = $('#field-value-dependson > a'); 30 | blocks = $('#field-value-blocked > a'); 31 | seeAlsoRefs = $('#field-value-see_also a'); 32 | combinedRefs = depends.add(blocks).add(seeAlsoRefs); 33 | 34 | 35 | if (flag1 === 1) { 36 | flag1 = 0; 37 | 38 | $(window).scrollTo('#field-dependson'); 39 | 40 | $.each(combinedRefs, function(index, val) { combinedInners[index] = combinedRefs[index].innerHTML;}); 41 | 42 | $.each(combinedRefs, function(index, val) { 43 | combinedRefs[index].nextSibling.remove(); 44 | combinedRefs[index].innerHTML = '(' + combinedRefs[index].innerHTML + ') ' + combinedRefs[index].title; 45 | combinedRefs[index].outerHTML += '
'; 46 | }); 47 | 48 | 49 | } else { 50 | if (flag1 === 0) { 51 | flag1 = 1; 52 | 53 | $.each(combinedRefs, function(index, val) { 54 | combinedRefs[index].innerHTML = combinedInners[index]; 55 | combinedRefs[index].outerHTML += ', '; 56 | }); 57 | 58 | var dependsNL = $('#field-value-dependson > a ~ br'); 59 | var blocksNL = $('#field-value-blocked > a ~ br'); 60 | 61 | var combinedNL = dependsNL.add(blocksNL); 62 | for (let m = (combinedNL.length) - 1; m >= 0; m -= 1) { 63 | combinedNL[m].remove(); 64 | } 65 | 66 | } 67 | document.body.scrollTop = document.documentElement.scrollTop = 0; // scroll to the top of the page 68 | // window.scrollTo(0, 0); 69 | // document.querySelector('html').scrollIntoView(); 70 | 71 | // $(window).scrollTo('#field-see_also'); 72 | $(window).scrollTo('#field-dependson'); // alternative to line 78 73 | } 74 | }); 75 | 76 | 77 | // ========================================================================= 78 | 79 | 80 | // Case 2: when you press ~ (in order to toggle Duplicates) 81 | 82 | var flag2 = 1; 83 | 84 | listener2.simple_combo('~', function() { 85 | // console.log('You pressed ~'); 86 | 87 | duplicatesRefs = $(`a:contains('Duplicates')`).parent().parent().find('.value > a'); 88 | 89 | if (flag2 === 1) { 90 | flag2 = 0; 91 | 92 | // $(window).scrollTo('#duplicates'); 93 | $(window).scrollTo(`a:contains('Duplicates')`).parent().parent(); 94 | 95 | $.each(duplicatesRefs, function(index, val) { duplicatesInners[index] = duplicatesRefs[index].innerHTML;}); 96 | 97 | $.each(duplicatesRefs, function(index, val) { 98 | duplicatesRefs[index].nextSibling.remove(); 99 | duplicatesRefs[index].innerHTML = '(' + duplicatesRefs[index].innerHTML + ') ' + duplicatesRefs[index].title; 100 | duplicatesRefs[index].outerHTML += '
'; 101 | }); 102 | 103 | } else { 104 | if (flag2 === 0) { 105 | flag2 = 1; 106 | 107 | $.each(duplicatesRefs, function(index, val) { 108 | duplicatesRefs[index].innerHTML = duplicatesInners[index]; 109 | duplicatesRefs[index].outerHTML += ', '; 110 | }); 111 | 112 | 113 | var duplicatesNL = $(`a:contains('Duplicates')`).parent().parent().find('.value > a ~ br'); 114 | for (let k = (duplicatesNL.length) - 1; k >= 0; k -= 1) { 115 | duplicatesNL[k].remove(); 116 | } 117 | 118 | } 119 | 120 | // document.body.scrollTop = document.documentElement.scrollTop = 0; // scroll to the top of the page 121 | window.scrollTo(0, 0); 122 | // document.querySelector('html').scrollIntoView(); 123 | // $(window).scrollTo('#duplicates'); 124 | $(window).scrollTo(`a:contains('Duplicates')`).parent().parent(); 125 | } 126 | }); 127 | -------------------------------------------------------------------------------- /Bugzilla_-_reveal_the_Depends,_Blocks,_See_Also_and_Duplicates_bug_titles/README.md: -------------------------------------------------------------------------------- 1 | It adds 2 keyboard shortcuts in bugzilla.mozilla.org to reveal: 2 | 3 | - the *Depends on*, *Blocks*, and *See Also* bug titles via pressing (\`) and 4 | - the *Duplicates* via pressing `~` (that is shift+`) 5 | 6 | *(press again to restore the initial display way, i.e. only the bug numbers).* 7 | 8 |
9 | *It uses [Keypress](https://github.com/dmauro/Keypress/) keyboard input capturing utility.* -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to my Userscripts repo 2 | 3 | * [How To Report Issues, Or Make Requests](#how-to-report-issues-or-make-requests) 4 | * [Contributing Code](#contributing-code) 5 | * [Installation](#installation) 6 | * [Pull Requests](#pull-requests) 7 | 8 | 9 | ## How to Report Issues, Or Make Requests. 10 | 11 | When reporting problems: 12 | - Start the issue title having the related script title in parenthesis. 13 | - Be as specific as possible, I need to know where to look. 14 | - State name and version of your browser and script manager. 15 | - Provide a web address example where I can see the problem for myself. A domain name is not enough. 16 | - Provide a screenshot if necessary. 17 | 18 | When making feature requests: 19 | - Be as specific as possible, don't make me have to guess what you want. 20 | 21 | 22 | ## Contributing Code 23 | 24 | ### Installation: 25 | 26 | Just use a script manager, such as Tampermonkey, Greasemonkey or Violentmonkey 27 | 28 | ### Pull Requests: 29 | 30 | You are welcome to open pull requests as long as you: 31 | * Follow the style that is already being used in the code, see the repo's [`.eslintrc` rules](https://github.com/darkred/Userscripts/blob/master/.eslintrc) 32 | * When naming variables: 33 | * Use names that properly describe the contents of the variable. 34 | * Use camel casing as needed. 35 | * Use comments if necesary. 36 | * Use semicolons. 37 | * Use single quotes. 38 | * Use tabs, not 4 spaces indentation. 39 | * Try not to have too long lines. 40 | -------------------------------------------------------------------------------- /Firefox_for_desktop_-_list_fixed_bugs_in_Mercurial/README.md: -------------------------------------------------------------------------------- 1 | This userscript applies to Mozilla Mercurial pushlog pages. 2 | 3 | It generates a list of only the bugs related to Firefox for desktop in Mozilla Mercurial pushlogs. 4 | It's basically for creating lists similar to the "The Official Win32 xxxxxxx builds" 5 | in [Firefox Builds • mozillaZine Forums](http://forums.mozillazine.org/viewforum.php?f=23) but for any date interval. 6 | 7 | Example links where the script applies to: *(changelogs for the last 1 day interval in these examples)* 8 | **Nightly**: https://hg.mozilla.org/mozilla-central/pushloghtml?startdate=1+day+ago&enddate=now 9 | **Inbound**: https://hg.mozilla.org/integration/mozilla-inbound/pushloghtml?startdate=1+day+ago&enddate=now 10 | **fx-team**: https://hg.mozilla.org/integration/fx-team/pushloghtml?startdate=1+day+ago&enddate=now 11 | **Aurora**: https://hg.mozilla.org/releases/mozilla-aurora/pushloghtml?startdate=1+day+ago&enddate=now 12 | **Beta**: https://hg.mozilla.org/releases/mozilla-beta/pushloghtml?startdate=1+day+ago&enddate=now 13 | **Release**: https://hg.mozilla.org/releases/mozilla-release/pushloghtml?startdate=1+day+ago&enddate=now 14 | 15 | Also, (about the "enddate" value when you do such a search): 16 | instead of putting "now" you may put the changeset of your currently installed build (via `about:buildconfig`|click on that link) 17 | so that you may view only the bugs that have been fixed till your current build - *not those that have been fixed til the current time in the relevant branch*. 18 | 19 | For example: (for inbound) instead of using: 20 | `https://hg.mozilla.org/integration/mozilla-inbound/pushloghtml?startdate=1+day+ago&enddate=now` 21 | you may enter this: *(it's for the changeset of [this build](https://hg.mozilla.org/integration/mozilla-inbound/rev/c4dd82aa903d89b3835ceb38cf0341a4190c383e))* 22 | `https://hg.mozilla.org/integration/mozilla-inbound/pushloghtml?startdate=1+day+ago&enddate=c4dd82aa903d` 23 | 24 |
25 | Screenshots of the resulting list: 26 | [![](https://i.imgur.com/vRuWsuQh.jpg)](https://i.imgur.com/vRuWsuQ.jpg) 27 | and screenshot of progress logging in Web Console: 28 | [![](https://i.imgur.com/D2sUx46h.jpg)](https://i.imgur.com/D2sUx46.jpg) 29 | 30 | During the procedure, you may open the Web Console (Ctrl+Shift+K) to monitor progress. 31 | 32 | Notes: 33 | 34 | 1. The requests for each link are done asynchronously, i.e. Firefox UI is not locked and frozen until the request completes. Also, the procedure completes quickly (multiple connections). 35 | After [v4](https://greasyfork.org/en/scripts/13169-firefox-for-desktop-list-fixed-bugs-in-mercurial?version=85976) (thanks to johnp) it now uses the Bugzilla REST API, therefore resulting in huge reduction to the procedure duration (a few seconds for parsing hundreds of bugs), i.e.: 36 | - requests from Bugzila only those fields that it requires *(not entire HTML pages)*, 37 | - uses one network connection for all examined bugs *(using the format=multiple GET-Parameter)* and 38 | - parses the response as JSON* 39 | 40 | 2. Since v4.2 it now stores the list content HTML code to clipboard. 41 | (_You may uncomment (line 11 and) 157 to enable this new feature_) 42 | This feature is aimed to MozillaZine daily "The Official Win32 xxxxxxx builds" maintainer : 43 | so, you may do these easy steps in order to produce the Nightly thread: 44 | - Go to e.g. http://www.garyshood.com/htmltobb/, paste the HTML code, and press "Submit HTML": 45 | it will be converted to BBCode. Copy that to clipboard (Ctrl+C). 46 | - Then, open Notepad++, paste the newly copied content. Now, by following ![this](http://stackoverflow.com/a/26224391), you may append numbering to each line. [i](i.e. first, select all `Ctrl+A`. Then go to `Edit->Column Editor`. Choose the "Number to Insert" button, then choose the starting value (`1`) and the increment (`1`). It will add numbering to each line)[/i] 47 | - Finally, by pressing Alt+dragging down, you may do a vertical selection ([screenshot](https://i.imgur.com/GhrnacT.png)), 48 | so that you may append a dot (`.`) _(and a space where necessary)_ after each line numbering. 49 | 50 | 3. You may also check [v5.5.2](https://greasyfork.org/en/scripts/13169-firefox-for-desktop-list-fixed-bugs-in-mercurial) (for all channels) or [v5.5.3](https://greasyfork.org/en/scripts/15715-firefox-for-desktop-list-modified-bugs-in-mercurial-inbound) (especially for inbound users) : 51 | since v5 the results are displayed as a sortable table (instead of a plain list), 52 | showing in an extra column the "Last Modified Date" of each bug, the values of which are converted to relative time (_e.g, "1 hour ago"_) taking account the user's timezone. (I've created a custom sorter for this extra column). 53 | By default it's sorted by "Modified Date" and "Product:Component"(and by "Summary") - _as a mozilla-inbound user I find this most practical because this way I can check whether any notable bugs have been just fixed, and therefore if it's worth downloading the latest m-i build_. 54 | But, you may sort the table as you wish: you can sort multiple columns simultaneously by holding down the Shift key and clicking a 2nd, 3rd or even 4th column header. 55 | 56 | 57 |
**The procedure:** 58 | - gets all bug links in the page and de-duplicates them 59 | - sends 1 request to Bugzilla for all the above bug links, requesting only the few fields that it requires 60 | _(id, summary, status, resolution, product, component, op sys, platform, whiteboard, last change time)_ 61 | - filters out the irrelevant bugs based on the response 62 | - finally it displays the results in a sortable table using a jQuery dialog 63 | where it's sorted by default by *Modified Date*, *Product: Component* and *Summary*. 64 | *(for the "Modified Date" column, the following libraries are used: [tablesorter](http://mottie.github.io/tablesorter/docs/), [moment.js](http://momentjs.com/), [moment-timezone.js](http://momentjs.com/timezone/), [jsTimezoneDetect](https://bitbucket.org/pellepim/jstimezonedetect), [date.js](http://www.datejs.com/)) and [Keypress](https://github.com/dmauro/Keypress/)*. 65 | 66 |
67 | **What it considered relevant/irrelevant**: 68 | *(info provided kindly by winapp2 and Josa, both maintainers (the first no longer) of the "[Official Win32 build](http://forums.mozillazine.org/viewforum.php?f=23)" threads)* 69 | 70 | 71 | Relevant `Status` values 72 | - RESOLVED 73 | - RESOLVED FIXED 74 | - VERIFIED 75 | - VERIFIED FIXED 76 | 77 | Relevant `Product` values 78 | - Add-on SDK 79 | - Cloud Services 80 | - Core 81 | - Firefox 82 | - Hello (Loop) 83 | - Toolkit 84 | 85 | 86 | Relevant `Component` value (belonging to Product: Core) 87 | - Embedding:APIs 88 | 89 | Irrelevant `Component` values (all belonging to Product: Core) 90 | - AutoConfig 91 | - Build Config 92 | - DMD 93 | - Embedding: GRE Core 94 | - Embedding: Mac 95 | - Embedding: MFC Embed 96 | - Embedding: Packaging 97 | - Hardware Abstraction Layer 98 | - mach 99 | - Nanojit 100 | - QuickLaunch 101 | - Widget: Gonk 102 | 103 | Irrelevant are also considered bugs with restricted access (you may find the bugs which were filtered out for being private, by opening Web Console and enter 'requires authorization' in the 'Filter output' textbox. Then you may click on the relevant links to open them (those that you have access to). 104 | 105 | 106 |
107 | Thanks a lot to: 108 | - wOxxOm for his help in [here](https://greasyfork.org/en/forum/discussion/6616/help-with-making-a-function-wait-until-all-gm-xmlhttprequest-requests-are-fully-completed), 109 | - Brock Adams for his help on [this](http://stackoverflow.com/questions/33347825/jquery-ui-dialog-in-a-userscript-for-greasemonkey-missing-close-button) i.e. [this](http://stackoverflow.com/a/25468298/3231411), and 110 | - johnp for modifying my code thus offering [v4](http://forums.mozillazine.org/viewtopic.php?p=14397041#p14397041) and [v4.1](http://forums.mozillazine.org/viewtopic.php?p=14397041#p14397041) that is [here](http://pastebin.com/5LwQUsLF). Your contribution is most appreciated! 111 | -------------------------------------------------------------------------------- /Firefox_for_desktop_-_list_fixed_bugs_in_Mercurial_as_sortable_table/README.md: -------------------------------------------------------------------------------- 1 | This userscript applies to Mozilla Mercurial pushlog pages. 2 | 3 | It generates a list of only the bugs related to Firefox for desktop in Mozilla Mercurial pushlogs. 4 | It's basically for creating lists similar to the "The Official Win32 xxxxxxx builds" 5 | in [Firefox Builds • mozillaZine Forums](http://forums.mozillazine.org/viewforum.php?f=23) but for any date interval. 6 | 7 | Example links where the script applies to: *(changelogs for the last 1 day interval in these examples)* 8 | **Nightly**: https://hg.mozilla.org/mozilla-central/pushloghtml?startdate=1+day+ago&enddate=now 9 | **Inbound**: https://hg.mozilla.org/integration/mozilla-inbound/pushloghtml?startdate=1+day+ago&enddate=now 10 | **fx-team**: https://hg.mozilla.org/integration/fx-team/pushloghtml?startdate=1+day+ago&enddate=now 11 | **Aurora**: https://hg.mozilla.org/releases/mozilla-aurora/pushloghtml?startdate=1+day+ago&enddate=now 12 | **Beta**: https://hg.mozilla.org/releases/mozilla-beta/pushloghtml?startdate=1+day+ago&enddate=now 13 | **Release**: https://hg.mozilla.org/releases/mozilla-release/pushloghtml?startdate=1+day+ago&enddate=now 14 | 15 | Also, (about the "enddate" value when you do such a search): 16 | instead of putting "now" you may put the changeset of your currently installed build (via `about:buildconfig`|click on that link) 17 | so that you may view only the bugs that have been fixed till your current build - *not those that have been fixed til the current time in the relevant branch*. 18 | 19 | For example: (for inbound) instead of using: 20 | `https://hg.mozilla.org/integration/mozilla-inbound/pushloghtml?startdate=1+day+ago&enddate=now` 21 | you may enter this: *(it's for the changeset of [this build](https://hg.mozilla.org/integration/mozilla-inbound/rev/c4dd82aa903d89b3835ceb38cf0341a4190c383e))* 22 | `https://hg.mozilla.org/integration/mozilla-inbound/pushloghtml?startdate=1+day+ago&enddate=c4dd82aa903d` 23 | 24 |
25 | Screenshots of the resulting list: 26 | v5.5.3 27 | [![](https://i.imgur.com/3PtDdrph.jpg)](https://i.imgur.com/3PtDdrp.jpg) 28 | [v4.2](https://greasyfork.org/en/scripts/19358-firefox-for-desktop-list-fixed-bugs-in-mercurial-2) 29 | [![](https://i.imgur.com/zJ9mupfh.jpg)](https://i.imgur.com/zJ9mupf.jpg) 30 | and screenshot of progress logging in Web Console: 31 | [![](https://i.imgur.com/gtYzPTdh.jpg)](https://i.imgur.com/gtYzPTd.jpg) 32 | 33 | During the procedure, you may open the Web Console (Ctrl+Shift+K) to monitor progress. 34 | 35 | Notes: 36 | 37 | 1. The requests for each link are done asynchronously, i.e. Firefox UI is not locked and frozen until the request completes. Also, the procedure completes quickly (multiple connections). 38 | After [v4](https://greasyfork.org/en/scripts/13169-firefox-for-desktop-list-fixed-bugs-in-mercurial?version=85976) (thanks to johnp) it now uses the Bugzilla REST API, therefore resulting in huge reduction to the procedure duration (a few seconds for parsing hundreds of bugs), i.e.: 39 | - requests from Bugzila only those fields that it requires *(not entire HTML pages)*, 40 | - uses one network connection for all examined bugs *(using the format=multiple GET-Parameter)* and 41 | - parses the response as JSON* 42 | 43 | 2. Since v4.2 it now stores the list content HTML code to clipboard. 44 | (_You may comment out lines 11 and 157 to disable this new feature_) 45 | This feature is aimed to MozillaZine daily "The Official Win32 xxxxxxx builds" maintainer : 46 | so, you may do these easy steps in order to produce the Nightly thread: 47 | - Go to e.g. http://www.garyshood.com/htmltobb/, paste the HTML code, and press "Submit HTML": 48 | it will be converted to BBCode. Copy that to clipboard (Ctrl+C). 49 | - Then, open Notepad++, paste the newly copied content. Now, by following ![this](http://stackoverflow.com/a/26224391), you may append numbering to each line. [i](i.e. first, select all `Ctrl+A`. Then go to `Edit->Column Editor`. Choose the "Number to Insert" button, then choose the starting value (`1`) and the increment (`1`). It will add numbering to each line)[/i] 50 | - Finally, by pressing Alt+dragging down, you may do a vertical selection ([screenshot](https://i.imgur.com/GhrnacT.png)), 51 | so that you may append a dot (`.`) _(and a space where necessary)_ after each line numbering. 52 | 53 | 3. In v5 it displays the results as a sortable table (instead of a plain list), 54 | showing in an extra column the "Last Modified Date" of each bug, the values of which are converted to relative time (_e.g, "1 hour ago"_) taking account the user's timezone. (I've created a custom sorter for this extra column). 55 | By default it's sorted by "Modified Date" and "Product:Component"(and by "Summary") - _as a mozilla-inbound user I find this most practical because this way I can check whether any notable bugs have been just fixed, and therefore if it's worth downloading the latest m-i build_. 56 | But, you may sort the table as you wish: you can sort multiple columns simultaneously by holding down the Shift key and clicking a 2nd, 3rd or even 4th column header. 57 | 58 | 4. In v5.5.1 I bind keypresses of \` to toggle the list display to either: 59 | - sorted by "Modified Date", "Product:Component" and by "Summary") (by default) 60 | and having separators between groups of the same timestamps ([screenshot](https://i.imgur.com/aNvAtBh.jpg)), or 61 | - by "Product:Component" and by "Summary" *(i.e. without the separators)* ([screenshot](https://i.imgur.com/P5a2b61.jpg)) 62 | 63 | 64 |
**The procedure:** 65 | - gets all bug links in the page and de-duplicates them 66 | - sends 1 request to Bugzilla for all the above bug links, requesting only the few fields that it requires 67 | _(id, summary, status, resolution, product, component, op sys, platform, whiteboard, last change time)_ 68 | - filters out the irrelevant bugs based on the response 69 | - finally it displays the results in a sortable table using a jQuery dialog 70 | where it's sorted by default by *Modified Date*, *Product: Component* and *Summary*. 71 | *(for the "Modified Date" column, the following libraries are used: [tablesorter](http://mottie.github.io/tablesorter/docs/), [moment.js](http://momentjs.com/), [moment-timezone.js](http://momentjs.com/timezone/), [jsTimezoneDetect](https://bitbucket.org/pellepim/jstimezonedetect), [date.js](http://www.datejs.com/)) and [Keypress](https://github.com/dmauro/Keypress/)*. 72 | 73 |
74 | **What it considered relevant/irrelevant**: 75 | *(info provided kindly by winapp2 and Josa, both maintainers (the first no longer) of the "[Official Win32 build](http://forums.mozillazine.org/viewforum.php?f=23)" threads)* 76 | 77 | 78 | Relevant `Status` values 79 | - RESOLVED 80 | - RESOLVED FIXED 81 | - VERIFIED 82 | - VERIFIED FIXED 83 | 84 | Relevant `Product` values 85 | - Add-on SDK 86 | - Cloud Services 87 | - Core 88 | - Firefox 89 | - Hello (Loop) 90 | - Toolkit 91 | 92 | 93 | Relevant `Component` value (belonging to Product: Core) 94 | - Embedding:APIs 95 | 96 | Irrelevant `Component` values (all belonging to Product: Core) 97 | - AutoConfig 98 | - Build Config 99 | - DMD 100 | - Embedding: GRE Core 101 | - Embedding: Mac 102 | - Embedding: MFC Embed 103 | - Embedding: Packaging 104 | - Hardware Abstraction Layer 105 | - mach 106 | - Nanojit 107 | - QuickLaunch 108 | - Widget: Gonk 109 | 110 | Irrelevant are also considered bugs with restricted access (you may find the bugs which were filtered out for being private, by opening Web Console and enter 'requires authorization' in the 'Filter output' textbox. Then you may click on the relevant links to open them (those that you have access to). 111 | 112 | 113 |
114 | Thanks a lot to: 115 | - wOxxOm for his help in [here](https://greasyfork.org/en/forum/discussion/6616/help-with-making-a-function-wait-until-all-gm-xmlhttprequest-requests-are-fully-completed), 116 | - Brock Adams for his help on [this](http://stackoverflow.com/questions/33347825/jquery-ui-dialog-in-a-userscript-for-greasemonkey-missing-close-button) i.e. [this](http://stackoverflow.com/a/25468298/3231411), and 117 | - johnp for modifying my code thus offering [v4](http://forums.mozillazine.org/viewtopic.php?p=14397041#p14397041) and [v4.1](http://forums.mozillazine.org/viewtopic.php?p=14397041#p14397041) that is [here](http://pastebin.com/5LwQUsLF). Your contribution is most appreciated! 118 | -------------------------------------------------------------------------------- /Firefox_for_desktop_-_list_modified_bugs_in_Mercurial_as_sortable_table/README.md: -------------------------------------------------------------------------------- 1 | Example link where the script applies to: *(changelogs for the last 1 day interval in these examples)* 2 | **Inbound**: https://hg.mozilla.org/integration/mozilla-inbound/pushloghtml?startdate=1+day+ago&enddate=now 3 | 4 | It's a further modified version of [Firefox for desktop - list fixed bugs in Mercurial](https://greasyfork.org/en/scripts/13169-firefox-for-desktop-list-fixed-bugs-in-mercurial) 5 | meant for inbound users only. 6 | 7 | It doesn't show only the RESOLVED and VERIFIED bugs as in v5.5.2 (and it displays their status in the resulting table) 8 | The reason why is because in the inbound(hourly) builds 9 | the patches land on a hourly basis, 10 | so, in this way, it shows the bugs for which patches have landed in the given interval, even if they aren't considered fixed yet. 11 | 12 | 13 | [![](https://i.imgur.com/SbqOUemh.jpg)](https://i.imgur.com/SbqOUem.jpg) 14 | -------------------------------------------------------------------------------- /GitHub_Confirmations_before_submitting_issues_and_comments/GitHub_Confirmations_before_submitting_issues_and_comments.user.js: -------------------------------------------------------------------------------- 1 | // ==UserScript== 2 | // @name GitHub - Confirmations before submitting issues and comments 3 | // @namespace darkred 4 | // @version 2017.4.26 5 | // @description Creates a confirmation popup whenever attempting to create an issue or post comment via Ctrl+Enter in GitHub 6 | // @author darkred 7 | // @license MIT 8 | // @include https://github.com/* 9 | // @grant none 10 | // @supportURL https://github.com/darkred/Userscripts/issues 11 | // ==/UserScript== 12 | 13 | 14 | 15 | (function () { 16 | function init() { 17 | 18 | 19 | // For submitting issues in issue title textbox via Ctrl+Enter or Enter 20 | 21 | var targArea1 = document.querySelector('#issue_title'); // New issue title 22 | function manageKeyEvents1(zEvent) { 23 | targArea1.blur(); 24 | targArea1.focus(); 25 | if ((zEvent.ctrlKey && zEvent.keyCode === 13) || zEvent.keyCode === 13) { 26 | if (confirm('Are you sure?') === false) { 27 | zEvent.stopPropagation(); 28 | zEvent.preventDefault(); 29 | } else { 30 | var btn = document.querySelector('.btn-primary'); // 'Submit new issue' button 31 | btn.click(); 32 | } 33 | } 34 | } 35 | if (targArea1 !== null) {targArea1.addEventListener('keydown', manageKeyEvents1);} 36 | 37 | 38 | // ------------------------------------------------------------------------------------------------ 39 | 40 | 41 | // For submitting issues in issue body textarea via Ctrl+Enter 42 | var targArea2 = document.querySelector('#issue_body'); // New issue textarea 43 | function manageKeyEvents2(zEvent) { 44 | targArea2.blur(); 45 | targArea2.focus(); 46 | if (zEvent.ctrlKey && zEvent.keyCode === 13) { 47 | if (confirm('Are you sure?') === false) { 48 | zEvent.stopPropagation(); 49 | zEvent.preventDefault(); 50 | } else { 51 | var btn1 = document.querySelector('.btn-primary'); 52 | if (btn1) {btn1.click();} 53 | } 54 | } 55 | } 56 | if (targArea2 !== null) { targArea2.addEventListener('keydown', manageKeyEvents2); } 57 | 58 | 59 | // ------------------------------------------------------------------------------------------------ 60 | 61 | 62 | // For submitting issues in new comment textarea via Ctrl+Enter 63 | var targArea3 = document.querySelector('#new_comment_field'); // New comment textarea 64 | function manageKeyEvents3(zEvent) { 65 | targArea3.blur(); 66 | targArea3.focus(); 67 | if (zEvent.ctrlKey && zEvent.keyCode === 13) { 68 | if (confirm('Are you sure?') === false) { 69 | zEvent.stopPropagation(); 70 | zEvent.preventDefault(); 71 | } else { 72 | var btn2 = document.querySelector('#partial-new-comment-form-actions button'); 73 | if (btn2) {btn2.click();} 74 | } 75 | } 76 | } 77 | if (targArea3 !== null) { targArea3.addEventListener('keydown', manageKeyEvents3); } 78 | 79 | 80 | 81 | 82 | 83 | } 84 | init(); 85 | document.addEventListener('pjax:end', init); // for the History API 86 | })(); 87 | -------------------------------------------------------------------------------- /GitHub_Confirmations_before_submitting_issues_and_comments/README.md: -------------------------------------------------------------------------------- 1 | GitHub by default allows in the issues area for a public repo: 2 | 3 | - submitting a new issue with just 1 character as title and no body, and 4 | - posting a comment with just 1 character. 5 | 6 |
7 | This script creates a confirmation popup whenever attempting to submit an issue or post a comment via Ctrl+Enter in GitHub 8 | i.e. it applies in these 3 cases: 9 | 10 | - when attempting to submit a new issue (while having focus in issue title textbox) via Ctrl+Enter or Enter 11 | - when attempting to submit a new issue (while having focus in issue body textarea) via Ctrl+Enter 12 | - when attempting to submit a new comment (while having focus in the new comment textarea) via Ctrl+Enter 13 | 14 |
15 | 16 | Thanks to trespassersW for his help [here](https://greasyfork.org/en/discussions/development/55889-script-for-creating-a-confirmation-popup-when-submitting-closing-an-issue-via-ctrl-enter-in-github#comment-145065). 17 | -------------------------------------------------------------------------------- /Google_youtube_search_link/Google_youtube_search_link.user.js: -------------------------------------------------------------------------------- 1 | // ==UserScript== 2 | // @name Google YouTube search link 3 | // @namespace darkred 4 | // @author wOxxOm, darkred 5 | // @license MIT 6 | // @description Adds a YouTube search link next to the Videos link (e.g. Web, Images, Videos, YouTube, News, Maps, Shopping, ...) 7 | // @version 2022.5.27 8 | // @include https://www.google.com/* 9 | // @include /https?:\/\/(www\.)?google\.(com|(?:com?\.)?\w\w)\/.*/ 10 | // @grant none 11 | // @run-at document-start 12 | // @supportURL https://github.com/darkred/Userscripts/issues 13 | // ==/UserScript== 14 | 15 | const escapeHTMLPolicy = (({ trustedTypes }, policy) => 16 | trustedTypes 17 | ? trustedTypes.createPolicy('myEscapePolicy', policy) 18 | : policy)(window, { 19 | createHTML: (str) => str, 20 | }); 21 | 22 | process(); 23 | new MutationObserver(process).observe(document, { childList: true, subtree: true }); 24 | 25 | function process(mutations) { 26 | var youtube = document.querySelector('#__YOUTUBE_SEARCH__'); 27 | if (youtube) 28 | return; 29 | 30 | // Selectors for the bar element that contains all the links (Web, Images, Videos, News, Maps, Shopping, ...) 31 | // '.ndYZfc', is for when the 'Images' tab is selected. The other, '#hdtb', is for all other cases. 32 | var menu = document.querySelector('#hdtb, .ndYZfc'); 33 | if (!menu) 34 | return; 35 | 36 | var menuContainer = menu.querySelector('#hdtb-msb, .tAcEof').parentNode; // '.tAcEof' is for when the 'Images' tab is selected. The other, '#hdtb-msb', is for all other cases. 37 | 38 | if (!youtube) { 39 | var q = '', 40 | queryElement = document.querySelector('input[name="q"]'); // The google search input textbox 41 | if (queryElement) { 42 | if (queryElement.value) 43 | q = encodeURIComponent(queryElement.value); 44 | else { 45 | new MutationObserver(function(mut) { 46 | if (queryElement.value) { 47 | var youtube = document.querySelector('#__YOUTUBE_SEARCH__'); 48 | if (youtube) { 49 | this.disconnect(); 50 | youtube.querySelector('a').href += encodeURIComponent(queryElement.value); 51 | } 52 | } 53 | }).observe(queryElement, { attributes: true, attributeFilter: ['value'] }); // monitor the textbox for changes (your typed criteria) 54 | } 55 | } else if ((q = location.href.match(/^.+?(?:[#/&?](?:q|query))=(.+?)(?:|&.+|\|.+)$/))) 56 | q = q[1]; 57 | 58 | // Source URL: https://upload.wikimedia.org/wikipedia/commons/c/c9/YouTube_play_buttom_dark_icon_%282013-2017%29.svg 59 | // No change is done to its source code (the only thing applied to it is the CSS below) 60 | var svg = ` 61 | 63 | 64 | 65 | 66 | 67 | 72 | 73 | 74 | 75 | `; 76 | 77 | var text = ''; 81 | 82 | const isVideosTabSelected = !!document.querySelector('.hdtb-mitem.hdtb-msel path[d^="M10 16.5l6-4.5-6-4.5"]'); 83 | var node = isVideosTabSelected === false ? document.querySelector(`a[href*='tbm=vid']`) : document.querySelector('path[d^="M10 16.5l6-4.5-6-4.5"]').closest('span').parentNode; 84 | 85 | 86 | // (when the selected/active tab is 'Images') select the 'Images' selected tab svg icon by its path[d] attribute 87 | var imagesTabSelected = !!document.querySelector('path[d^="M14 13l"]').closest('span.rQEFy'); 88 | if (imagesTabSelected) { 89 | text = '' + svg + 'YouTube'; 91 | // select the (next, non-selected/non-active) 'Videos' tab svg icon by its path[d] attribute 92 | node = document.querySelector('path[d^="M10 16.5l6-4.5-6-4.5"]').closest('span'); 93 | } 94 | 95 | const escaped = escapeHTMLPolicy.createHTML(text); 96 | node.parentElement.insertAdjacentHTML('afterend', escaped); // insert the YouTube link 97 | 98 | } 99 | 100 | new MutationObserver(process).observe(menuContainer, { childList: true }); 101 | } 102 | 103 | 104 | function addCss(cssString) { 105 | var head = document.getElementsByTagName('head')[0]; 106 | var newCss = document.createElement('style'); 107 | newCss.type = 'text/css'; 108 | newCss.innerHTML = escapeHTMLPolicy.createHTML(cssString); 109 | head.appendChild(newCss); 110 | } 111 | 112 | addCss(` 113 | #__YOUTUBE_SEARCH__ svg { 114 | filter: invert(100%); 115 | } 116 | `); 117 | -------------------------------------------------------------------------------- /Google_youtube_search_link/README.md: -------------------------------------------------------------------------------- 1 | This script is a fork of [Google youtube search link](https://greasyfork.org/en/scripts/7784-google-youtube-search-link) by wOxxOm. 2 | Thanks to wOxxOm for the initial version. 3 | 4 | --- 5 | 6 | This script applies to Google search (using any language). 7 | 8 | It inserts a `YouTube` link next to the `Videos` one, i.e. `Videos | YouTube` 9 | in order to search for the given criteria in YouTube. 10 | _It doesn't rearrange the rest links (see note)._ 11 | 12 | 13 | i.e. if you type something in google search that looks like you're searching for _images_, 14 | the links will become [2] : 15 | `All | Images | Videos | YouTube | etc` 16 | 17 | If it looks like you're looking for _videos_, the links will become: 18 | `All | Videos | YouTube | Images | etc` 19 | 20 | If you type something that looks like an _address_, the links will become: 21 | `All | Maps | Images | Videos | YouTube | News | More` 22 | 23 | If you type something that's related to some recent _news_, the links will become: 24 | `All | News | Images | Videos | YouTube | Maps | More` 25 | 26 | And, if you type a _book_ title then the links will become: 27 | `All | Images | Videos | YouTube | Books | News | More` 28 | 29 | 30 |
31 | 32 | _Notes:_ 33 | 1. The initial script was offering: 34 | - either (by default) to re-arrange links so that the Images, Videos, Youtube links to always be on 2nd, 3rd, 4th places, 35 | _which was breaking the Google's default tabs order (which takes into account the kind of search criteria that you have entered) and is removed in this fork._ 36 | - or to add the YouTube link after all existing links, to the right (with some spacing in between). 37 | 2. The script currently no longer works when you are in the 'Images' tab, because the selectors are changed. [TODO] 38 | *see https://github.com/darkred/Userscripts/issues/20#issuecomment-778643921* -------------------------------------------------------------------------------- /GreasyFork_-_add_a_send_PM_to_user_button_in_Greasyfork_profile_pages/GreasyFork_-_add_a_send_PM_to_user_button_in_Greasyfork_profile_pages.user.js: -------------------------------------------------------------------------------- 1 | // ==UserScript== 2 | // @name GreasyFork - add a 'send PM to user' button in Greasyfork profile pages 3 | // @namespace darkred 4 | // @version 2021.1.22 5 | // @description Adds a 'send PM to user' button in Greasyfork profile pages (also compatible with Citrus GFork). 6 | // @author darkred 7 | // @license MIT 8 | // @include https://greasyfork.org/*/users/* 9 | // @include https://greasyfork.org/*/forum/messages/add 10 | // @include https://sleazyfork.org/*/users/* 11 | // @include https://sleazyfork.org/*/forum/messages/add 12 | // @run-at document-idle 13 | // @grant none 14 | // @supportURL https://github.com/darkred/Userscripts/issues 15 | // ==/UserScript== 16 | 17 | 18 | var yourProfileNameElement = document.querySelector('.user-profile-link > a:nth-child(1)'); 19 | if (yourProfileNameElement !== null) { 20 | var yourProfileName = yourProfileNameElement.innerHTML; 21 | var yourProfileURL = yourProfileNameElement.href; 22 | // https://greasyfork.org/en/users/2160-darkred 23 | // https://greasyfork.org/en/users/2160-darkred/conversations/new 24 | // https://greasyfork.org/en/users/2160-darkred/conversations/new?other_user=JasonBarnabe 25 | var yourCreateNewConversationURL = yourProfileURL + '/conversations/new' ; 26 | } 27 | 28 | var targetProfileNameElement = document.querySelector('.text-content > h2'); 29 | if (targetProfileNameElement !== null) { 30 | // var targetProfileName = targetProfileNameElement.firstChild.textContent.replace('\'s Profile', ''); // the .firstChild is for mods profile pages, e.g. https://greasyfork.org/en/users/1-jasonbarnabe , https://greasyfork.org/en/users/2159-woxxom 31 | var targetProfileName = targetProfileNameElement.firstChild.textContent; // the .firstChild is for mods profile pages, e.g. https://greasyfork.org/en/users/1-jasonbarnabe , https://greasyfork.org/en/users/2159-woxxom 32 | } 33 | 34 | 35 | if (window.location.href.indexOf('users') !== -1 // if current URL is a profile page 36 | && yourProfileName !== targetProfileName // ... and this profile page is not yours 37 | && window.location.href !== yourProfileURL + '/conversations' // ... and this profile page is not your conversations page 38 | && window.location.href.indexOf('conversations/new') === -1) { // .. and this page is not a 'Create a new conversation' page 39 | sessionStorage.setItem('recipient', targetProfileName); // store in sessionStorage the profileName (it will be inserted in the 'Recipients' textbox ) -after you press the button- 40 | var a = document.createElement('a'); 41 | targetProfileNameElement.appendChild(a); 42 | a.style.padding = '0px 12px'; 43 | var img = document.createElement('img'); 44 | a.appendChild(img); 45 | // http://i.imgur.com/ZU0xS0c.jpg 46 | img.setAttribute('src', 'data:image/jpeg;base64,/9j/2wBDAAMCAgMCAgMDAwMEAwMEBQgFBQQEBQoHBwYIDAoMDAsKCwsNDhIQDQ4RDgsLEBYQERMUFRUVDA8XGBYUGBIUFRT/2wBDAQMEBAUEBQkFBQkUDQsNFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBT/wAARCAATABcDAREAAhEBAxEB/8QAFwABAQEBAAAAAAAAAAAAAAAABwAICf/EACgQAAEEAQMCBQUAAAAAAAAAAAECAwQFEQAGEgcIEyEiMUEUNmGl4//EABQBAQAAAAAAAAAAAAAAAAAAAAD/xAAUEQEAAAAAAAAAAAAAAAAAAAAA/9oADAMBAAIRAxEAPwDof1i6ryOlkCHIi0YvlvJdccjpl+A4203x5OAcFFQHMZx7A59skAMDvnyfsj9t/DQPnS/fUnqDtxyxmVQpJbb5YdgGT462jxSoBZ4p4qIWDxIyMjPn5ADTuZg3ibzZN1R0c+7kVf1q0twoy3gh1QZDZcCQfTkFWD5K4lPzoAqDXblqLJq7r+kVoxuFDiXA85AkOQ0KBBKm43h+lR/KylOfSkYGA0f2x0s6m2demdVz6gzLt+W1Gsm1oeCFNM+/IAqwQpPL5450DBoLQWg//9k='); 47 | a.id = 'pmButton'; 48 | a.title = 'Send PM to ' + targetProfileName; 49 | // var yourCreateNewConversationURL = yourProfileURL + '/conversations/new' ; 50 | // https://greasyfork.org/en/users/2160-darkred/conversations/new?other_user=JasonBarnabe 51 | a.href = yourCreateNewConversationURL + '?other_user=' + targetProfileName; 52 | } 53 | -------------------------------------------------------------------------------- /GreasyFork_-_add_a_send_PM_to_user_button_in_Greasyfork_profile_pages/README.md: -------------------------------------------------------------------------------- 1 | By default you may send a pm via a user's forum profile page (e.g. see link 1). 2 | With this script you may also send a pm via user's Greasyfork profile page (e.g. see link 2). 3 | 4 | ``` 5 | Forum profile: https://greasyfork.org/en/forum/profile/1/JasonBarnabe 6 | Greasyfork profile: https://greasyfork.org/en/users/1-jasonbarnabe 7 | ``` 8 | 9 | example: 10 | ![](https://i.imgur.com/0pe0Ce2.jpg) 11 | 12 | How it works: 13 | 14 | - By clicking the script's PM icon, the script always gets you to a "Create a new conversation" page (`https://greasyfork.org/en/users/your_username/conversations/new?other_user=target_username`). 15 | - In contrast, by clicking the the site's built-in"Send message" link: 16 | - if you haven't sent any PM before, 17 | it gets you to a "Create a new conversation (`https://greasyfork.org/en/users/your_username/conversations/new?other_user=target_username`) 18 | - if you have send PMs before, 19 | it gets you to a "Conversation with user" page (`https://greasyfork.org/en/users/your_username/conversations/___`) 20 | where all your previous PMs are displayed in the same page, 21 | and you have to scroll down to reach the "Post Reply" form. 22 | 23 | Notes: 24 | 25 | - the button doesn't appear in your own Greasyfork profile page, and it only works when you are logged in, for obvious reasons, 26 | - it is compatible with Citrus GFork. 27 | 28 | [Hosted in GitHub](https://github.com/darkred/Userscripts) -------------------------------------------------------------------------------- /GreasyFork_-_add_a_send_PM_to_user_button_in_Greasyfork_profile_pages/ZU0xS0c.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darkred/Userscripts/5137627e96d6e06cb0d13cc6ebdc5f4f9917cb0a/GreasyFork_-_add_a_send_PM_to_user_button_in_Greasyfork_profile_pages/ZU0xS0c.jpg -------------------------------------------------------------------------------- /GreasyFork_-_filter_discussions_on_scripts_by_review_type_and_author/README.md: -------------------------------------------------------------------------------- 1 | This script applies in discussions list on scripts (yours and of others). 2 | 3 | It adds 3 element sets: 4 | - filter buttons (one to filter the discussions based on type (`Question`, `Bad`, `Ok`, `Good`) ), 5 | - a hoverable dropdown menu, and 6 | - an autocomplete searchbox 7 | to filter the discussions based on author. 8 | 9 | The author's list in the hoverable dropdown menu is sorted based on the usernames as they appear on the page. 10 | 11 | It's partially based on this script: [userscripts.org Bullshit Filter](http://userscripts-mirror.org/scripts/show/97145) (by kuehlschrank). 12 | Thanks a lot to kuehlschrank for making another great script. 13 | 14 | It also works with [[TS] Citrus GFork](https://greasyfork.org/en/scripts/4336-ts-citrus-gfork). 15 | Τhanks to decembre for contributing the needed changes. 16 | 17 | 18 | Screen capture: 19 | ![](https://i.imgur.com/Yn8cK3Q.gif) 20 | 21 | 22 | 23 | *Tested in Greasemonkey.* 24 | 25 | [Hosted in GitHub](https://github.com/darkred/Userscripts) 26 | -------------------------------------------------------------------------------- /GreasyFork_-_filter_libraries_in_profiles/GreasyFork_-_filter_libraries_in_profiles.user.js: -------------------------------------------------------------------------------- 1 | // ==UserScript== 2 | // @name GreasyFork - filter libraries in profiles 3 | // @namespace darkred 4 | // @version 2018.9.6 5 | // @description Filters libraries in GreasyFork profiles 6 | // @author darkred 7 | // @contributor Skej 8 | // @license MIT 9 | // @include https://greasyfork.org/*/users/* 10 | // @require https://code.jquery.com/jquery-3.3.1.min.js 11 | // @grant none 12 | // @supportURL https://github.com/darkred/Userscripts/issues 13 | // ==/UserScript== 14 | 15 | 16 | var all = document.querySelectorAll('li[data-script-type="public"], li[data-script-type="library"]').length; 17 | var libraries = document.querySelectorAll('li[data-script-type="library"]').length; 18 | var scripts = all - libraries; 19 | 20 | 21 | var parentElement = document.querySelector('#script-list-sort'); 22 | 23 | var theFirstChild = parentElement.firstChild; 24 | 25 | var div = document.createElement('div'); 26 | parentElement.insertBefore(div, theFirstChild); 27 | 28 | 29 | div.style.position = 'fixed'; 30 | div.style.background = 'white'; 31 | 32 | div.style.top = '150px'; 33 | div.style.right = '287px'; 34 | 35 | 36 | 37 | 38 | 39 | var a = document.createElement('a'); 40 | div.appendChild(a); 41 | a.innerHTML = '' + 'All: ' + '' + '' + all + '' + '
'; 42 | a.onclick = toggleAll; 43 | 44 | 45 | var b = document.createElement('a'); 46 | div.appendChild(b); 47 | b.innerHTML = '' + 'Scripts: ' + '' + '' + scripts + '' + '
'; 48 | b.onclick = toggleScripts; 49 | 50 | 51 | var c = document.createElement('a'); 52 | div.appendChild(c); 53 | c.innerHTML = '' + 'Libraries: ' + '' + '' + libraries + '' + '
'; 54 | c.onclick = toggleLibraries; 55 | 56 | 57 | b.click(); 58 | 59 | function toggleAll(){ 60 | a.style.fontWeight = 'bold'; b.style.fontWeight = 'normal'; c.style.fontWeight = 'normal'; 61 | $('li[data-script-type="public"], li[data-script-type="library"]').show(); 62 | } 63 | 64 | 65 | function toggleScripts(){ 66 | a.style.fontWeight = 'normal'; b.style.fontWeight = 'bold'; c.style.fontWeight = 'normal'; 67 | $('li[data-script-type="public"], li[data-script-type="library"]').hide(); 68 | $('li[data-script-type="public"]').show(); 69 | } 70 | 71 | 72 | function toggleLibraries(){ 73 | a.style.fontWeight = 'normal'; b.style.fontWeight = 'normal'; c.style.fontWeight = 'bold'; 74 | $('li[data-script-type="public"], li[data-script-type="library"]').hide(); 75 | $('li[data-script-type="library"]').show(); 76 | } 77 | -------------------------------------------------------------------------------- /GreasyFork_-_filter_libraries_in_profiles/README.md: -------------------------------------------------------------------------------- 1 | This script applies in profile view (yours and of others). 2 | It's meant for those who have also uploaded libraries (i.e. not only scripts): 3 | By default it shows only the scripts - optionally you may display only the libraries or both. 4 | 5 | It adds these 3 links/buttons on top right: (here, to [my profile](https://greasyfork.org/en/users/2160-darkred)) 6 | ![](https://i.imgur.com/bVXlUH3.jpg) -------------------------------------------------------------------------------- /GreasyFork_Bullshit_Filter/GreasyFork_Bullshit_Filter.user.js: -------------------------------------------------------------------------------- 1 | // ==UserScript== 2 | // @name GreasyFork Bullshit Filter 3 | // @namespace darkred 4 | // @version 2021.3.31 5 | // @description Hides scripts for popular browser games and social networks as well as scripts that use "foreign" characters in descriptions. Applies to posts in Forum too. 6 | // @author kuehlschrank, darkred, valacar, Graphen 7 | // @license MIT 8 | // @icon https://raw.githubusercontent.com/darkred/Userscripts/master/GreasyFork_Bullshit_Filter/large.png 9 | // @include /^https:\/\/(greasy|sleazy)fork\.org\/(.*\/)?(scripts|discussions|users).*$/ 10 | // @exclude /^https:\/\/(greasy|sleazy)fork\.org\/(.*\/)?(scripts\/[\w-]+\/feedback|discussions\/[\d]+|users\/.*\/conversations.*)$/ 11 | // @grant none 12 | // This is a modified version of this script (http://userscripts-mirror.org/scripts/show/97145) by kuehlschrank. 13 | // Thanks a lot to: 14 | // - kuehlschrank for making another great script, 15 | // - valacar for the refactoring, 16 | // - Graphen for the 'Non-Latin' regex. 17 | // @supportURL https://github.com/darkred/Userscripts/issues 18 | // ==/UserScript== 19 | 20 | 21 | (function() { 22 | 23 | const DEBUGGING = 0; 24 | 25 | const filters = { 26 | 'Non-ASCII': /[^\x00-\x7F\s]+/, 27 | 'Non-Latin': /[^\u0000-\u024F\u2000-\u214F\s]+/, 28 | 'Games': /Aimbot|AntiGame|Agar|agar\.io|alis\.io|angel\.io|ExtencionRipXChetoMalo|AposBot|DFxLite|ZTx-Lite|AposFeedingBot|AposLoader|Balz|Blah Blah|Orc Clan Script|Astro\s*Empires|^\s*Attack|^\s*Battle|BiteFight|Blood\s*Wars|Bloble|Bonk|Bots|Bots4|Brawler|\bBvS\b|Business\s*Tycoon|Castle\s*Age|City\s*Ville|chopcoin\.io|Comunio|Conquer\s*Club|CosmoPulse|cursors\.io|Dark\s*Orbit|Dead\s*Frontier|Diep\.io|\bDOA\b|doblons\.io|DotD|Dossergame|Dragons\s*of\s*Atlantis|driftin\.io|Dugout|\bDS[a-z]+\n|elites\.io|Empire\s*Board|eRep(ublik)?|Epicmafia|Epic.*War|ExoPlanet|Falcon Tools|Feuerwache|Farming|FarmVille|Fightinfo|Frontier\s*Ville|Ghost\s*Trapper|Gladiatus|Goalline|Gondal|gota\.io|Grepolis|Hobopolis|\bhwm(\b|_)|Ikariam|\bIT2\b|Jellyneo|Kapi\s*Hospital|Kings\s*Age|Kingdoms?\s*of|knastv(o|oe)gel|Knight\s*Fight|\b(Power)?KoC(Atta?ck)?\b|\bKOL\b|Kongregate|Krunker|Last\s*Emperor|Legends?\s*of|Light\s*Rising|lite\.ext\.io|Lockerz|\bLoU\b|Mafia\s*(Wars|Mofo)|Menelgame|Mob\s*Wars|Mouse\s*Hunt|Molehill\s*Empire|MooMoo|MyFreeFarm|narwhale\.io|Neopets|NeoQuest|Nemexia|\bOGame\b|Ogar(io)?|Pardus|Pennergame|Pigskin\s*Empire|PlayerScripts|pokeradar\.io|Popmundo|Po?we?r\s*(Bot|Tools)|PsicoTSI|Ravenwood|Schulterglatze|Skribbl|slither\.io|slitherplus\.io|slitheriogameplay|SpaceWars|splix\.io|Survivio|\bSW_[a-z]+\n|\bSnP\b|The\s*Crims|The\s*West|torto\.io|Travian|Treasure\s*Isl(and|e)|Tribal\s*Wars|TW.?PRO|Vampire\s*Wars|vertix\.io|War\s*of\s*Ninja|World\s*of\s*Tanks|West\s*Wars|wings\.io|\bWoD\b|World\s*of\s*Dungeons|wtf\s*battles|Wurzelimperium|Yohoho|Zombs/iu, 29 | 'Social Networks': /Face\s*book|Google(\+| Plus)|\bHabbo|Kaskus|\bLepra|Leprosorium|MySpace|meinVZ|odnoklassniki|Одноклассники|Orkut|sch(ue|ü)ler(VZ|\.cc)?|studiVZ|Unfriend|Valenth|VK|vkontakte|ВКонтакте|Qzone|Twitter|TweetDeck/iu, 30 | 'Clutter': /^\s*(.{1,3})\1+\n|^\s*(.+?)\n+\2\n*$|^\s*.{1,5}\n|do\s*n('|o)?t (install|download)|nicht installieren|(just )?(\ban? |\b)test(ing|s|\d|\b)|^\s*.{0,4}test.{0,4}\n|\ntest(ing)?\s*|^\s*(\{@|Smolka|Hacks)|\[\d{4,5}\]|free\s*download|theme|(night|dark) ?(mode)?/iu 31 | }; 32 | 33 | const commonCss = ` 34 | .filter-status { 35 | margin-left: 6px; 36 | } 37 | 38 | .filter-switches { 39 | display: none; 40 | } 41 | 42 | :hover>.filter-switches { 43 | display: block; 44 | } 45 | 46 | .filter-on, 47 | .filter-off { 48 | display: block; 49 | width: 100px; 50 | } 51 | 52 | .filter-switches a { 53 | text-decoration: none; 54 | color: inherit; 55 | cursor: pointer; 56 | } 57 | 58 | .filter-switches a { 59 | margin-left: 8px; 60 | padding: 0 4px; 61 | } 62 | 63 | a.filter-on { 64 | background-color: #ffcccc; 65 | color: #333333; 66 | text-decoration: line-through; 67 | } 68 | 69 | a.filter-off { 70 | background-color: #ccffcc; 71 | color: #333333; 72 | } 73 | `; 74 | 75 | const isOnForum = /discussions|feedback/.test(window.location.href); 76 | 77 | const site = {}; 78 | if (isOnForum) { 79 | site.css = '.discussion-list-item.filtered { display: none; } .filter-on, .filter-off { color: black; } ' + commonCss; 80 | site.cssDebug = '.discussion-list-item.filtered { background-color: khaki; } ' + commonCss; 81 | site.filterStatusLocation = '.list-option-groups'; 82 | site.itemsToCheck = '.discussion-list-item'; 83 | site.itemType = 'discussions'; 84 | site.removeFilter = function(el) { 85 | el.classList.remove('filtered'); 86 | }; 87 | site.applyFilter = function(el, activeFilter) { 88 | const temp = el.children[1].innerText; 89 | if (temp && temp.match(activeFilter)) { 90 | el.classList.add('filtered'); 91 | return true; 92 | } 93 | return false; 94 | }; 95 | } else { 96 | site.css = 'li.filtered { display: none; } ' + commonCss; 97 | site.cssDebug = 'li.filtered { background-color: khaki; } ' + commonCss; 98 | site.filterStatusLocation = '#script-list-option-groups'; 99 | site.itemsToCheck = 'article > h2'; 100 | site.itemType = 'scripts'; 101 | site.removeFilter = function(el) { 102 | el.parentNode.parentNode.classList.remove('filtered'); 103 | }; 104 | site.applyFilter = function(el, activeFilter) { 105 | if (el.innerText.match(activeFilter)) { 106 | el.parentNode.parentNode.classList.add('filtered'); 107 | return true; 108 | } 109 | return false; 110 | }; 111 | } 112 | 113 | insertStyle(); 114 | insertStatus(); 115 | filterScripts(); 116 | insertSwitches(); 117 | 118 | function insertStyle() { 119 | const style = document.createElement('style'); 120 | style.textContent = DEBUGGING ? site.cssDebug : site.css; 121 | style.type = 'text/css'; 122 | document.head.appendChild(style); 123 | } 124 | 125 | function insertStatus() { 126 | const p = document.querySelector(site.filterStatusLocation); 127 | if (p) { 128 | const status = document.createElement('span'); 129 | status.className = 'filter-status'; 130 | p.appendChild(status); 131 | } 132 | } 133 | 134 | function filterScripts() { 135 | const activeFilters = []; 136 | for (let filterType of Object.keys(filters)) { 137 | if (configGetValue(filterType, 'on') === 'on') { 138 | activeFilters.push(filters[filterType]); 139 | } 140 | } 141 | const nodes = document.querySelectorAll(site.itemsToCheck); 142 | let numFiltered = 0; 143 | for (let node of nodes) { 144 | site.removeFilter(node); 145 | for (let activeFilter of activeFilters) { 146 | let filtered = site.applyFilter(node, activeFilter); 147 | if (filtered) { 148 | numFiltered++; 149 | break; 150 | } 151 | } 152 | } 153 | const filterStatus = document.querySelector('.filter-status'); 154 | if (filterStatus) { 155 | const numUnfiltered = document.querySelectorAll(site.itemsToCheck).length - numFiltered; 156 | filterStatus.textContent = `${numUnfiltered} ${site.itemType} (${numFiltered} filtered)`; 157 | } 158 | } 159 | 160 | function insertSwitches() { 161 | const span = document.createElement('span'); 162 | span.className = 'filter-switches'; 163 | for (let filterType of Object.keys(filters)) { 164 | span.appendChild(createSwitch(filterType, configGetValue(filterType, 'on') === 'on')); 165 | } 166 | const filterStatus = document.querySelector('.filter-status'); 167 | if (filterStatus) { 168 | filterStatus.parentNode.appendChild(span); 169 | } 170 | } 171 | 172 | function createSwitch(label, isOn) { 173 | const a = document.createElement('a'); 174 | a.className = isOn ? 'filter-on' : 'filter-off'; 175 | a.textContent = label; 176 | a.addEventListener('click', function(e) { 177 | if (this.className === 'filter-on') { 178 | this.className = 'filter-off'; 179 | configSetValue(this.textContent, 'off'); 180 | } else { 181 | this.className = 'filter-on'; 182 | configSetValue(this.textContent, 'on'); 183 | } 184 | filterScripts(); 185 | e.preventDefault(); 186 | }, false); 187 | return a; 188 | } 189 | 190 | function configSetValue(name, value) { 191 | localStorage.setItem(name, value); 192 | } 193 | 194 | function configGetValue(name, defaultValue) { 195 | const value = localStorage.getItem(name); 196 | return value ? value : defaultValue; 197 | } 198 | 199 | })(); 200 | -------------------------------------------------------------------------------- /GreasyFork_Bullshit_Filter/README.md: -------------------------------------------------------------------------------- 1 | Hides scripts for popular browser games and social networks as well as scripts that use "foreign" characters in descriptions, when browsing or searching scripts. 2 | i.e. it filters any/all of these 4 categories: 3 | * **Games**: scripts for browser games like Kingdoms of Camelot, Mafia Wars and Ikariam 4 | * **Social Networks**: scripts for general purpose social networking sites like Facebook, studiVZ and VKontakte 5 | * **Non-ASCII**: scripts that use non-English characters in description (accents, umlauts, cyrillic letters, ...) 6 | * **Clutter**: obvious spam, titles like "asdasdasd", description = title, title < 6 characters, "just a test", scripts for themes/dark/night mode (because they are, in effect, userstyles). 7 | 8 | The filters list appears just below the `#script-list-option-groups` element (i.e. on the right). 9 | ![image](https://i.imgur.com/ASbOvvm.gif) 10 | 11 | *Note: you may uncomment line 35 (and comment out line 46), in order the filtered scripts to be highlighted khaki -instead of hiding them- so that you can check which scripts have been filtered.* 12 | 13 | This is a modified version of this script: [userscripts.org Bullshit Filter](http://userscripts-mirror.org/scripts/show/97145) (by kuehlschrank). 14 | Thanks a lot to kuehlschrank for making another great script. 15 | Thanks a lot to valacar for [the refactoring](https://greasyfork.org/en/forum/discussion/42803/refactored). 16 | -------------------------------------------------------------------------------- /GreasyFork_Bullshit_Filter/large.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darkred/Userscripts/5137627e96d6e06cb0d13cc6ebdc5f4f9917cb0a/GreasyFork_Bullshit_Filter/large.png -------------------------------------------------------------------------------- /GreasyFork_Bullshit_Filter_-_for_TS_Citrus_Gfork/README.md: -------------------------------------------------------------------------------- 1 | Hides scripts for popular browser games and social networks as well as scripts that use "foreign" characters in descriptions, when browsing or searching scripts. 2 | i.e. it filters any/all of these 4 categories: 3 | * **Games**: scripts for browser games like Kingdoms of Camelot, Mafia Wars and Ikariam 4 | * **Social Networks**: scripts for general purpose social networking sites like Facebook, studiVZ and VKontakte 5 | * **Non-ASCII**: scripts that use non-English characters in description (accents, umlauts, cyrillic letters, ...) 6 | * **Clutter**: obvious spam, titles like "asdasdasd", description = title, title < 6 characters, "just a test", scripts for themes/dark/night mode (because they are, in effect, userstyles). 7 | 8 | 9 | It's the same as [GreasyFork Bullshit Filter](https://greasyfork.org/en/scripts/12179-greasyfork-bull-filter,) now compatible with [TS] Citrus GFork. 10 | Per-request [here](https://greasyfork.org/en/forum/discussion/6643/x) 11 | Note: you may comment out #49 and uncomment #50 in order to change position of the filters list 12 | *(the filters list appears either below the GreasyFork logo (one-line), or a bit lower,on top of the results table(multi-lines))* 13 | ![image](https://i.imgur.com/ASbOvvm.gif) 14 | 15 | 16 | This is a modified version of this script: [userscripts.org Bullshit Filter](http://userscripts-mirror.org/scripts/show/97145) (by kuehlschrank). 17 | Thanks a lot to kuehlschrank for making another great script. 18 | Thanks a lot to valacar for [the refactoring](https://greasyfork.org/en/forum/discussion/42803/refactored). 19 | -------------------------------------------------------------------------------- /GreasyFork_Bullshit_Filter_-_for_TS_Citrus_Gfork/large.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darkred/Userscripts/5137627e96d6e06cb0d13cc6ebdc5f4f9917cb0a/GreasyFork_Bullshit_Filter_-_for_TS_Citrus_Gfork/large.png -------------------------------------------------------------------------------- /IMDb_user_reviews_pages_-_ten_star_ratings/IMDb_user_reviews_pages_-_ten_star_ratings.user.js: -------------------------------------------------------------------------------- 1 | // ==UserScript== 2 | // @name IMDb user reviews pages - ten star ratings 3 | // @namespace darkred 4 | // @version 2018.4.30 5 | // @description In IMDb user reviews pages, display the ratings with 10 stars, instead of just 1 6 | // @author darkred 7 | // @license MIT 8 | // @match https://www.imdb.com/title/*/reviews* 9 | // @grant GM_addStyle 10 | // @supportURL https://github.com/darkred/Userscripts/issues 11 | // ==/UserScript== 12 | 13 | 14 | 15 | // Example: 16 | // rating = 9 17 | // is displayed as: 18 | // 1 star + 9/10 text 19 | // 20 | // Therefore: (1 existing +) 8 more stars needed 21 | // and, if element is larger than 9, i.e. >9, i.e. 10th then blacken it 22 | 23 | 24 | const fillColor = ['#e8e7e7', '#e6e5e5']; // default (almost white --> a bit darker) 25 | // const fillColor = ['#2b2b2b', '#2f2f2f']; // for use with a dark style 26 | 27 | 28 | 29 | function addStars(){ 30 | 31 | let stars = document.querySelectorAll('.ipl-star-icon'); 32 | 33 | for (let i = 0; i < stars.length; i++) { 34 | 35 | if (stars[i].parentNode.children.length !== 12) { // if not already 10-star (+ 2 elements) 36 | 37 | let rating = Number(stars[i].nextElementSibling.textContent); 38 | for (let j = 0; j < 9; j++) { // 9 more stars to each line 39 | let clone = stars[i].cloneNode(true); 40 | stars[i].parentNode.insertBefore(clone, stars[i].nextSibling); // https://stackoverflow.com/questions/11117519/inserting-a-clone-after-the-original 41 | 42 | } 43 | 44 | 45 | for (let j = 0; j < 10; j++) { 46 | 47 | if (j > rating-1 ) { 48 | if (i % 2 === 0){ // https://stackoverflow.com/a/12984254 (odd/even iterations of the loop) 49 | stars[i].parentNode.children[j].children[1].setAttribute('style', 'fill:' + fillColor[0] + ';'); // for use with this style: https://userstyles.org/styles/98447/imdb-com-nightmode ---> OK 50 | } else { 51 | stars[i].parentNode.children[j].children[1].setAttribute('style', 'fill:' + fillColor[1] + ';'); // for use with this style: https://userstyles.org/styles/98447/imdb-com-nightmode ---> OK 52 | } 53 | } 54 | 55 | 56 | } 57 | } 58 | 59 | } 60 | 61 | } 62 | 63 | let CSS = ` 64 | svg.ipl-star-icon { 65 | height: 18px; 66 | width: 18px; 67 | vertical-align: middle !important; 68 | } 69 | `; 70 | GM_addStyle(CSS); 71 | 72 | 73 | 74 | addStars(); 75 | 76 | 77 | 78 | 79 | var observer = new MutationObserver(function() { 80 | addStars(); 81 | }).observe(document.querySelector('div.lister-list'), // target of the observer: the "pics" area element, with rows that contain 3 pics each (watching for 'row' element additions) 82 | { 83 | // attributes: true, 84 | childList: true, 85 | // characterData: true, 86 | // subtree: true, 87 | }); // config of the observer -------------------------------------------------------------------------------- /IMDb_user_reviews_pages_-_ten_star_ratings/README.md: -------------------------------------------------------------------------------- 1 | This userscript applies to IMDb user reviews pages. It displays the ratings with 10 stars, instead of just 1. 2 | _It also works when you click the 'Load More' button to view more reviews._ 3 | 4 | Screenshot from e.g. https://www.imdb.com/title/tt0076759/reviews 5 | Intial: 6 | ![initial](https://i.imgur.com/ApMIFAK.jpg) 7 | 8 | With the script: 9 | ![With the script](https://i.imgur.com/Wl0PKtQ.jpg) 10 | 11 | Note: if you use this style: [IMDb.com - Nightmode](https://userstyles.org/styles/98447/imdb-com-nightmode) (like me) then comment out line 22 and uncomment line 29, 12 | in order the extra stars to be almost-black (instead of almost-white). 13 | -------------------------------------------------------------------------------- /Instagram_-_visible_images_counter/README.md: -------------------------------------------------------------------------------- 1 | This script in profile pages in Instagram. 2 | It adds a static element in the upper right corner of the page, 3 | showing how many images out of total are visible (and also as a percentage) (see screenshot in the end). 4 | Also, if you scroll down, beyond the first 12 images, 5 | then the "LOAD MORE" button(to show more images) will be automatically clicked (so, it's bypassed). 6 | 7 | The instagram site uses single-page application workflow (i.e. the history API). 8 | Since v2016.08.02 it's no no longer needed to open a profile page in a new tab *(now using the excellent library [arrive.js](https://github.com/uzairfarooq/arrive)). 9 | 10 | Thanks a lot to wOxxOm for his valuable help in [here](https://greasyfork.org/en/forum/discussion/4642/help-with-making-a-hovering-element-that-scrolls-with-you-with-attaching-to-infinite-scrolling-event). 11 | 12 | 13 | ![Screenshot](https://greasyfork.org/system/screenshots/screenshots/000/001/676/original/2015-08-11_195605_.jpg?1439312224) -------------------------------------------------------------------------------- /KAT_-_add_APPROVE_ALL_and_APPROVE_SELECTED_buttons_to_Feedback_popup/KAT_-_add_APPROVE_ALL_and_APPROVE_SELECTED_buttons_to_Feedback_popup.user.js: -------------------------------------------------------------------------------- 1 | // ==UserScript== 2 | // @name KAT - add APPROVE ALL and APPROVE SELECTED buttons to Feedback popup 3 | // @namespace darkred 4 | // @version 2015.12.30 5 | // @description Adds 'APPROVE ALL' and 'APPROVE SELECTED' buttons inside the 'Torrents awaiting feedback' popup 6 | // @author darkred 7 | // @license MIT 8 | // @include https://kat.cr/* 9 | // @grant none 10 | // @supportURL https://github.com/darkred/Userscripts/issues 11 | // ==/UserScript== 12 | 13 | 14 | 15 | 16 | 17 | function approveAll() { 18 | var x = document.getElementsByClassName('ka-thumbs-up'); 19 | for (var i = 2; i < x.length; i++) { 20 | x[i].click(); 21 | } 22 | } 23 | 24 | 25 | function approveSelected() { 26 | var x = document.getElementsByClassName('torrentboxes'); 27 | var y = document.querySelectorAll('table > tbody > tr > td > div > form > div > a > i.ka-thumbs-up '); 28 | for (var i = 0; i < x.length; i++) { 29 | if (x[i].checked){ 30 | y[i].click(); 31 | } 32 | } 33 | } 34 | 35 | 36 | 37 | 38 | 39 | 40 | document.querySelector('.showFeedback > a').addEventListener('click', function() { 41 | 42 | 43 | new MutationObserver(function(mutations, observer) { 44 | if (document.querySelector('#fancybox-wrap') ) { 45 | observer.disconnect(); 46 | console.log('TRUE'); 47 | 48 | 49 | 50 | // add button "APPROVE SELECTED" 51 | var parentElement = document.querySelector('div.buttonsline:nth-child(10)'); 52 | var theFirstChild = parentElement.firstChild; 53 | var button1 = document.createElement('BUTTON'); 54 | parentElement.insertBefore(button1, theFirstChild); 55 | button1.id = 'mybutton1'; 56 | button1.innerHTML = 'APPROVE SELECTED'; 57 | button1.className = 'siteButton bigButton'; 58 | 59 | button1.addEventListener('click', function() { 60 | approveSelected(); 61 | // document.querySelector('#fancybox-close').click(); // uncomment this line to also close the popup after approving all torrents. 62 | }); 63 | 64 | 65 | 66 | // add button "APPROVE ALL" 67 | parentElement = document.querySelector('div.buttonsline:nth-child(10)'); 68 | theFirstChild = parentElement.firstChild; 69 | var button2 = document.createElement('BUTTON'); 70 | parentElement.insertBefore(button2, theFirstChild); 71 | button2.id = 'mybutton2'; 72 | button2.innerHTML = 'APPROVE ALL'; 73 | button2.className = 'siteButton bigButton'; 74 | button2.style = 'margin-right: 4px'; 75 | 76 | button2.addEventListener('click', function() { 77 | approveAll(); 78 | document.querySelector('#fancybox-close').click(); // uncomment this line to also close the popup after approving all torrents. 79 | }); 80 | 81 | 82 | 83 | 84 | // add button "DISCARD ALL" 85 | parentElement = document.querySelector('button.siteButton:nth-child(3)'); 86 | theFirstChild = parentElement.firstChild; 87 | var button3 = document.createElement('BUTTON'); 88 | parentElement.parentNode.insertBefore(button3, theFirstChild.nextSibling); 89 | button3.id = 'mybutton3'; 90 | button3.innerHTML = 'DISCARD ALL'; 91 | button3.className = 'siteButton bigButton'; 92 | 93 | button3.addEventListener('click', function() { 94 | document.querySelector('th.lasttd:nth-child(1) > input:nth-child(1)').click(); 95 | document.querySelector('button.siteButton:nth-child(3)').click(); 96 | // document.querySelector('#fancybox-close').click(); // uncomment this line to also close the popup after approving all torrents. 97 | }); 98 | 99 | 100 | 101 | 102 | } 103 | }).observe( 104 | document.querySelector('#fancybox-wrap'), { 105 | attributes: true, 106 | attributeFilter: ['style'], 107 | } 108 | ); 109 | 110 | 111 | 112 | 113 | }); 114 | -------------------------------------------------------------------------------- /KAT_-_add_APPROVE_ALL_and_APPROVE_SELECTED_buttons_to_Feedback_popup/README.md: -------------------------------------------------------------------------------- 1 | This script applies to https://kar.cr. 2 | It adds `APPROVE ALL`, `APPROVE SELECTED` and `DISCARD ALL` buttons inside the "Torrents awaiting feedback" popup: 3 | _(by default it only has `DISCARD SELECTED`)_ 4 | ![image](https://i.imgur.com/9okUtOK.jpg) 5 | 6 | _Note: You may uncomment lines 59, 76 and/or 94 to also close the popup after approving all/selected torrents._ 7 | 8 | Thanks to wOxxOm for his help in [here](http://stackoverflow.com/questions/34072802/insertbefore-enclosed-in-addeventlistener-click-and-called-via-mutationobserv). -------------------------------------------------------------------------------- /Markdown_toolbar_for_GreasyFork/66x40-solid.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darkred/Userscripts/5137627e96d6e06cb0d13cc6ebdc5f4f9917cb0a/Markdown_toolbar_for_GreasyFork/66x40-solid.png -------------------------------------------------------------------------------- /Markdown_toolbar_for_GreasyFork/README.md: -------------------------------------------------------------------------------- 1 | The script is a modified version of by wOxxOm, to work with the new GF layout. 2 | Thanks to wOxxOm for offering the initial versions. 3 | 4 | * Common formatting buttons (markdown only) 5 | * (forum) HTML & markdown formatting help links 6 | * CODE markdown button that wraps selected text in \` or \``` if multiple lines are selected. 7 | * MARKDOWN format by default for new comments - also can be set in your profile settings. 8 | 9 | Tested on Chrome/Firefox with Tampermonkey/Violentmonkey *(Greasemonkey is not supported)*. 10 | 11 | Screenshots: 12 | 13 |
14 | Forum 15 | 16 | ![](https://i.imgur.com/lxFoQBs.jpg) ![](https://i.imgur.com/9CLLAzV.jpg) 17 |
18 | 19 |
20 | Publish script | Info 21 | 22 | ![](https://i.imgur.com/poPEKZ3.jpg) 23 |
24 | 25 |
26 | Conversations/pm 27 | 28 | ![](https://i.imgur.com/VZ4clqQ.jpg) 29 |
-------------------------------------------------------------------------------- /Markdown_toolbar_for_reddit.com/66x40-solid.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darkred/Userscripts/5137627e96d6e06cb0d13cc6ebdc5f4f9917cb0a/Markdown_toolbar_for_reddit.com/66x40-solid.png -------------------------------------------------------------------------------- /Markdown_toolbar_for_reddit.com/Markdown_toolbar_for_redditcom.user.js: -------------------------------------------------------------------------------- 1 | // ==UserScript== 2 | // @name Markdown toolbar for reddit.com 3 | // @namespace darkred 4 | // @version 1.4.1 5 | // @description Creates a Markdown toolbar whenever you make/edit text posts or comments in reddit.com 6 | // @author wOxxOm, darkred 7 | // @license MIT 8 | // @include https://www.reddit.com/*submit* 9 | // @include https://old.reddit.com/*submit* 10 | // @include https://www.reddit.com/*comments* 11 | // @include https://old.reddit.com/*comments* 12 | // @grant GM_addStyle 13 | // @icon https://raw.githubusercontent.com/dcurtis/markdown-mark/master/png/66x40-solid.png 14 | // 15 | // 16 | // This is a modified version of the script "Markdown toolbar for GreasyFork and UserStyles.org" ()https://greasyfork.org/en/scripts/6779-markdown-toolbar-for-greasyfork-and-userstyles-org) 17 | // Thanks a lot to wOxxOm for making that script. 18 | // 19 | // @supportURL https://github.com/darkred/Userscripts/issues 20 | // ==/UserScript== 21 | 22 | 23 | var x; 24 | 25 | // IF IT'S A SUBMIT PAGE 26 | if (window.location.href.indexOf('submit') > - 1) { 27 | // THEN ADD TOOLBAR TO THE 'NEW POST' TEXTBOX 28 | x = document.querySelectorAll('div.md > textarea:nth-child(1)')[0].parentNode; 29 | addFeatures(x); 30 | } 31 | else { 32 | var textareas = document.querySelectorAll('textarea'); 33 | 34 | // ADD TOOLBAR: TO EDITING YOUR POST, TO 'NEW COMMENT' FORM AND TO EDITING YOUR EXISTING COMMENT(S) 35 | for (var i = 0; i < textareas.length; i++) { 36 | x = document.querySelectorAll('textarea') [i].parentNode; 37 | addFeatures(x); 38 | } 39 | } 40 | 41 | 42 | 43 | 44 | 45 | function addFeatures(n) { 46 | 47 | n.parentNode.textAreaNode = x.firstChild; 48 | 49 | GM_addStyle('\ 50 | .Button {\ 51 | display: inline-block;\ 52 | cursor: pointer;\ 53 | margin: 0px;\ 54 | font-size: 12px;\ 55 | line-height: 1;\ 56 | font-weight: bold;\ 57 | padding: 4px 6px;\ 58 | background: -moz-linear-gradient(center bottom , #CCC 0%, #FAFAFA 100%) repeat scroll 0% 0% #F8F8F8;\ 59 | border: 1px solid #999;\ 60 | border-radius: 2px;\ 61 | white-space: nowrap;\ 62 | text-shadow: 0px 1px 0px #FFF;\ 63 | box-shadow: 0px 1px 0px #FFF inset, 0px -1px 2px #BBB inset;\ 64 | color: #333;}'); 65 | 66 | 67 | // add buttons 68 | btnMake(n, 'B', 'Bold', '**'); 69 | btnMake(n, 'I', 'Italic', '*'); 70 | // btnMake(n, 'U', 'Underline', '',''); 71 | // btnMake(n, 'S', 'Strikethrough', '',''); 72 | btnMake(n, 'S', 'Strikethrough', '~~'); 73 | btnMake(n, '^', 'Superscript', '^','', true); 74 | btnMake(n, '\\n', 'Line break', ' \n', '', true); 75 | btnMake(n, '---', 'Horizontal line', '\n\n---\n\n', '', true); 76 | btnMake(n, 'URL', 'Add URL to selected text', 77 | function(e) { 78 | try {edWrapInTag('[', ']('+prompt('URL'+':')+')', edInit(e.target));} 79 | catch(e) {} 80 | }); 81 | // btnMake(n, 'Image', 'Convert selected https://url to inline image', '!['+'image'+'](', ')'); 82 | btnMake(n, 'Table', 'Insert table template', '\n| head1 | head2 |\n|-------|-------|\n| cell1 | cell2 |\n| cell3 | cell4 |\n', '', true); 83 | btnMake(n, 'Code', 'Apply CODE markdown to selected text', 84 | function(e){ 85 | var ed = edInit(e.target); 86 | if (ed.sel.indexOf('\n') < 0) 87 | edWrapInTag('`', '`', ed); 88 | else 89 | edWrapInTag(((ed.sel1==0) || (ed.text.charAt(ed.sel1-1) == '\n') ? '' : '\n') + '```' + (ed.sel.charAt(0) == '\n' ? '' : '\n'), 90 | (ed.sel.substr(-1) == '\n' ? '' : '\n') + '```' + (ed.text.substr(ed.sel2,1) == '\n' ? '' : '\n'), 91 | ed); 92 | }); 93 | } 94 | 95 | function btnMake(afterNode, label, title, tag1, tag2, noWrap) { 96 | var a = document.createElement('a'); 97 | a.className = 'Button'; 98 | a.innerHTML = label; 99 | a.title = title; 100 | a.style.setProperty('float','right'); 101 | 102 | a.addEventListener('click', 103 | typeof(tag1) === 'function' 104 | ? tag1 105 | : noWrap ? function(e){edInsertText(tag1, edInit(e.target));} 106 | : function(e){edWrapInTag(tag1, tag2, edInit(e.target));}); 107 | 108 | var nparent = afterNode.parentNode; 109 | a.textAreaNode = nparent.textAreaNode; 110 | nparent.insertBefore(a, nparent.firstElementChild); 111 | } 112 | 113 | 114 | 115 | function edInit(btn) { 116 | 117 | var ed = {node: btn.parentNode.textAreaNode } ; 118 | 119 | ed.sel1 = ed.node.selectionStart; 120 | ed.sel2 = ed.node.selectionEnd, 121 | ed.text = ed.node.value; 122 | ed.sel = ed.text.substring(ed.sel1, ed.sel2); 123 | return ed; 124 | } 125 | 126 | 127 | 128 | 129 | function edWrapInTag(tag1, tag2, ed) { 130 | ed.node.value = ed.text.substr(0, ed.sel1) + tag1 + ed.sel + (tag2?tag2:tag1) + ed.text.substr(ed.sel2); 131 | ed.node.setSelectionRange(ed.sel1 + tag1.length, ed.sel1 + tag1.length + ed.sel.length); 132 | ed.node.focus(); 133 | } 134 | 135 | function edInsertText(text, ed) { 136 | ed.node.value = ed.text.substr(0, ed.sel2) + text + ed.text.substr(ed.sel2); 137 | ed.node.setSelectionRange(ed.sel2 + text.length, ed.sel2 + text.length); 138 | ed.node.focus(); 139 | } -------------------------------------------------------------------------------- /Markdown_toolbar_for_reddit.com/README.md: -------------------------------------------------------------------------------- 1 | This script creates a Markdown toolbar whenever you make/edit text posts or comments in reddit.com. 2 | 3 | It offers: 4 | - Common formatting buttons. 5 | - CODE markdown button that wraps selected text in \` or \``` if multiple lines are selected. 6 | 7 | Tested on FF+Greasemonkey. 8 |
9 | 10 | This is a modified version of this script [Markdown toolbar for GreasyFork and UserStyles.org](https://greasyfork.org/en/scripts/6779-markdown-toolbar-for-greasyfork-and-userstyles-org) . 11 | Thanks a lot to wOxxOm for making that script. 12 | 13 | 14 | ![screenshot](https://greasyfork.org/system/screenshots/screenshots/000/002/244/original/2015-10-15_163149.jpg?1444915978) -------------------------------------------------------------------------------- /Metal_Archives_discography_pages_-_Reviews_column_split_and_sortable_tables/Metal_Archives_discography_pages_-_Reviews_column_split_and_sortable_tables.user.js: -------------------------------------------------------------------------------- 1 | // ==UserScript== 2 | // @name Metal Archives discography pages - Reviews column split and sortable tables 3 | // @namespace darkred 4 | // @version 2.1.0 5 | // @date 2020.9.20 6 | // @description Splits the Reviews column into Reviews(count) and Ratings and makes the tables in all discography tabs sortable. 7 | // @author RobG, Brock Adams, Mottie, darkred 8 | // @license MIT 9 | // @include /^https?:\/\/www\.metal-archives\.com/bands?/.*$/ 10 | // @grant GM_addStyle 11 | // @require https://code.jquery.com/jquery-3.5.1.min.js 12 | // @require https://greasyfork.org/scripts/12036-mutation-summary/code/Mutation%20Summary.js 13 | // @require https://cdnjs.cloudflare.com/ajax/libs/jquery.tablesorter/2.31.3/js/jquery.tablesorter.min.js 14 | // @require https://cdnjs.cloudflare.com/ajax/libs/jquery.tablesorter/2.31.3/js/jquery.tablesorter.widgets.min.js 15 | // @require https://cdnjs.cloudflare.com/ajax/libs/jquery.tablesorter/2.31.3/js/extras/jquery.tablesorter.pager.min.js 16 | // 17 | // This userscript uses jQuery v1.11.1, 18 | // the jQuery plugin 'tablesorter' (forked by Rob Garrison (Mottie)) http://mottie.github.io/tablesorter/docs/index.html , 19 | // and the JavaScript library 'Mutation Summary' (https://github.com/rafaelw/mutation-summary) (by Rafael Weinstein). 20 | // 21 | // Thanks a lot for the invaluable help to RobG, Mottie and especially Brock Adams. 22 | // 23 | // @supportURL https://github.com/darkred/Userscripts/issues 24 | // ==/UserScript== 25 | 26 | 27 | /* global MutationSummary */ 28 | 29 | // CSS rules in order to show 'up' and 'down' arrows in each table header 30 | var stylesheet = ` 31 | `; 111 | 112 | $('head').append(stylesheet); 113 | 114 | 115 | 116 | 117 | 118 | function appendColumn(jNode) { 119 | 120 | // STEP 1+2: SPLIT THE 'REVIEWS' COLUMN INTO A 'REVIEWS' COLUMN AND A 'RATINGS' COLUMN 121 | var tbl = jNode[0]; // table reference 122 | 123 | 124 | // If you have logged in (therefore the column 'Tools' exists in the discography table) 125 | if (document.getElementsByClassName('member_name').length >0){ 126 | tbl.rows[0].cells[1].width = '45%'; // In order the column 'Name'(it's the 2nd) to have enough(in fact fixed) width 127 | } else { 128 | tbl.rows[0].cells[0].width = '53%'; // In order the column 'Name'(it's the 1nd) to have enough(in fact fixed) width 129 | } 130 | 131 | 132 | 133 | // If the current sub-table has no data, then stop the execution of the function 134 | if (tbl.rows[1].cells[0].innerHTML === 'Nothing entered yet. Please add the releases, if applicable. ') { 135 | return; 136 | } 137 | 138 | var newCell; 139 | 140 | const cols = tbl.rows[0].cells.length - 1; 141 | 142 | var tr = tbl.tHead.children[0], 143 | th = document.createElement('th'); 144 | 145 | th.innerHTML = 'Ratings'; 146 | th.className = 'ratingsCol'; 147 | tr.appendChild(th); 148 | 149 | for (var i = 1; i < tbl.rows.length; i++) { 150 | var k = tbl.rows[i].cells[cols].innerHTML; // Retrieve the content of the current cell of the Review column and store it to variable k 151 | 152 | 153 | var re1 = /]*>[^(]*[(]([^)]+)/ ; // (RegEx which matches the 'Ratings' percentage(incl.the % symbol) 154 | var l = re1.exec(k); // (Execute the RegEx and store it to variable l) 155 | 156 | newCell = tbl.rows[i].insertCell(-1); // Add a new cell (for the new 'Ratings' column ) -for each row- 157 | 158 | if (re1.test(k)){ // If the RegEx has matches, (only) then create new cells with... 159 | 160 | var re0 = /(]*>)[0-9]*[^(]/ ; // (RegEx which matches the reviews URL) 161 | var url = re0.exec(k); // (Execute the RegEx and store it to variable url) 162 | 163 | newCell.innerHTML = url[1] + l[1] + ''; // ...the Ratings percentage (which is also a link to the Reviews)... 164 | 165 | 166 | var re2 = /]*>([0-9]*)[^(]/ ; // (RegEx which matches the 'Reviews' number) 167 | var m = re2.exec(k); // (Execute the RegEx and store it to variable m) 168 | 169 | newCell = tbl.rows[i].cells[cols]; 170 | newCell.innerHTML = url[1] + m[1] + ''; // ...and the Reviews number (which is also a link to the Reviews) 171 | } 172 | } 173 | 174 | 175 | // TODO: are you login? Then header0: sorter: false 176 | let login; 177 | // if login form doesn't exist (=you have login), then disable sorting (NOT filtering too) on column 0 ("Edit/Tools") 178 | $('#login_form > div > button').length === 0 ? login = false : login = true; 179 | 180 | // STEP 3: MAKE THE DISCOGRAPHY TABLE SORTABLE (using the jQuery plugin "tablesorter") 181 | $(tbl).tablesorter ( { 182 | cssAsc: 'up', 183 | cssDesc: 'down', 184 | headers: { 185 | // 0: {sorter: false} 186 | 0: { sorter: login, 187 | filter: login} 188 | }, 189 | widgets: ['filter'], 190 | ignoreCase: true, 191 | widgetOptions : { 192 | filter_hideFilters : true, 193 | }, 194 | } ); 195 | } 196 | 197 | 198 | function handleDiscographyChanges (muteSummaries) { 199 | var mSummary = muteSummaries[0]; 200 | if (mSummary.added.length) { 201 | appendColumn ( $(mSummary.added[0]) ); 202 | } 203 | } 204 | 205 | 206 | new MutationSummary ( { 207 | callback: handleDiscographyChanges, 208 | rootNode: $('#band_disco')[0], 209 | queries: [ {element: '.discog'} ] 210 | } ); 211 | -------------------------------------------------------------------------------- /Metal_Archives_discography_pages_-_Reviews_column_split_and_sortable_tables/README.md: -------------------------------------------------------------------------------- 1 | This userscript applies to metal-archives.com(Metal Archives), in discography pages. 2 | 3 | It splits the 'Reviews' column into 'Reviews' and 'Ratings' and makes the tables in all discography tabs sortable 4 | (just click on each of the table headers). 5 | *Tip: you can sort multiple columns simultaneously by holding down the `Shift` key and clicking a 2nd, 3rd or even 4th column header.* 6 | (Note: since version 2.0 the [visual glitch/delay](http://i.stack.imgur.com/ABMts.gif) that occured as you switched sub-tabs (tables) appears no more) 7 | 8 | Example *(see screenshots below)* : 9 | http://www.metal-archives.com/bands/Kamelot/166 (DISCOGRAPHY > MAIN tab) 10 | -the script works in all DISCOGRAPHY tabs- 11 | 12 | Tested with Greasemonkey and Tampermonkey. 13 |
14 | 15 | This userscript makes use of: 16 | 17 | - ~~the page's~~ jQuery 1.11.1 ~~(because of the script's '@grant none' imperative), located inside the combined jQuery libraries file http://www.metal-archives.com/min/index.php?g=js,~~ 18 | - the jQuery plugin [tablesorter](http://mottie.github.io/tablesorter/docs/index.html) (forked by Mottie), and 19 | - the JavaScript library [Mutation Summary](https://github.com/rafaelw/mutation-summary) (by Rafael Weinstein). 20 | 21 | Thanks a lot for the invaluable help to RobG, Mottie and especially Brock Adams ([1](http://stackoverflow.com/questions/26331773/javascript-in-an-html-table-how-to-select-part-of-text-matching-some-regex-f), [2](http://stackoverflow.com/questions/26416049/greasemonkey-using-the-waitforkeyelements-utility-how-to-call-a-function-aft), [3](https://github.com/Mottie/tablesorter/issues/990), [4](http://stackoverflow.com/questions/32233895/using-waitforkeyelements-is-it-possible-to-prevent-the-key-element-from-being-d), [5](https://github.com/Tampermonkey/tampermonkey/issues/780)) 22 | 23 | Screenshots 24 | ![initially](https://greasyfork.org/system/screenshots/screenshots/000/001/815/original/1.jpg?1440546373) ![with the script](https://greasyfork.org/system/screenshots/screenshots/000/001/816/original/2_.jpg?1440546373) ![with the script (here sorted by Ratings(avg) in descending order)](https://greasyfork.org/system/screenshots/screenshots/000/001/817/original/3_.jpg?1440546373) 25 | -------------------------------------------------------------------------------- /OpenSubtitles_-_direct_download_links/OpenSubtitles_-_direct_download_links.user.js: -------------------------------------------------------------------------------- 1 | // ==UserScript== 2 | // @name OpenSubtitles - direct download links 3 | // @namespace darkred 4 | // @version 2017.11.6 5 | // @description Converts the subtitles download links to direct ones, in order to avoid redirection to download pages that display ads. 6 | // @author darkred 7 | // @license MIT 8 | // @include https://www.opensubtitles.org/*/search/* 9 | // @include https://www.opensubtitles.org/*/subtitles/* 10 | // @grant none 11 | // @supportURL https://github.com/darkred/Userscripts/issues 12 | // ==/UserScript== 13 | 14 | 15 | // cases for the selectors: 16 | // 1. https://www.opensubtitles.org/en/search/subs 17 | // 2. https://www.opensubtitles.org/en/search/sublanguageid-all/idmovie-513313 18 | // 3. https://www.opensubtitles.website/en/opensubtitles-player.subtitles-download/subtitles/7150264 19 | 20 | var allLinks = document.querySelectorAll(` 21 | html body div.content fieldset table.smalltable tbody tr.change td:nth-child(4) a, 22 | html body div.content form#submultiedit table#search_results tbody tr td:nth-child(5) a, 23 | #bt-dwl-bt 24 | `); 25 | 26 | for (var i = 0; i < allLinks.length; i++) { 27 | allLinks[i].href = allLinks[i].href.replace('subtitleserve/', 'download/vrf-108d030f/'); 28 | } 29 | 30 | var old_element = document.querySelector('#bt-dwl-bt'); 31 | if (old_element){ 32 | var new_element = old_element.cloneNode(true); 33 | old_element.parentNode.replaceChild(new_element, old_element); 34 | } 35 | 36 | 37 | 38 | // in order to avoid the redirections when you click the "Download" button on a subtitle page. 39 | document.querySelector('#bt-dwl-bt').addEventListener('click', function(){ 40 | $('#bt-dwl-bt').off(); // the script uses the page's jQuery, v1.12.2 (https://static.opensubtitles.org/libs/js/jquery/jquery.min.js) 41 | window.location.href = document.querySelector('#bt-dwl-bt').href; 42 | }); 43 | -------------------------------------------------------------------------------- /OpenSubtitles_-_direct_download_links/README.md: -------------------------------------------------------------------------------- 1 | This userscript converts the subtitles download links to direct ones, in order to avoid gettings redirections to download pages that display ads. 2 | 3 | It applies to: 4 | 1. search results, (the links in the column `Downloaded`) e.g. `https://www.opensubtitles.org/en/search/subs` 5 | 2. movie pages (the links in the column `Downloaded`) e.g `https://www.opensubtitles.org/en/search/sublanguageid-all/idmovie-513313` 6 | 3. subtitle pages (the button `Download`) e.g. `https://www.opensubtitles.org/en/subtitles/7149428/transformers-the-last-knight-sv` 7 | -------------------------------------------------------------------------------- /OpenUserJS_Bullshit_Filter/OpenUserJS_Bullshit_Filter.user.js: -------------------------------------------------------------------------------- 1 | // ==UserScript== 2 | // @name OpenUserJS Bullshit Filter 3 | // @namespace darkred 4 | // @version 2019.12.5 5 | // @description Hides scripts for popular browser games and social networks as well as scripts that use "foreign" characters in descriptions. 6 | // @author kuehlschrank, darkred, valacar, Graphen 7 | // @license MIT 8 | // @include /^https:\/\/openuserjs\.org\/((\?(q|p|orderBy|library)=|group\/|users\/.*\/scripts).*)?$/ 9 | // @include /^http:\/\/localhost:8080\/((\?(q|p|orderBy|library)=|group\/|users\/.*\/scripts).*)?$/ 10 | // @grant none 11 | // @icon https://raw.githubusercontent.com/darkred/Userscripts/master/OpenUserJS_Bullshit_Filter/large.png 12 | // This is a modified version of this script (http://userscripts-mirror.org/scripts/show/97145) by kuehlschrank. 13 | // Thanks a lot to: 14 | // - kuehlschrank for making another great script, 15 | // - valacar for the refactoring, 16 | // - Graphen for the 'Non-Latin' regex. 17 | // @supportURL https://github.com/darkred/Userscripts/issues 18 | // ==/UserScript== 19 | 20 | 21 | (function() { 22 | 23 | const DEBUGGING = 0; 24 | 25 | const filters = { 26 | 'Non-ASCII': /[^\x00-\x7F\s]+/, 27 | 'Non-Latin': /[^\u0000-\u024F\u2000-\u214F\s]+/, 28 | 'Games': /Aimbot|AntiGame|Agar|agar\.io|alis\.io|angel\.io|ExtencionRipXChetoMalo|AposBot|DFxLite|ZTx-Lite|AposFeedingBot|AposLoader|Balz|Blah Blah|Orc Clan Script|Astro\s*Empires|^\s*Attack|^\s*Battle|BiteFight|Blood\s*Wars|Bloble|Bonk|Bots|Bots4|Brawler|\bBvS\b|Business\s*Tycoon|Castle\s*Age|City\s*Ville|chopcoin\.io|Comunio|Conquer\s*Club|CosmoPulse|cursors\.io|Dark\s*Orbit|Dead\s*Frontier|Diep\.io|\bDOA\b|doblons\.io|DotD|Dossergame|Dragons\s*of\s*Atlantis|driftin\.io|Dugout|\bDS[a-z]+\n|elites\.io|Empire\s*Board|eRep(ublik)?|Epicmafia|Epic.*War|ExoPlanet|Falcon Tools|Feuerwache|Farming|FarmVille|Fightinfo|Frontier\s*Ville|Ghost\s*Trapper|Gladiatus|Goalline|Gondal|gota\.io|Grepolis|Hobopolis|\bhwm(\b|_)|Ikariam|\bIT2\b|Jellyneo|Kapi\s*Hospital|Kings\s*Age|Kingdoms?\s*of|knastv(o|oe)gel|Knight\s*Fight|\b(Power)?KoC(Atta?ck)?\b|\bKOL\b|Kongregate|Krunker|Last\s*Emperor|Legends?\s*of|Light\s*Rising|lite\.ext\.io|Lockerz|\bLoU\b|Mafia\s*(Wars|Mofo)|Menelgame|Mob\s*Wars|Mouse\s*Hunt|Molehill\s*Empire|MooMoo|MyFreeFarm|narwhale\.io|Neopets|NeoQuest|Nemexia|\bOGame\b|Ogar(io)?|Pardus|Pennergame|Pigskin\s*Empire|PlayerScripts|pokeradar\.io|Popmundo|Po?we?r\s*(Bot|Tools)|PsicoTSI|Ravenwood|Schulterglatze|Skribbl|slither\.io|slitherplus\.io|slitheriogameplay|SpaceWars|splix\.io|Survivio|\bSW_[a-z]+\n|\bSnP\b|The\s*Crims|The\s*West|torto\.io|Travian|Treasure\s*Isl(and|e)|Tribal\s*Wars|TW.?PRO|Vampire\s*Wars|vertix\.io|War\s*of\s*Ninja|World\s*of\s*Tanks|West\s*Wars|wings\.io|\bWoD\b|World\s*of\s*Dungeons|wtf\s*battles|Wurzelimperium|Yohoho|Zombs/iu, 29 | 'Social Networks': /Face\s*book|Google(\+| Plus)|\bHabbo|Kaskus|\bLepra|Leprosorium|MySpace|meinVZ|odnoklassniki|Одноклассники|Orkut|sch(ue|ü)ler(VZ|\.cc)?|studiVZ|Unfriend|Valenth|VK|vkontakte|ВКонтакте|Qzone|Twitter|TweetDeck/iu, 30 | 'Clutter': /^\s*(.{1,3})\1+\n|^\s*(.+?)\n+\2\n*$|^\s*.{1,5}\n|do\s*n('|o)?t (install|download)|nicht installieren|(just )?(\ban? |\b)test(ing|s|\d|\b)|^\s*.{0,4}test.{0,4}\n|\ntest(ing)?\s*|^\s*(\{@|Smolka|Hacks)|\[\d{4,5}\]|free\s*download|theme|(night|dark) ?(mode)?/iu 31 | }; 32 | 33 | const commonCss = ` 34 | .filter-status { 35 | margin-left: 6px; 36 | } 37 | 38 | .filter-switches { 39 | display: none; 40 | } 41 | 42 | :hover>.filter-switches { 43 | display: block; 44 | } 45 | 46 | .filter-on, 47 | .filter-off { 48 | display: block; 49 | width: 125px; 50 | } 51 | 52 | .filter-switches a { 53 | text-decoration: none; 54 | color: inherit; 55 | cursor: pointer; 56 | } 57 | 58 | .filter-switches a { 59 | margin-left: 8px; 60 | padding: 0 4px; 61 | } 62 | 63 | a.filter-on { 64 | background-color: #ffcccc; 65 | color: #333333; 66 | text-decoration: line-through; 67 | } 68 | 69 | a.filter-off { 70 | background-color: #ccffcc; 71 | color: #333333 72 | } 73 | `; 74 | 75 | // const isOnForum = window.location.href.includes('forum'); 76 | 77 | const site = {}; 78 | 79 | 80 | 81 | // if (isOnForum) { 82 | // // site.css = '.ItemDiscussion.filtered { display: none; } .filter-on, .filter-off { color: black; } ' + commonCss; 83 | // site.css = '.tr-link.filtered { display: none; } ' + commonCss; 84 | // site.cssDebug = '.tr-link.filtered { background-color: khaki; } ' + commonCss; 85 | // // site.filterStatusLocation = '#Head'; 86 | // site.filterStatusLocation = '.col-md-2'; 87 | // site.itemsToCheck = '.tr-link'; 88 | // site.itemType = 'discussions'; 89 | // site.removeFilter = function(el) { 90 | // el.classList.remove('filtered'); 91 | // }; 92 | // site.applyFilter = function(el, activeFilter) { 93 | // let textToFilter = el.firstElementChild.firstElementChild.innerText; 94 | // if (textToFilter.match(activeFilter) ) { 95 | // el.classList.add('filtered'); 96 | // return true; 97 | // } 98 | // return false; 99 | // }; 100 | // } else { 101 | 102 | site.css = 'tr.filtered { display: none; } ' + commonCss; 103 | site.cssDebug = 'tr.filtered { background-color: khaki; } ' + commonCss; 104 | site.filterStatusLocation = '.col-sm-4'; 105 | site.itemsToCheck = '.col-sm-8 tbody tr'; 106 | site.itemType = 'scripts'; 107 | site.removeFilter = function(el) { 108 | el.classList.remove('filtered'); 109 | }; 110 | site.applyFilter = function(el, activeFilter) { 111 | // if (el.innerText.match(activeFilter)) { 112 | let textToFilter = el.firstElementChild.querySelector('a.tr-link-a').innerText + ' ' + el.firstElementChild.lastElementChild.innerText ; // Script title + description 113 | if (textToFilter.match(activeFilter) ) { 114 | 115 | el.classList.add('filtered'); 116 | return true; 117 | } 118 | return false; 119 | }; 120 | // } 121 | 122 | insertStyle(); 123 | insertStatus(); 124 | filterScripts(); 125 | insertSwitches(); 126 | 127 | function insertStyle() { 128 | const style = document.createElement('style'); 129 | style.textContent = DEBUGGING ? site.cssDebug : site.css; 130 | style.type = 'text/css'; 131 | document.head.appendChild(style); 132 | } 133 | 134 | function insertStatus() { 135 | const p = document.querySelector(site.filterStatusLocation); 136 | if (p) { 137 | const status = document.createElement('span'); 138 | status.className = 'filter-status'; 139 | p.appendChild(status); 140 | } 141 | } 142 | 143 | 144 | 145 | function filterScripts() { 146 | const activeFilters = []; 147 | for (let filterType of Object.keys(filters)) { 148 | if (configGetValue(filterType, 'on') === 'on') { 149 | activeFilters.push(filters[filterType]); 150 | } 151 | } 152 | const nodes = document.querySelectorAll(site.itemsToCheck); 153 | let numFiltered = 0; 154 | for (let node of nodes) { 155 | site.removeFilter(node); 156 | for (let activeFilter of activeFilters) { 157 | let filtered = site.applyFilter(node, activeFilter); 158 | if (filtered) { 159 | numFiltered++; 160 | break; 161 | } 162 | } 163 | } 164 | const filterStatus = document.querySelector('.filter-status'); 165 | if (filterStatus) { 166 | const numUnfiltered = document.querySelectorAll(site.itemsToCheck).length - numFiltered; 167 | filterStatus.textContent = `${numUnfiltered} ${site.itemType} (${numFiltered} filtered)`; 168 | } 169 | } 170 | 171 | function insertSwitches() { 172 | const span = document.createElement('span'); 173 | span.className = 'filter-switches'; 174 | for (let filterType of Object.keys(filters)) { 175 | span.appendChild(createSwitch(filterType, configGetValue(filterType, 'on') === 'on')); 176 | } 177 | const filterStatus = document.querySelector('.filter-status'); 178 | if (filterStatus) { 179 | filterStatus.parentNode.appendChild(span); 180 | } 181 | } 182 | 183 | function createSwitch(label, isOn) { 184 | const a = document.createElement('a'); 185 | a.className = isOn ? 'filter-on' : 'filter-off'; 186 | a.textContent = label; 187 | a.addEventListener('click', function(e) { 188 | if (this.className === 'filter-on') { 189 | this.className = 'filter-off'; 190 | configSetValue(this.textContent, 'off'); 191 | } else { 192 | this.className = 'filter-on'; 193 | configSetValue(this.textContent, 'on'); 194 | } 195 | filterScripts(); 196 | e.preventDefault(); 197 | }, false); 198 | return a; 199 | } 200 | 201 | function configSetValue(name, value) { 202 | localStorage.setItem(name, value); 203 | } 204 | 205 | function configGetValue(name, defaultValue) { 206 | const value = localStorage.getItem(name); 207 | return value ? value : defaultValue; 208 | } 209 | 210 | })(); 211 | -------------------------------------------------------------------------------- /OpenUserJS_Bullshit_Filter/README.md: -------------------------------------------------------------------------------- 1 | Hides scripts for popular browser games and social networks as well as scripts that use "foreign" characters in descriptions, when browsing or searching scripts. 2 | i.e. it filters any/all of these 4 categories: 3 | * **Games**: scripts for browser games like Kingdoms of Camelot, Mafia Wars and Ikariam 4 | * **Social Networks**: scripts for general purpose social networking sites like Facebook, studiVZ and VKontakte 5 | * **Non-ASCII**: scripts that use non-English characters in description (accents, umlauts, cyrillic letters, ...) 6 | * **Clutter**: obvious spam, titles like "asdasdasd", description = title, title < 6 characters, "just a test", scripts for themes/dark/night mode (because they are, in effect, userstyles). 7 | 8 | The filters list appears just below the "Announcements" table (i.e. on the right). 9 | ![screenshot](https://i.imgur.com/uPvFcSS.gif) 10 | 11 | *Note: you may uncomment line 37 (and comment out line 38), in order the filtered scripts to be highlighted khaki -instead of hiding them- so that you can check which scripts have been filtered.* 12 | 13 | This is a modified version of this script: [userscripts.org Bullshit Filter](http://userscripts-mirror.org/scripts/show/97145) (by kuehlschrank). 14 | Thanks a lot to kuehlschrank for making another great script. 15 | Thanks a lot to valacar for [the refactoring](https://greasyfork.org/en/forum/discussion/42803/refactored). 16 | -------------------------------------------------------------------------------- /OpenUserJS_Bullshit_Filter/large.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darkred/Userscripts/5137627e96d6e06cb0d13cc6ebdc5f4f9917cb0a/OpenUserJS_Bullshit_Filter/large.png -------------------------------------------------------------------------------- /ProtonMail_-_remove_forced_signature/ProtonMail_-_remove_forced_signature.user.js: -------------------------------------------------------------------------------- 1 | // ==UserScript== 2 | // @name ProtonMail - remove forced signature 3 | // @namespace darkred 4 | // @version 2023.6.1 5 | // @description Removes the forced ProtonMail signature from the 'New message' textboxes 6 | // @author darkred 7 | // @license MIT 8 | // @include https://mail.protonmail.com/* 9 | // @include https://mail.proton.me/* 10 | // @include https://protonirockerxow.onion/* 11 | // @include https://protonmailrmez3lotccipshtkleegetolb73fuirgj7r4o4vfu7ozyd.onion/* 12 | // @grant none 13 | // @require https://greasyfork.org/scripts/21927-arrive-js/code/arrivejs.js 14 | // @supportURL https://github.com/darkred/Userscripts/issues 15 | // @icon https://proton.me/favicons/favicon.ico 16 | // ==/UserScript== 17 | 18 | const elementToWatch = 'iframe[title="Email composer"]'; 19 | document.arrive(elementToWatch, function () { 20 | let iframe = this.contentDocument; // refers to the newly created element 21 | 22 | const config = { 23 | childList: true, 24 | subtree: true 25 | }; 26 | 27 | const callback = function(mutationList, observer) { 28 | mutationList.forEach( (mutation) => { 29 | mutation.addedNodes.forEach( (node) => { 30 | 31 | const refNode = 'protonmail_signature_block'; 32 | 33 | if (node.className === refNode) { 34 | 35 | // DOM STRUCTURE: 36 | // 37 | // The 2 previous element siblings of the main signature element, '.protonmail_signature_block', both contain a
element with a
inside, i.e.
=
\
) : 38 | //
\
|
\
| .protonmail_signature_block 39 | // 40 | // The '.protonmail_signature_block' itself has either 3 or 2
children which can be: 41 | // 42 | // (when user signature doesn't exist) the (empty) user signature , and the proton signature 43 | // .protonmail_signature_block-user.protonmail_signature_block-empty | .protonmail_signature_block-proton 44 | // 45 | // (when user signature exists) the user signature , 1
\
, and the signature itself 46 | // .protonmail_signature_block-user |
\
| .protonmail_signature_block-proton 47 | // 48 | // The script's functionality is: 49 | // 1a. If user signature exists(=it's not empty), to remove the
\
element before the last element ('.protonmail_signature_block-proton') ... 50 | // 1b. ... otherwise to remove the 2
\
elements before the main/reference '.protonmail_signature_block' element. 51 | // 2. To remove the last element ('.protonmail_signature_block-proton') itself. 52 | // 53 | // See DOM screenshots: https://imgur.com/a/VEI4nDQ 54 | 55 | 56 | const signatureProton = '.protonmail_signature_block-proton'; 57 | 58 | 59 | if (!node.firstElementChild.classList.contains('protonmail_signature_block-empty')){ 60 | node.querySelector(signatureProton).previousElementSibling.remove(); 61 | } else { 62 | node.previousElementSibling.remove(); 63 | node.previousElementSibling.remove(); 64 | } 65 | 66 | node.querySelector(signatureProton).remove(); 67 | 68 | 69 | observer.disconnect(); 70 | } 71 | }); 72 | 73 | }); 74 | }; 75 | 76 | const observer = new MutationObserver(callback); 77 | observer.observe(iframe, config); 78 | 79 | }); 80 | -------------------------------------------------------------------------------- /ProtonMail_-_remove_forced_signature/README.md: -------------------------------------------------------------------------------- 1 | This userscript applies to https://mail.protonmail.com 2 | *(after the recent layout update there's no `beta` subdomain anymore (`beta.protonmail.com` ) --- enabling 'beta' features is just a toggle button now (Settings | 'Beta Access' )*. 3 | It automatically removes the ProtonMail signature from the 'New message' textboxes, 4 | which is appended by default to each mail body and cannot be modified via Settings in free accounts. 5 | 6 | It uses the excellent library [arrive.js](https://github.com/uzairfarooq/arrive) 7 | 8 | The script only works in Chrome, not Firefox - see [here](https://github.com/darkred/Userscripts/issues/13#issuecomment-739492052) and [here](https://github.com/darkred/Userscripts/issues/43#issuecomment-893362520). 9 | Tampermonkey and Violentmonkey are supported - Greasemonkey is not supported. 10 | -------------------------------------------------------------------------------- /RARBG_-_convert_torrent_timestamps_to_relative_format/RARBG_-_convert_torrent_timestamps_to_relative_format.user.js: -------------------------------------------------------------------------------- 1 | // ==UserScript== 2 | // @name RARBG - convert torrent timestamps to relative format 3 | // @namespace darkred 4 | // @version 2021.11.9 5 | // @description Converts torrent upload timestamps to relative format 6 | // @author darkred 7 | // @license MIT 8 | // @include /^(https?:)?\/\/(www\.)?(proxy|unblocked)?rarbg((2018|2019|2020|2021)?|access(ed)?|cdn|core|data|enter|get|go|index|mirror(ed)?|p2p|prox(ied|ies|y)|prx|to(r|rrents)?|unblock(ed)?|way|web)\.(to|com|org|is)\/(torrents\.php.*|catalog\/.*|s\/.*|tv\/.*|top10)$/ 9 | // @grant none 10 | // @require https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.25.0/moment.min.js 11 | // @require https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.28/moment-timezone-with-data-10-year-range.min.js 12 | // @require https://greasyfork.org/scripts/21927-arrive-js/code/arrivejs.js 13 | // @supportURL https://github.com/darkred/Userscripts/issues 14 | // ==/UserScript== 15 | 16 | 'use strict'; 17 | /* global moment */ 18 | 19 | 20 | // Based on the timestamp on the footer of each RARBG page --> "Sat, 01 May 2020 20:14:56 +0200", the script takes that the server time is GMT+2 and that it doesn't take DST. 21 | // Otherwise, when it's e.g. --> "Mon, 08 Nov 2021 21:26:11 +0100", it takes that the server time is GMT+1 and that it doesn't take DST. 22 | // Also, the script uses the 'moment-timezone' library as it takes DST offsets into account when converting the timestamps to user/local timezone. 23 | 24 | /* 25 | // This is no typo: 26 | // const serverTimezone = 'Etc/GMT+2'; // -02:00 -02:00 (=no DST) 27 | // const serverTimezone = 'Etc/GMT-2'; // +02:00 +02:00 (=no DST) 28 | const serverTimezone = 'Etc/GMT-1'; // +01:00 +01:00 (=no DST) 29 | */ 30 | let serverTimezone; 31 | $('div:contains("SUPPORT :")').contents().last().text().trim().slice(-5) === '+0200' ? serverTimezone = 'Etc/GMT-2' : serverTimezone = 'Etc/GMT-1'; 32 | 33 | 34 | const localTimezone = moment.tz.guess(); // In my case ----> +02:00 +03:00 (DST) 35 | 36 | // const format = 'MM/DD/YYYY HH:mm:ss'; 37 | // const format = 'YYYY-MM-DD HH:mm:ss'; 38 | const format = 'YYYY-MM-DD HH:mm:ss'; 39 | 40 | // Customize the strings in the locale to display "1 minute ago" instead of "a minute ago" (https://github.com/moment/moment/issues/3764#issuecomment-279928245) 41 | moment.updateLocale('en', { 42 | relativeTime: { 43 | future: 'in %s', 44 | past: '%s ago', 45 | s: 'seconds', 46 | m: '1 minute', 47 | mm: '%d minutes', 48 | h: '1 hour', 49 | hh: '%d hours', 50 | d: '1 day', 51 | dd: '%d days', 52 | M: '1 month', 53 | MM: '%d months', 54 | y: '1 year', 55 | yy: '%d years' 56 | } 57 | }); 58 | 59 | 60 | function convertToLocalTimezone(timestamps) { 61 | for (let i = 0; i < timestamps.length; i++) { 62 | let initialTimestamp = timestamps[i].textContent; 63 | if (moment(initialTimestamp, format, true).isValid()) { // As of moment.js v2.3.0, you may specify a boolean for the last argument to make Moment use strict parsing. Strict parsing requires that the format and input match exactly, including delimeters. 64 | let convertedToLocalTimezone = moment.tz(initialTimestamp, format, serverTimezone).tz(localTimezone); 65 | timestamps[i].textContent = convertedToLocalTimezone.fromNow(); 66 | timestamps[i].title = convertedToLocalTimezone.format(format); 67 | // timestamps[i].title = convertedToLocalTimezone.toISOString(); // Display timestamps in tooltips in ISO 8601 format, combining date and time (https://stackoverflow.com/questions/25725019/how-do-i-format-a-date-as-iso-8601-in-moment-js/) 68 | // timestamps[i].title = convertedToLocalTimezone.format(); 69 | } 70 | } 71 | 72 | // recalculate the relative dates every 1 min 73 | (function(){ 74 | for (let i = 0; i < timestamps.length; i++) { 75 | timestamps[i].textContent = moment(timestamps[i].title).fromNow(); 76 | } 77 | // setTimeout(arguments.callee, 10 * 1000); // 10 * 1000 msec = 10 sec = 1/6 min 78 | setTimeout(arguments.callee, 60 * 1000); // 60 * 1000 msec = 1 min 79 | })(); 80 | 81 | } 82 | 83 | 84 | 85 | // Per request: https://greasyfork.org/en/scripts/21550-rarbg-convert-torrent-timestamps-to-relative-format/discussions/91794 86 | const isOnTV = window.location.href.includes('/tv/'); // example link: https://rarbgproxy.org/tv/tt1720601/ 87 | 88 | if (isOnTV) { 89 | 90 | // document.querySelectorAll('.tvshowClick').forEach((element) => { 91 | document.querySelectorAll('div[id^="episode_"]').forEach((element) => { 92 | element.addEventListener('click', function(){ 93 | document.arrive('div[id^="tvcontent_"] .lista2t', function () { 94 | convertToLocalTimezone(document.querySelectorAll('td[width="150px"]')); 95 | }); 96 | }); 97 | }); 98 | 99 | } else { 100 | 101 | // const timestamps = document.querySelectorAll('tr.lista2 td:nth-child(3)'); 102 | const timestamps = document.querySelectorAll('td[width="150px"]'); 103 | convertToLocalTimezone(timestamps); 104 | 105 | } 106 | -------------------------------------------------------------------------------- /RARBG_-_convert_torrent_timestamps_to_relative_format/README.md: -------------------------------------------------------------------------------- 1 | This script applies to RARBG lists: 2 | - it converts torrent timestamps to relative format in local timezone. Also, it recalculates them every 1 min. 3 | - The initial timestamps are still available as tooltips (on mouse hover), also converted to local timezone. 4 | 5 | Note: there's a timestamp on the footer of each RARBG page e.g. `Sun, 28 Mar 2021 18:26:22 +0200`. 6 | Based on that, the script takes that for the server the UTC/UTC DST offsets are `+02:00 +02:00` (=no DST), 7 | therefore the timezone in the above case `GMT-2`. 8 | 9 | Examples: 10 | 11 | > +01:00 +01:00 (=no DST) ---> 'Etc/GMT-1'; 12 | > +02:00 +02:00 (=no DST) ---> 'Etc/GMT-2'; 13 | 14 | It uses [moment.js](http://momentjs.com/) and [moment-timezone.js](http://momentjs.com/timezone/). 15 | 16 | Screenshot comparison: 17 | Initial: 18 | ![](https://i.imgur.com/vdv2xjR.jpg) 19 | With the script: 20 | ![](https://i.imgur.com/iTuWa4d.jpg) 21 | 22 | [Hosted in GitHub](https://github.com/darkred/Userscripts) 23 | -------------------------------------------------------------------------------- /RARBG_-_torrent_and_magnet_links/RARBG_-_torrent_and_magnet_links.user.js: -------------------------------------------------------------------------------- 1 | // ==UserScript== 2 | // @name RARBG - torrent and magnet links 3 | // @namespace darkred 4 | // @version 2021.7.3 5 | // @description Adds a column with torrent and magnet links in lists 6 | // @author darkred 7 | // @contributor sxe, dandyclubs, lx19990999 8 | // @license MIT 9 | // @include /^(https?:)?\/\/(www\.)?(proxy|unblocked)?rarbg((2018|2019|2020|2021)?|access(ed)?|cdn|core|data|enter|get|go|index|mirror(ed)?|p2p|prox(ied|ies|y)|prx|to(r|rrents)?|unblock(ed)?|way|web)\.(to|com|org|is)\/(torrents\.php.*|catalog\/.*|s\/.*|tv\/.*|top10)$/ 10 | // @grant none 11 | // @require https://cdnjs.cloudflare.com/ajax/libs/arrive/2.4.1/arrive.min.js 12 | // @run-at document-idle 13 | // @supportURL https://github.com/darkred/Userscripts/issues 14 | // ==/UserScript== 15 | 16 | 17 | function appendColumn(elem) { 18 | 19 | const title = 'DL ML'; 20 | 21 | let entries = elem.querySelectorAll('.lista2t > tbody > tr > td:nth-child(2) '); // the initial column 'Files' after of which the extra column will be appended 22 | 23 | for (let i = 0; i < entries.length; i++) { // creation of the extra column 24 | entries[i].insertAdjacentHTML('afterend', `` + title + ``); 25 | } 26 | 27 | let header = elem.querySelector('.lista2t > tbody:nth-child(1) > tr:nth-child(1) > td:nth-child(3)'); // the first cell (the header cell) of the new column 28 | header.innerHTML = title; 29 | header.setAttribute('align', 'center'); 30 | header.setAttribute('class', 'header6'); 31 | 32 | let cells = elem.querySelectorAll('.lista2t > tbody > tr[class="lista2"] > td:nth-child(3)'); // the rest cells of the new column 33 | for (let i = 0; i < cells.length; i++) { 34 | cells[i].setAttribute('class', 'lista'); 35 | cells[i].setAttribute('width', '50px'); 36 | cells[i].setAttribute('align', 'center'); 37 | } 38 | 39 | let newColumn = elem.querySelectorAll('.lista2t > tbody > tr[class="lista2"] > td:nth-child(3)'); // new column 40 | let oldColumn = elem.querySelectorAll('.lista2t > tbody > tr[class="lista2"] > td:nth-child(2)'); // old column 41 | 42 | 43 | for (let i = 0; i < newColumn.length; i++) { 44 | 45 | let href = oldColumn[i].firstChild.href; 46 | 47 | newColumn[i].innerHTML = ''; 48 | newColumn[i].lastChild.title = 'DL via XHR'; 49 | 50 | newColumn[i].innerHTML += ' '; 51 | newColumn[i].lastChild.title = 'ML via XHR'; 52 | 53 | } 54 | } 55 | 56 | 57 | 58 | function addClickListeners(links, type){ 59 | 60 | for(let i = 0; i < links.length; i++) { 61 | 62 | links[i].addEventListener('click', function(event){ 63 | 64 | let href = this.getAttribute('href'); 65 | if (href === 'javascript:void(0)') { 66 | let tLink = this.getAttribute('data-href'); 67 | 68 | var xhr = new XMLHttpRequest(); 69 | xhr.open('GET', tLink, true); // XMLHttpRequest.open(method, url, async) 70 | xhr.onload = function () { 71 | 72 | let container = document.implementation.createHTMLDocument().documentElement; 73 | container.innerHTML = xhr.responseText; 74 | 75 | let retrievedLink; 76 | if (type === 'dl'){ 77 | retrievedLink = container.querySelector('a[href^="/download.php"]'); // the 'download link' element in the retrieved page 78 | } else { 79 | retrievedLink = container.querySelector('a[href^="magnet:"]'); // the 'magnet link' element in the retrieved page 80 | } 81 | 82 | 83 | if (retrievedLink) { 84 | links[i].setAttribute('href', retrievedLink.href); 85 | links[i].click(); 86 | } 87 | 88 | 89 | }; 90 | xhr.send(); 91 | 92 | } 93 | 94 | }, false); 95 | 96 | } 97 | 98 | } 99 | 100 | 101 | 102 | function createColumn(element){ 103 | appendColumn(element); 104 | addClickListeners(element.querySelectorAll('.xhrDownloadLink'), 'dl' ); 105 | addClickListeners(element.querySelectorAll('.xhrMagnetLink'), 'ml' ); 106 | } 107 | 108 | 109 | 110 | 111 | 112 | const isOnTV = window.location.href.includes('/tv/'); // example link: https://rarbgproxy.org/tv/tt1720601/ 113 | 114 | const tvEpisodes = 'div[id^="episode_"]'; 115 | const tvContent = 'div[id^="tvcontent_"] .lista2t'; 116 | 117 | if (isOnTV) { 118 | // var tvLinks = document.querySelectorAll('.tvshowClick'); 119 | var tvLinks = document.querySelectorAll(tvEpisodes); 120 | 121 | for (let i = 0; i < tvLinks.length; i++) { 122 | tvLinks[i].addEventListener('click', function handler(event) { // https://stackoverflow.com/questions/26617719/turn-off-event-listener-after-triggered-once 123 | 124 | var targetElement = ( event.target || event.srcElement ).closest(tvEpisodes); // https://stackoverflow.com/questions/11741070/js-how-to-get-the-element-clicked-on 125 | targetElement.arrive(tvContent, function() { 126 | // createColumn(targetElement.querySelector(tvContent)); 127 | createColumn(this); // 'this' refers to the newly created element 128 | targetElement.unbindArrive(tvContent); 129 | }); 130 | 131 | }); 132 | } 133 | } else { 134 | createColumn(document); // the initial column 'Files' after of which the extra column will be appended); 135 | } 136 | -------------------------------------------------------------------------------- /RARBG_-_torrent_and_magnet_links/README.md: -------------------------------------------------------------------------------- 1 | Adds a column with torrent and magnet links in RARBG lists: 2 | ![](https://i.imgur.com/JpNCgIe.jpg) 3 | 4 | Notes: 5 | - *(Initialy most of the ML links could be generated from the page itself ((i.e. from the filename of the thumbnail image that appeared when you mouseover on the torrent title, and that's because these filenames were the same as the relevant torrent hash)* ). Since 2/1/2019 that's no longer possible, due to the site's latest HTML changes). 6 | - So, from now on, the script generates all links via XHR: 7 | - The DL/ML links will have: 8 | - initially, as its destination (`href`) a: `javascript:void(0)` *(to avoid taking the user back to the top of the page, something that previously occured when I had a `#` as href, instead)*, 9 | - as tooltip: "`DL/ML via XHR`". 10 | - As you click a DL/ML icon, the relevant target page will be retrieved via XHR in the background (so, after clicking an icon, it will now have the magnet link). 11 | *(thanks to sxe [for the initial suggestion](https://greasyfork.org/en/forum/discussion/30691/x))*. 12 | - Since 4/27/2019 it uses the [arrive.js](https://github.com/uzairfarooq/arrive) library in order to work in TV Browser pages too. 13 | -------------------------------------------------------------------------------- /RARBG_-_various_tweaks/README.md: -------------------------------------------------------------------------------- 1 | This userscript applies mainly to RARBG torrent detail pages, e.g. `https://rarbgproxy.org/torrent/fmzeqtk`: it rearranges various entries, displays in bold the various rating values, renames a few entries more suitably and uses decimal rating for the users' ratings. 2 | Also, in torrent listings, the Recommended section now links to search by IMDb id (instead of each torrent page). 3 | Finally, in search-by-IMDb-id pages (e.g. https://rarbgproxy.org/torrents.php?imdb=tt0448115) , the `IMDb` in "IMDb Rating" becomes a link to relevant IMDb movie page and the IMDb plot summary is displayed. 4 | 5 | Notes: 6 | - The script makes use of the page's jQuery 1.11.3. 7 | - The `Size` row gets duplicated below the 'Torrent' row. 8 | - Regarding the `Rating` row: the five star rating is converted to ten star, both the stars themselves and the text value, but, if you hover the mouse over the stars to click to rate the movie, still only the first five stars are clickable, i.e. it's actually still five star rating. 9 | - The `Runtime` and `PG rating` rows info is appended to the end of the 'IMDb summary' row text (the 'Runtime' info is converted from: e.g. '118' to: 1h 58min). 10 | - The `Year` row becomes hidden because that info is still contained in various other rows ('Release Name', 'IMDb' link title, 'Title') 11 | - The `VPN` row *(not shown in the 'initial' screenshot)* becomes hidden because it's an ad. 12 | - Regarding the `Trailer` row: when using ad-blocking extensions, https://rarbgproxy.org/trailers.php is blocked by default via EasyList. So, in previous script versions the 'Trailer' row was getting hidden by the script. Since v2018.9.6.2 it's been restored (per https://greasyfork.org/en/forum/discussion/42158/x ) 13 | - The Recommended section (in torrent listings) would link to each torrent page. Now it links to search by IMDb id (per request: https://github.com/darkred/Userscripts/issues/8). 14 | - Also now, in search-by-IMDb-id pages (e.g. https://rarbgproxy.org/torrents.php?imdb=tt0448115) , the `IMDb` in "IMDb Rating" becomes a link to relevant IMDb movie page. Also, now, below it, the IMDb plot summary is displayed (retrieved from the relevant RARBG torrent page). 15 | 16 | Screenshot comparison: 17 | Initial: 18 | [![](https://i.imgur.com/T2pb0tHl.jpg)](https://i.imgur.com/T2pb0tH.jpg) 19 | 20 | With the script: 21 | [![](https://i.imgur.com/iBJt3Hwl.jpg)](https://i.imgur.com/iBJt3Hw.jpg) -------------------------------------------------------------------------------- /Reddit_Infinite_Scrolling/README.md: -------------------------------------------------------------------------------- 1 | This script adds infinite scrolling to subreddits and to comments. 2 | To Subreddits it does this while omitting the nav buttons as new page content is loaded. 3 | It also works for comments (in pages with a lot of comments, for example [this one](https://www.reddit.com/r/technology/comments/3h70d5/a_trail_of_evidence_leading_to_atts_partnership/)). 4 | 5 | It uses [jScroll](https://greasyfork.org/en/scripts/11636-jscroll) (a jQuery plugin) 6 | Official site: http://jscroll.com/ 7 | GitHub page: https://github.com/pklauzinski/jscroll 8 |
9 | Thanks a lot to jScroll's developer, Philip Klauzinski, 10 | for essentially making this script himself, ([the initial version](https://github.com/pklauzinski/jscroll/issues/58), i.e. for subreddits only), 11 | as well as wOxxOm for his help [here](https://greasyfork.org/en/forum/discussion/comment/16349#Comment_16349). -------------------------------------------------------------------------------- /Reddit_Infinite_Scrolling/Reddit_Infinite_Scrolling.user.js: -------------------------------------------------------------------------------- 1 | // ==UserScript== 2 | // @name Reddit Infinite Scrolling 3 | // @namespace darkred 4 | // @version 2018.4.25 5 | // @description Adds infinite scrolling to subreddits and to comments. 6 | // @author darkred 7 | // @license MIT 8 | // @include https://www.reddit.com/* 9 | // @include https://old.reddit.com/* 10 | // @grant unsafeWindow 11 | // @require http://code.jquery.com/jquery-2.1.4.min.js 12 | // @require https://cdnjs.cloudflare.com/ajax/libs/jscroll/2.4.1/jquery.jscroll.min.js 13 | // @supportURL https://github.com/darkred/Userscripts/issues 14 | // ==/UserScript== 15 | 16 | // Jscroll code 17 | $('#siteTable').jscroll({ 18 | nextSelector: 'span.nextprev a:last', 19 | contentSelector: '#siteTable .thing, .nav-buttons', 20 | callback: function() { 21 | $('.nav-buttons').remove(); 22 | } 23 | }); 24 | 25 | 26 | //if current URL contains the string 'comments', then click the 'more comments' button when scrolling at the end of the page 27 | if (/(.*comments.*)/.test(document.location)) { 28 | $(window).scroll(function() { 29 | if ($(window).scrollTop() + $(window).height() > $(document).height() - 100) { 30 | // console.log('bottom!'); 31 | var element = unsafeWindow.document.getElementsByClassName('morecomments'); 32 | var last = element.length; 33 | element[last - 1].firstChild.click(); 34 | } 35 | }); 36 | } -------------------------------------------------------------------------------- /Rotten_Tomatoes_Decimal_Rating/README.md: -------------------------------------------------------------------------------- 1 | *By default RottenTomatoes pages uses base 10 rating for TOMATOMETER and base-5 for AUDIENCE SCORE.* 2 | This script changes the latter's base-5 to base-10, and modifies both relevant tooltips, in order to be perceived more easily. 3 | It modifies the following 3 elements inside the modal that is displayed after clicking "See score details": 4 | 5 | - multiplies `x2` the Audience Rating **Avg Rating**, 6 | - appends `(=6 stars or higher)` to the Tomatometer **descriptive text**, 7 | - modifies`3.5 stars or higher` to `7 stars or higher`, in the Audience Score **descriptive text**. 8 | 9 |   10 | 11 | Thanks a lot to wOxxOm: he initially wrote it ([v1](https://greasyfork.org/en/forum/discussion/comment/5975/#Comment_5975) and he also offered improvements ([v2](http://stackoverflow.com/a/32413134/3231411), [v3](https://greasyfork.org/en/forum/discussion/7583/x) and v4). 12 | 13 | [Hosted in GitHub](https://github.com/darkred/Userscripts) 14 | -------------------------------------------------------------------------------- /Rotten_Tomatoes_Decimal_Rating/Rotten_Tomatoes_Decimal_Rating.user.js: -------------------------------------------------------------------------------- 1 | // ==UserScript== 2 | // @name Rotten Tomatoes Decimal Rating 3 | // @namespace darkred 4 | // @version 7 5 | // @date 2023.6.3 6 | // @description Changes base-5 Rating of Rotten Tomatoes to base-10 7 | // @author wOxxOm, darkred 8 | // @license MIT 9 | // @match https://*.rottentomatoes.com/* 10 | // @grant none 11 | // @supportURL https://github.com/darkred/Userscripts/issues 12 | // ==/UserScript== 13 | 14 | 15 | // Example URLs: 16 | // https://www.rottentomatoes.com/m/birds_of_prey_2020 17 | // https://www.rottentomatoes.com/m/toy_story_3 18 | 19 | 20 | 21 | function modifyaudienceScoreStars(audienceScoreStars){ 22 | if (!audienceScoreStars.textContent.includes('NaN') && audienceScoreStars.textContent.includes('out of 5') ) { 23 | audienceScoreStars.textContent = audienceScoreStars.textContent.replace('out of 5',''); 24 | audienceScoreStars.textContent *= 2; 25 | audienceScoreStars.textContent += ' out of 10'; 26 | } 27 | } 28 | 29 | 30 | function audienceScorex2(){ 31 | 32 | // 'Score Details' card | 'AUDIENCE' > average rating" score --> Multiply x2 33 | let audienceScoreStars = document.querySelector('score-details-audience').shadowRoot.querySelector('star-rating').shadowRoot.querySelector('.average-stars'); 34 | modifyaudienceScoreStars(audienceScoreStars); 35 | 36 | 37 | // Select the node that will be observed for mutations 38 | const targetNode = audienceScoreStars; 39 | 40 | // Options for the observer (which mutations to observe) 41 | const config = { // attributes: true , 42 | childList: true , 43 | // subtree: true, 44 | // characterData: true 45 | }; 46 | 47 | 48 | // Callback function to execute when mutations are observed 49 | const callback = mutations => { 50 | 51 | mutations.forEach(function(mutation) { 52 | 53 | observer.disconnect(); 54 | modifyaudienceScoreStars(audienceScoreStars); 55 | 56 | }); 57 | 58 | }; 59 | 60 | // Create an observer instance linked to the callback function 61 | const observer = new MutationObserver(callback); 62 | 63 | // Start observing the target node for configured mutations 64 | observer.observe(targetNode, config); 65 | 66 | } 67 | 68 | 69 | 70 | let scoreBoard = document.querySelector('score-board'); 71 | 72 | 73 | scoreBoard.onclick = function(event) { 74 | 75 | // let target = event.target; 76 | 77 | audienceScorex2(); 78 | 79 | let buttonVerifiedAudience = document.querySelector('#topSection > div.thumbnail-scoreboard-wrap > overlay-base > score-details > score-details-audience > filter-chip:nth-child(2)'); 80 | let buttonAllAudience = document.querySelector('#topSection > div.thumbnail-scoreboard-wrap > overlay-base > score-details > score-details-audience > filter-chip:nth-child(3)'); 81 | [ buttonVerifiedAudience, buttonAllAudience ].forEach(function(element) { 82 | if (element) { 83 | element.addEventListener('click', function() { 84 | audienceScorex2(); 85 | }); 86 | } 87 | }); 88 | 89 | 90 | 91 | // the '?' buttons for the two descriptive texts 92 | let buttonQuestionmarkTomatometer = document.querySelector('#topSection > div.thumbnail-scoreboard-wrap > overlay-base > score-details > score-details-critics > tool-tip'); 93 | let buttonQuestionmarkAudienceScore = document.querySelector('#topSection > div.thumbnail-scoreboard-wrap > overlay-base > score-details > score-details-audience > tool-tip'); 94 | 95 | 96 | buttonQuestionmarkTomatometer.addEventListener('click', function(){ 97 | 98 | let descriptiveTextTomatometer = document.querySelector('#topSection > div.thumbnail-scoreboard-wrap > overlay-base > score-details > score-details-critics > tool-tip').shadowRoot.querySelector('.description'); 99 | if (!descriptiveTextTomatometer.textContent.includes('review (6 stars or higher)')) { 100 | descriptiveTextTomatometer.innerHTML = descriptiveTextTomatometer.innerHTML.replace('review', 'review (6 stars or higher)'); 101 | } 102 | 103 | }); 104 | 105 | 106 | buttonQuestionmarkAudienceScore.addEventListener('click', function(){ 107 | 108 | // There are now two occurrences of '3.5 stars or higher' in the AUDIENCE descriptive text overlay, hence the querySelectorAll() 109 | let descriptiveTextAudienceScode = document.querySelector('#topSection > div.thumbnail-scoreboard-wrap > overlay-base > score-details > score-details-audience > tool-tip').shadowRoot.querySelectorAll('.description'); 110 | /* 111 | descriptiveTextAudienceScode.innerHTML = descriptiveTextAudienceScode.innerHTML.replace(/([\d.]+)( stars)/g, function (m, s1, s2) { 112 | return 2 * s1 + s2; 113 | }); 114 | */ 115 | descriptiveTextAudienceScode.forEach((el) => { 116 | if (!el.textContent.includes('7 stars or higher')) { 117 | el.innerHTML = el.innerHTML.replace('3.5 stars or higher', '7 stars or higher'); 118 | } 119 | }); 120 | 121 | }); 122 | 123 | 124 | }; 125 | -------------------------------------------------------------------------------- /StackExchange_sites_-_convert_dates_to_local_timezone/README.md: -------------------------------------------------------------------------------- 1 | This script applies to StackExchange sites stackoverflow.com, stackexchange.com, superuser.com, etc. 2 | The timezone that the StackExchange sites use is UTC i.e. +0000 ([source](http://meta.stackexchange.com/questions/2941/why-are-the-time-stamps-in-utc-instead-of-localized-for-the-client)) 3 | So, this script converts the dates to your local timezone, in both: 4 | - tooltips `2015-12-14 14:11:13Z`, and in 5 | - date text like `Dec 14 at 14:11`. 6 | 7 | *It also recalculates them whenever the page changes.* 8 | 9 |
10 | *It uses the [jsTimezoneDetect](https://bitbucket.org/pellepim/jstimezonedetect) JavaScript script (for getting the local timezone), 11 | and the [Moment.js](http://momentjs.com/) and [Moment-Timezone](http://momentjs.com/timezone/) JavaScript libraries (for converting the dates). 12 | Also note: `jsTimezoneDetect` does not do geo-location, nor does it care very much about historical time zones. 13 | e.g. it may get "Europe/Berlin" when the user is in fact in "Europe/Stockholm" (they are both identical in modern time). 14 | 15 | 16 | Known issues: 17 | 1. While you are on the superuser.com homepage, every 1 minute the activity indicator which will show when new posts are asked or answered. 18 | Also, every relative timestamp, e.g. `answered 1 min ago` will become `answered 2 min ago`, and so on. 19 | Well, while using the script, the latter feature, i.e. "*the relative timestamps being increased every 1 min*" becomes broken, and they don't get updated anymore. 20 | 2. if you reopen Firefox e.g. stackexchange.com, then session restore uses the timestamps for the tooltips from cache, so the script uses these cached values (refreshing the page (F5) fixes the issue).* 21 | 22 | 23 | Relative post I made in stackapps.com 24 | [Here's a script to convert dates to local timezone in Stack Exchange sites](http://stackapps.com/questions/6711/heres-a-script-to-convert-dates-to-local-timezone-in-stack-exchange-sites) -------------------------------------------------------------------------------- /StackExchange_sites_-_convert_dates_to_local_timezone/StackExchange_sites_-_convert_dates_to_local_timezone.user.js: -------------------------------------------------------------------------------- 1 | // ==UserScript== 2 | // @name StackExchange sites - convert dates to local timezone 3 | // @namespace darkred 4 | // @version 2019.8.28 5 | // @description Converts dates to your local timezone 6 | // @author darkred 7 | // @license MIT 8 | // @include /^(https?:)?\/\/(www\.)?((3dprinting|academia|ai|alcohol|android|anime|apple|arduino|astronomy|aviation|bicycles|bioinformatics|biology|bitcoin|blender|boardgames|bricks|buddhism|chemistry|chess|chinese|christianity|civicrm|codegolf|codereview|coffee|communitybuilding|computergraphics|conlang|cooking|craftcms|crafts|crypto|cs|cseducators|cstheory|datascience|dba|devops|diy|drupal|dsp|earthscience|ebooks|economics|electronics|elementaryos|ell|emacs|engineering|english|eosio|esperanto|ethereum|expatriates|expressionengine|fitness|freelancing|french|gamedev|gaming|gardening|genealogy|german|gis|graphicdesign|ham|hardwarerecs|hermeneutics|hinduism|history|homebrew|hsm|interpersonal|iot|iota|islam|italian|japanese|joomla|judaism|korean|languagelearning|latin|law|lifehacks|linguistics|literature|magento|martialarts|math|matheducators|mathematica|mechanics|medicalsciences|meta|monero|money|movies|music|musicfans|mythology|networkengineering|opendata|opensource|or|outdoors|parenting|patents|pets|philosophy|photo|physics|pm|poker|politics|portuguese|psychology|puzzling|quant|quantumcomputing|raspberrypi|retrocomputing|reverseengineering|robotics|rpg|rus|russian|salesforce|scicomp|scifi|security|sharepoint|sitecore|skeptics|softwareengineering|softwarerecs|sound|space|spanish|sports|sqa|stats|stellar|sustainability|tex|tezos|tor|travel|tridion|ukrainian|unix|ux|vegetarianism|vi|video|webapps|webmasters|windowsphone|woodworking|wordpress|workplace|worldbuilding|writing)\.stackexchange\.com|(es|ja|pt|ru)\.stackoverflow\.com|(askubuntu|serverfault|stackapps|stackoverflow|superuser)\.com|mathoverflow\.net).*$/ 9 | // @grant none 10 | // @require https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.24.0/moment.min.js 11 | // @require https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.26/moment-timezone-with-data.min.js 12 | // @require https://cdnjs.cloudflare.com/ajax/libs/jstimezonedetect/1.0.6/jstz.min.js 13 | // @supportURL https://github.com/darkred/Userscripts/issues 14 | // ==/UserScript== 15 | 16 | /* eslint-disable quotes, no-console */ 17 | /* global jstz, moment */ 18 | 19 | 20 | var localTimezone = jstz.determine().name(); 21 | var serverTimezone = 'Europe/Berlin'; // GMT+1 22 | 23 | function convertDates(dates) { 24 | // var dates = document.querySelectorAll('.relativetime, .rep-time'); 25 | var temp, temp2; 26 | for (var i = 0; i < dates.length; i++) { 27 | 28 | // 2019-08-24 03:26:50Z 29 | temp = moment(dates[i].title, 'YYYY-MM-DD HH:mm:ssZ', true); 30 | if (temp.isValid()) { 31 | dates[i].title = moment.tz(dates[i].title, serverTimezone).tz(localTimezone); 32 | } 33 | 34 | // Example URLS: 35 | // older, but of the same year: https://stackoverflow.com/questions?tab=newest&page=1200 36 | // older, of previous years: https://stackoverflow.com/questions?tab=newest&page=120000 37 | // Example timestamps: 38 | // Aug 7 at 6:45 39 | // Aug 24 at 12:23 40 | // Oct 24 '18 at 9:56 41 | // Oct 24 '18 at 13:57 42 | temp2 = dates[i].innerHTML.replace('at ', '').replace('\'', '') + ' Z'; 43 | 44 | var formatNoYear = 'MMM D H:mm Z'; 45 | var formatWithYear = 'MMM D YY H:mm Z'; 46 | 47 | var newMoment1 = moment(temp2, formatNoYear, true); 48 | var newMoment2 = moment(temp2, formatWithYear, true); 49 | 50 | if (newMoment1.isValid()){ 51 | dates[i].innerHTML = moment.tz(newMoment1, serverTimezone).tz(localTimezone).format('MMM D [at] H:mm'); 52 | } else if (newMoment2.isValid()){ 53 | dates[i].innerHTML = moment.tz(newMoment2, serverTimezone).tz(localTimezone).format("MMM D [']YY [at] H:mm"); 54 | } 55 | } 56 | } 57 | 58 | 59 | var dates = document.querySelectorAll('.relativetime, .rep-time'); 60 | convertDates(dates); 61 | 62 | 63 | // The part below is pointless to enable because the site's built-in feature that "the relative timestamps being increased every 1 min" becomes broken when this script is running 64 | /* 65 | // recalculate the relative times every 10 sec 66 | (function(){ 67 | convertDates(dates); 68 | setTimeout(arguments.callee, 1 * 60 * 1000); 69 | })(); 70 | */ 71 | 72 | 73 | var target = document.querySelectorAll('#question-mini-list, #questions, .rep-breakdown')[0], 74 | observer = new MutationObserver(function (mutations) { 75 | convertDates(); 76 | }), 77 | config = { 78 | characterData: true, 79 | subtree: true 80 | }; 81 | observer.observe(target, config); 82 | -------------------------------------------------------------------------------- /SunXDCC_-_normalize_values/README.md: -------------------------------------------------------------------------------- 1 | This script applies to https://sunxdcc.com 2 | 3 | It converts the values: 4 | - in the 'Record' column from `B/s` to `kB/s`, 5 | - in the 'Size' column from e.g. `G` to `GB`, 6 | 7 | and adds a space between the value and the unit, in both cases. 8 |
9 | 10 | _This userscript uses the JavaScript library [Mutation Summary](https://github.com/rafaelw/mutation-summary) (by Rafael Weinstein)._ -------------------------------------------------------------------------------- /SunXDCC_-_normalize_values/SunXDCC_-_normalize_values.user.js: -------------------------------------------------------------------------------- 1 | // ==UserScript== 2 | // @name SunXDCC - normalize values 3 | // @namespace darkred 4 | // @version 2018.2.27 5 | // @description It converts the values: in the 'Record' column from B/s to kB/s, and in the 'Size' column from e.g. G to GB. Also adds a space between the value and the unit, in both cases. 6 | // @author darkred 7 | // @license MIT 8 | // @include /^https?:\/\/(www\.)?sunxdcc\.com.*/ 9 | // @grant none 10 | // @require https://greasyfork.org/scripts/12036-mutation-summary/code/Mutation%20Summary.js 11 | // @supportURL https://github.com/darkred/Userscripts/issues 12 | // ==/UserScript== 13 | 14 | /* global MutationSummary */ 15 | 16 | function normalizeValues(){ 17 | 18 | var records = document.querySelectorAll('.record.val'); 19 | for (var i = 0; i < records.length; i++) { 20 | if (records[i].innerText !== 'Na'){ 21 | var initial = records[i].innerText; 22 | var temp = parseInt(records[i].innerText.replace('kB/s', '')) / 1000; 23 | // temp = Math.round(100 * temp) / 100; // round to 2 decimal places 24 | temp = Math.round(10 * temp) / 10; // round to 1 decimal place 25 | records[i].innerText = temp + 'mB/s'; 26 | records[i].title = initial; 27 | 28 | var len = records[i].innerText.length; 29 | records[i].innerText = records[i].innerText.substring(0, len-4) + ' ' + records[i].innerText.substring(len-4); 30 | } 31 | 32 | } 33 | 34 | 35 | var sizes = document.querySelectorAll('.fsize.val'); 36 | for (let i = 0; i < sizes.length; i++) { 37 | // var initial = sizes[i].innerText; 38 | // var temp 39 | sizes[i].innerText += 'B'; 40 | // http://stackoverflow.com/questions/5869551/insert-before-last-2-char-in-javascript 41 | let len = sizes[i].innerText.length; 42 | sizes[i].innerText = sizes[i].innerText.substring(0, len-2) + ' ' + sizes[i].innerText.substring(len-2); 43 | } 44 | } 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | new MutationSummary({ 53 | callback: normalizeValues, 54 | rootNode: document.querySelector('#content'), 55 | queries: [{ element: '.table' }], 56 | // queries: [{ element: '.results > .table:first-child' }], 57 | }); -------------------------------------------------------------------------------- /Twitter_-_add_unread_notifications_count_in_the_tab_title/README.md: -------------------------------------------------------------------------------- 1 | This script adds unread notifications count in the tab title in Twitter. 2 | eg. (in timeline) instead of 3 | `(1) Twitter`, it becomes 4 | `3 | (1) Twitter` 5 | where 3 is the unread notifications count and (1) the default unread tweets count. 6 | 7 | Since v3 using the excellent library [arrive.js](https://github.com/uzairfarooq/arrive) 8 | 9 | Thanks a lot to wOxxOm for his valuable help in [here](https://greasyfork.org/en/forum/discussion/3765/twitter-to-include-the-unread-notifications-count-in-the-tab-title). -------------------------------------------------------------------------------- /Twitter_-_add_unread_notifications_count_in_the_tab_title/Twitter_-_add_unread_notifications_count_in_the_tab_title.user.js: -------------------------------------------------------------------------------- 1 | // ==UserScript== 2 | // @name Twitter - add unread notifications count in the tab title 3 | // @namespace darkred 4 | // @version 2018.2.27 5 | // @description Adds unread notifications count in the tab title 6 | // @author darkred 7 | // @license MIT 8 | // @include https://twitter.com/* 9 | // @grant none 10 | // @require https://greasyfork.org/scripts/21927-arrive-js/code/arrivejs.js 11 | // @supportURL https://github.com/darkred/Userscripts/issues 12 | // ==/UserScript== 13 | 14 | 15 | 16 | // .count > .count-inner 17 | // Notifications counter 18 | 19 | // .dm-new > .count-inner 20 | // DM counter 21 | 22 | 23 | var notificationsCounter; 24 | 25 | function addCounterInTitle() { 26 | // alert(0); 27 | // counter = parseInt(document.querySelector('.count-inner').innerHTML); // the Notifications counter value 28 | notificationsCounter = parseInt(document.querySelector('.count > .count-inner').innerHTML); // the Notifications counter value 29 | // if (counter > 0 && document.title.indexOf('|') > 3) { // if the '|' symbol is the default separator of username and 'Twitter' when viewing profiles, e.g.: Twitter Support (@Support) | Twitter. In here the position of `|` is 27. 30 | if (notificationsCounter > 0) { // if the '|' symbol is the default separator of username and 'Twitter' when viewing profiles, e.g.: Twitter Support (@Support) | Twitter. In here the position of `|` is 27. 31 | if (/[0-9]+\ \|\ .*/.test(document.title)){ // if our counter is already added to title 32 | var defaultTitle = document.title.match(/[0-9]+\ \|\ (.*)/)[1]; 33 | document.title = notificationsCounter + ' | ' + defaultTitle; 34 | return; 35 | } else { 36 | document.title = notificationsCounter + ' | ' + document.title; // add the counter to the title 37 | return; 38 | } 39 | } else if (notificationsCounter === 0) { 40 | document.title = /[0-9]+\ \|\ (.*)/g.exec(document.title)[1]; // remove title's added counter 41 | } 42 | } 43 | 44 | 45 | 46 | // After the 'Notifications' counter is first visible in the page (= the selector below is for the element: 'the 1st avatar thumbnail in the "Who to follow" panel') 47 | document.arrive('div.js-account-summary:nth-child(1) > div:nth-child(2) > a:nth-child(1) > img:nth-child(1)', function () { 48 | addCounterInTitle(); 49 | }); 50 | 51 | 52 | 53 | // Whenever there are new unread tweets in the timeline.. 54 | document.arrive('.new-tweets-bar', function () { 55 | var target = document.querySelector('.new-tweets-bar'); // ..οbserve the unread counter for changes(increase) 56 | var observer = new MutationObserver(function (mutations) { 57 | addCounterInTitle(); // Refresh the counter on every such change 58 | }); 59 | var config = { 60 | childList: true, 61 | }; 62 | observer.observe(target, config); 63 | }); 64 | 65 | 66 | 67 | // Refresh the counter when there are no unread tweets 68 | document.leave('.new-tweets-bar', function () { 69 | addCounterInTitle(); 70 | }); 71 | 72 | 73 | 74 | // Whenever viewing the 'Notifications' tab 75 | document.arrive('.NotificationsHeadingContent', function () { 76 | // document.querySelector('.count-inner').innerHTML = 0; // ..reset the counter.. 77 | document.querySelector('.count > .count-inner').innerHTML = 0; // ..reset the counter.. 78 | notificationsCounter = 0; 79 | document.title = document.title.match(/[0-9]+\ \|\ (.*)/)[1]; // ..and the tab title 80 | }); 81 | 82 | 83 | 84 | // Observe the 'Notifications' counter for changes 85 | var target2 = document.querySelector('.count-inner'); 86 | var observer2 = new MutationObserver(function (mutations) { 87 | addCounterInTitle(); 88 | }); 89 | var config2 = { 90 | childList: true, 91 | }; 92 | observer2.observe(target2, config2); 93 | 94 | 95 | 96 | 97 | 98 | 99 | function resetCounter(){ 100 | // document.querySelector('.new-count').className = 'count'; 101 | notificationsCounter = 0; 102 | document.querySelector('.count-inner').innerHTML = ''; 103 | document.title = /[0-9]+\ \|\ (.*)/g.exec(document.title)[1]; 104 | } 105 | 106 | /// A "click" event listener attached on the "Notifications" button: 107 | // if the user clicks, rightclicks or middle-clicks the button, then reset the counter and the tab title. 108 | var target3 = document.querySelector('.people'); 109 | target3.addEventListener('mousedown', resetCounter, false); 110 | -------------------------------------------------------------------------------- /Userstyles_-_filter_deleted_styles_in_your_profile/README.md: -------------------------------------------------------------------------------- 1 | This script applies in your profile view in userstyles.org (provided that you have login). 2 | It's meant for those who have also uploaded styles that they have deleted: 3 | By default it shows only the active styles - optionally you may display only the deleted styles or both. 4 | 5 | It adds these 3 links/buttons on top right. For example: 6 | ![image](https://i.imgur.com/4W4K8F4.jpg) -------------------------------------------------------------------------------- /Userstyles_-_filter_deleted_styles_in_your_profile/Userstyles_-_filter_deleted_styles_in_your_profile.user.js: -------------------------------------------------------------------------------- 1 | // ==UserScript== 2 | // @name Userstyles - filter deleted styles in your profile 3 | // @namespace darkred 4 | // @version 1 5 | // @description Filters deleted styles in your profile in userstyles.org 6 | // @author darkred 7 | // @license MIT 8 | // @include /^https:\/\/userstyles.org\/users\/[0-9]*/ 9 | // @grant none 10 | // @supportURL https://github.com/darkred/Userscripts/issues 11 | // ==/UserScript== 12 | 13 | 14 | if (document.querySelector('#main-article > ul:nth-child(1) > li:nth-child(1) > a:nth-child(1)')) { // if in your own profile 15 | 16 | var all = document.querySelectorAll('tr').length - 1; 17 | var deleted = document.querySelectorAll('.obsolete').length; 18 | var scripts = all - deleted; 19 | 20 | 21 | var parentElement = document.querySelector('#left-sidebar'); 22 | 23 | var theFirstChild = parentElement.firstChild; 24 | 25 | var div = document.createElement('div'); 26 | parentElement.insertBefore(div, theFirstChild); 27 | 28 | 29 | div.style.position = 'fixed'; 30 | div.style.background = 'white'; 31 | 32 | div.style.top = '210px'; 33 | div.style.right = '257px'; 34 | 35 | 36 | 37 | 38 | 39 | var a = document.createElement('a'); 40 | div.appendChild(a); 41 | a.innerHTML = '' + 'All: ' + '' + '' + all + '' + '
'; 42 | a.onclick = toggleAll; 43 | 44 | 45 | var b = document.createElement('a'); 46 | div.appendChild(b); 47 | b.innerHTML = '' + 'Active: ' + '' + '' + scripts + '' + '
'; 48 | b.onclick = toggleScripts; 49 | 50 | 51 | var c = document.createElement('a'); 52 | div.appendChild(c); 53 | c.innerHTML = '' + 'Deleted: ' + '' + '' + deleted + '' + '
'; 54 | c.onclick = toggledeleted; 55 | 56 | 57 | b.click(); 58 | 59 | 60 | 61 | } 62 | 63 | 64 | 65 | function toggleAll(){ 66 | a.style.fontWeight = 'bold'; b.style.fontWeight = 'normal'; c.style.fontWeight = 'normal'; 67 | $('tr').show(); 68 | $('.obsolete').parent().show(); 69 | } 70 | 71 | 72 | function toggleScripts(){ 73 | a.style.fontWeight = 'normal'; b.style.fontWeight = 'bold'; c.style.fontWeight = 'normal'; 74 | $('tr').show(); 75 | $('.obsolete').parent().hide(); // Initially hide the obsolete userstyles 76 | } 77 | 78 | 79 | function toggledeleted(){ 80 | a.style.fontWeight = 'normal'; b.style.fontWeight = 'normal'; c.style.fontWeight = 'bold'; 81 | $('tr').show(); 82 | $('tr').not($('tr .obsolete').parent()).not($('tr:first')).hide(); 83 | 84 | 85 | } 86 | -------------------------------------------------------------------------------- /Userstyles_Bullshit_Filter/README.md: -------------------------------------------------------------------------------- 1 | Hides styles for popular browser games and social networks, styles that use "foreign" characters in descriptions as well as styles that have no screenshots, when browsing or searching styles. 2 | i.e. it filters any/all of these 5 categories: 3 | * **Games**: styles for browser games like Kingdoms of Camelot, Mafia Wars and Ikariam 4 | * **Social Networks**: styles for general purpose social networking sites like Facebook, studiVZ and VKontakte 5 | * **Non-ASCII**: styles that use non-English characters in description (accents, umlauts, cyrillic letters, ...) 6 | * **Clutter**: obvious spam, titles like "asdasdasd", description = title, title < 6 characters, "just a test". 7 | * **No screenshot**: styles that have no screenshots. 8 | 9 | The filters list appears just below the `#sidebar-forum` element (i.e. on the left). 10 | ![image](https://i.imgur.com/1wTYLK7.jpg) 11 | 12 | *Note: you may uncomment line 42 (and comment out line 43), in order the filtered styles to be highlighted khaki -instead of hiding them- so that you can check which styles have been filtered.* 13 | 14 | This is a modified version of this script: [userscripts.org Bullshit Filter](http://userscripts-mirror.org/scripts/show/97145) (by kuehlschrank). 15 | Thanks a lot to kuehlschrank for making another great script. -------------------------------------------------------------------------------- /Userstyles_Bullshit_Filter/Userstyles_Bullshit_Filter.user.js: -------------------------------------------------------------------------------- 1 | // ==UserScript== 2 | // @name Userstyles Bullshit Filter 3 | // @namespace darkred 4 | // @version 1.1 5 | // @description Hides styles for popular browser games and social networks, styles that use "foreign" characters in descriptions as well as styles that have no screenshots. 6 | // @author kuehlschrank, darkred 7 | // @license MIT 8 | // @include https://userstyles.org/styles/browse* 9 | // @grant GM_addStyle 10 | // @grant GM_setValue 11 | // @grant GM_getValue 12 | // @icon https://s3.amazonaws.com/uso_ss/icon/97145/large.png 13 | // This is an edited version of this script (http://userscripts-mirror.org/scripts/show/97145) by kuehlschrank. 14 | // Thanks a lot to kuehlschrank for making another great script. 15 | // @supportURL https://github.com/darkred/Userscripts/issues 16 | // ==/UserScript== 17 | 18 | // GM_addStyle("body { color: white; background-color: black; } img { border: 0; }"); 19 | 20 | // GM_addStyle('.filter-status, .filter-switches {position: fixed !important}'); 21 | // GM_addStyle('.filter-status {top: 314px !important; left: 460px !important;}'); 22 | // GM_addStyle('.filter-switches {top: 350 !important; left: 460px !important;}'); 23 | 24 | 25 | (function() { 26 | var filters = { 27 | 'Games': /AntiGame|Agar|agar.io|ExtencionRipXChetoMalo|AposBot|DFxLite|ZTx-Lite|AposFeedingBot|AposLoader|Blah Blah|Orc Clan Script|Astro\s*Empires|^\s*Attack|^\s*Battle|BiteFight|Blood\s*Wars|Bots|Bots4|Brawler|\bBvS\b|Business\s*Tycoon|Castle\s*Age|City\s*Ville|Comunio|Conquer\s*Club|CosmoPulse|Dark\s*Orbit|Dead\s*Frontier|Diep\.io|\bDOA\b|Dossergame|Dragons\s*of\s*Atlantis|Dugout|\bDS[a-z]+\n|Empire\s*Board|eRep(ublik)?|Epic.*War|ExoPlanet|Falcon Tools|Feuerwache|Farming|FarmVille|Fightinfo|Frontier\s*Ville|Ghost\s*Trapper|Gladiatus|Goalline|Gondal|Grepolis|Hobopolis|\bhwm(\b|_)|Ikariam|\bIT2\b|Jellyneo|Kapi\s*Hospital|Kings\s*Age|Kingdoms?\s*of|knastv(ö|oe)gel|Knight\s*Fight|\b(Power)?KoC(Atta?ck)?\b|\bKOL\b|Kongregate|Last\s*Emperor|Legends?\s*of|Light\s*Rising|Lockerz|\bLoU\b|Mafia\s*(Wars|Mofo)|Menelgame|Mob\s*Wars|Mouse\s*Hunt|Molehill\s*Empire|NeoQuest|MyFreeFarm|Neopets|Nemexia|\bOGame\b|Ogar(io)?|Pardus|Pennergame|Pigskin\s*Empire|PlayerScripts|Popmundo|Po?we?r\s*(Bot|Tools)|PsicoTSI|Ravenwood|Schulterglatze|slither\.io|SpaceWars|\bSW_[a-z]+\n|\bSnP\b|The\s*Crims|The\s*West|Travian|Treasure\s*Isl(and|e)|Tribal\s*Wars|TW.?PRO|Vampire\s*Wars|War\s*of\s*Ninja|West\s*Wars|\bWoD\b|World\s*of\s*Dungeons|wtf\s*battles|Wurzelimperium/i, 28 | 'Social Networks': /Face\s*book|Google(\+| Plus)|\bHabbo|Kaskus|\bLepra|Leprosorium|MySpace|meinVZ|odnoklassniki|Одноклассники|Orkut|sch(ue|ü)ler(VZ|\.cc)?|studiVZ|Unfriend|Valenth|VK|vkontakte|ВКонтакте|Qzone|Twitter|TweetDeck/i, 29 | 'Non-ASCII': /[^\x00-\x7F\s]+/i, 30 | 'Clutter': /^\s*(.{1,3})\1+\n|^\s*(.+?)\n+\2\n*$|^\s*.{1,5}\n|do\s*n('|o)?t (install|download)|nicht installieren|just(\s*a)?\s*test|^\s*.{0,4}test.{0,4}\n|\ntest(ing)?\s*|^\s*(\{@|Smolka|Hacks)|\[\d{4,5}\]|free\s*download/i, 31 | 'No screenshot': /^\(No\ screenshot\ available\)/i 32 | }; 33 | if (typeof GM_getValue == 'undefined' || (typeof GM_getValue.toString == 'function' && GM_getValue.toString().indexOf('not supported') > -1)) { 34 | GM_getValue = my_GM_getValue; 35 | GM_setValue = my_GM_setValue; 36 | } 37 | insertStyle(); 38 | insertStatus(); 39 | filterScripts(); 40 | insertSwitches(); 41 | 42 | // Note: you may uncomment line 42 (and comment out line 43), in order the filtered styles to be highlighted khaki -instead of hiding them- so that you can check which styles have been filtered 43 | function insertStyle() { 44 | var style = document.createElement('style'); 45 | // style.textContent = 'article#filtered { background-color:DarkKhaki; !important; } .filter-status { margin-left: 6px; } .filter-switches { display:none; } *:hover > .filter-switches { display:block !important; } .filter-on, .filter-off {display:block !important; width: 105px;} .filter-switches a { text-decoration:none !important; color:inherit; cursor:pointer; } .filter-switches a { margin-left: 8px; padding: 0 4px; } a.filter-on { background-color:#ffcccc; color:#333333; text-decoration:line-through !important } a.filter-off { background-color:#ccffcc; color:#333333 } '; 46 | style.textContent = 'article#filtered { display:none !important; } .filter-status { margin-left: 6px; } .filter-switches { display:none; } *:hover > .filter-switches { display:block !important; } .filter-on, .filter-off {display:block !important; width: 105px;} .filter-switches a { text-decoration:none !important; color:inherit; cursor:pointer; } .filter-switches a { margin-left: 8px; padding: 0 4px; } a.filter-on { background-color:#ffcccc; color:#333333; text-decoration:line-through !important } a.filter-off { background-color:#ccffcc; color:#333333 } '; 47 | style.type = 'text/css'; 48 | document.querySelector('head').appendChild(style); 49 | } 50 | 51 | function insertStatus() { 52 | var p = document.querySelector('#left-sidebar'); 53 | if (p) { 54 | var status = document.createElement('span'); 55 | status.className = 'filter-status'; 56 | p.appendChild(status); 57 | } 58 | } 59 | 60 | function filterScripts() { 61 | var activeFilters = []; 62 | for (var filter in filters) { 63 | if (filters.hasOwnProperty(filter) && GM_getValue(filter, 'on') == 'on') { 64 | activeFilters.push(filters[filter]); 65 | } 66 | } 67 | var nodes = document.querySelectorAll('article .style-brief'), 68 | numActiveFilters = activeFilters.length, 69 | numFiltered = 0; 70 | for (var i = 0, numNodes = nodes.length, td = null; i < numNodes && (td = nodes[i]); i++) { 71 | td.id = ''; 72 | for (var j = 0; j < numActiveFilters; j++) { 73 | var temp = td.innerText.replace(/[\s]*Updated[\s\S]*/, ''); 74 | if (temp.match(activeFilters[j])) { 75 | td.id = 'filtered'; 76 | numFiltered++; 77 | break; 78 | } 79 | } 80 | } 81 | document.querySelector('.filter-status').textContent = document.querySelectorAll('article .style-brief').length - numFiltered + ' styles (' + numFiltered + ' filtered)'; 82 | } 83 | 84 | function insertSwitches() { 85 | var span = document.createElement('span'); 86 | span.className = 'filter-switches'; 87 | for (var filter in filters) { 88 | if (filters.hasOwnProperty(filter)) { 89 | span.appendChild(createSwitch(filter, GM_getValue(filter, 'on') == 'on')); 90 | } 91 | } 92 | document.querySelector('.filter-status').parentNode.appendChild(span); 93 | } 94 | 95 | function createSwitch(label, isOn) { 96 | var a = document.createElement('a'); 97 | a.className = isOn ? 'filter-on' : 'filter-off'; 98 | a.textContent = label; 99 | a.addEventListener('click', function(e) { 100 | if (this.className == 'filter-on') { 101 | this.className = 'filter-off'; 102 | GM_setValue(this.textContent, 'off'); 103 | } else { 104 | this.className = 'filter-on'; 105 | GM_setValue(this.textContent, 'on'); 106 | } 107 | filterScripts(); 108 | e.preventDefault(); 109 | }, false); 110 | return a; 111 | } 112 | 113 | function my_GM_setValue(name, value) { 114 | localStorage.setItem(name, value); 115 | } 116 | 117 | function my_GM_getValue(name, defaultValue) { 118 | var value; 119 | if (!(value = localStorage.getItem(name))) { 120 | return defaultValue; 121 | } 122 | return value; 123 | } 124 | })(); 125 | -------------------------------------------------------------------------------- /Userstyles_Bullshit_Filter/large.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darkred/Userscripts/5137627e96d6e06cb0d13cc6ebdc5f4f9917cb0a/Userstyles_Bullshit_Filter/large.png -------------------------------------------------------------------------------- /eslint.config.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable @stylistic/js/quotes */ 2 | /* eslint-disable @stylistic/js/indent */ 3 | 4 | // import * as cssPlugin from "eslint-plugin-css"; 5 | import css from "@eslint/css"; 6 | import eslintPluginJsonc from 'eslint-plugin-jsonc'; 7 | import json from "@eslint/json"; 8 | import noJquery from "eslint-plugin-no-jquery"; 9 | import * as regexpPlugin from "eslint-plugin-regexp"; 10 | import markdown from "@eslint/markdown"; 11 | import globals from "globals"; 12 | import js from "@eslint/js"; 13 | import stylisticJs from "@stylistic/eslint-plugin-js"; 14 | 15 | 16 | export default [ 17 | { 18 | files: ['**/*.js', '**/*.mjs'], 19 | ...js.configs.recommended 20 | }, 21 | // cssPlugin.configs["flat/recommended"], 22 | ...eslintPluginJsonc.configs['flat/recommended-with-jsonc'], 23 | { 24 | files: ['**/*.js', '**/*.mjs'], 25 | ...regexpPlugin.configs["flat/recommended"], 26 | }, 27 | ...markdown.configs.recommended, 28 | { 29 | files: ["**/*.js"], 30 | ignores: ["**/*.min.js"], 31 | 32 | plugins: { 33 | "@stylistic/js": stylisticJs 34 | }, 35 | 36 | linterOptions: { 37 | reportUnusedDisableDirectives: true, 38 | }, 39 | 40 | languageOptions: { 41 | globals: { 42 | ...globals.browser, 43 | ...globals.greasemonkey, 44 | ...globals.jquery, 45 | }, 46 | 47 | ecmaVersion: "latest", 48 | sourceType: "module", 49 | 50 | 51 | parserOptions: { 52 | ecmaFeatures: { 53 | "globalReturn ": true, 54 | impliedStrict: true, 55 | }, 56 | }, 57 | }, 58 | 59 | rules: { 60 | complexity: ["warn", 20], 61 | eqeqeq: "warn", 62 | "func-style": "off", 63 | 64 | "@stylistic/js/indent": ["warn", "tab", { 65 | ignoreComments: false, 66 | SwitchCase: 1, 67 | }], 68 | 69 | "@stylistic/js/linebreak-style": ["warn", "unix"], 70 | "@stylistic/js/max-len": "off", 71 | "@stylistic/js/max-statements-per-line": "off", 72 | "new-cap": "off", 73 | "no-alert": "warn", 74 | "no-console": "warn", 75 | "no-dupe-keys": "warn", 76 | "@stylistic/js/no-extra-semi": "warn", 77 | "no-inline-comments": "off", 78 | "no-magic-numbers": "off", 79 | "no-misleading-character-class": "warn", 80 | "@stylistic/js/no-mixed-spaces-and-tabs": "warn", 81 | "@stylistic/js/no-multiple-empty-lines": "off", 82 | "@stylistic/js/no-tabs": "off", 83 | "no-unused-labels": "warn", 84 | 85 | "no-unused-vars": ["warn", { 86 | vars: "all", 87 | args: "after-used", 88 | }], 89 | 90 | "no-useless-escape": "warn", 91 | "@stylistic/js/padded-blocks": "off", 92 | 93 | "@stylistic/js/quotes": ["warn", "single", { 94 | allowTemplateLiterals: true, 95 | }], 96 | 97 | "require-jsdoc": "off", 98 | "require-unicode-regexp": "off", 99 | "@stylistic/js/semi": ["warn", "always"], 100 | "@stylistic/js/space-before-function-paren": "off", 101 | "unicode-bom": ["warn", "never"], 102 | }, 103 | 104 | }, 105 | 106 | 107 | // https://github.com/eslint/json#usage 108 | { 109 | plugins: { 110 | json, 111 | }, 112 | }, 113 | // lint JSON files // (from: https://github.com/eslint/json#recommended-configuration) 114 | { 115 | files: ["**/*.json"], 116 | language: "json/json", 117 | ...json.configs.recommended, 118 | }, 119 | 120 | // lint JSON-C files 121 | { 122 | // files: ["**/*.jsonc"], 123 | files: ["**/*.jsonc", ".vscode/*.json"], // https://github.com/eslint/json/pull/11 124 | language: "json/jsonc", 125 | ...json.configs.recommended, 126 | }, 127 | 128 | 129 | 130 | // https://github.com/eslint/markdown#configuring 131 | { 132 | // 1. Add the plugin 133 | plugins: { 134 | markdown 135 | } 136 | }, 137 | 138 | // https://www.npmjs.com/package/eslint-plugin-markdown 139 | // https://eslint.org/docs/latest/use/configure/plugins 140 | // https://github.com/eslint/json 141 | { 142 | // 2. Enable the Markdown processor for all .md files. 143 | files: ["**/*.md"], 144 | // files: ["**/*.md/*.js"], 145 | // plugins: { 146 | // markdown 147 | // }, 148 | processor: "markdown/markdown" 149 | }, 150 | { 151 | // // 3. Optionally, customize the configuration ESLint uses for ```js 152 | // // fenced code blocks inside .md files. 153 | files: ["**/*.md/*.js"], 154 | rules: { 155 | // ... 156 | 157 | // 2. Disable other rules. 158 | // "no-console": "off", 159 | // "import/no-unresolved": "off" 160 | } 161 | }, 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | // https://eslint.org/blog/2025/02/eslint-css-support/ [NEW ADDITION 20/2/2025] 171 | // 172 | // lint css files 173 | { 174 | files: ["**/*.css"], 175 | plugins: { 176 | css, 177 | }, 178 | language: "css/css", 179 | rules: { 180 | "css/no-duplicate-imports": "error", 181 | }, 182 | }, 183 | 184 | 185 | 186 | 187 | // https://eslint.org/docs/latest/use/configure/ignore 188 | // https://eslint.org/docs/latest/use/configure/migration-guide#ignoring-files 189 | { 190 | // Note: there should be no other properties in this object 191 | ignores: [ 192 | 193 | "node_modules/*", 194 | "**/*.min.js", 195 | "package-lock.json" 196 | 197 | ] 198 | 199 | } 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | ]; -------------------------------------------------------------------------------- /ixIRC_-_sortable_search_results/README.md: -------------------------------------------------------------------------------- 1 | This script applies to https://ixirc.com. 2 | 3 | It makes the search results sortable. 4 | 5 |
6 | 7 | _This userscript uses: jQuery,_ 8 | _the jQuery plugin [tablesorter](http://mottie.github.io/tablesorter/docs/index.html) (forked by Rob Garrison (Mottie))_ 9 | _the JavaScript [Datejs](http://www.datejs.com/) library_ 10 | _and [mathjs](http://mathjs.org/), an extensive math library for JavaScript and Node.js.) 11 | 12 | _Thanks a lot to Mottie for his help on using DateJs in a custom parser ([link](https://github.com/Mottie/tablesorter/issues/1402#issuecomment-302744234))_ -------------------------------------------------------------------------------- /ixIRC_-_sortable_search_results/ixIRC_-_sortable_search_results.user.js: -------------------------------------------------------------------------------- 1 | // ==UserScript== 2 | // @name ixIRC - sortable search results 3 | // @namespace darkred 4 | // @version 1 5 | // @description Makes the search results sortable 6 | // @authors darkred, Mottie 7 | // @license MIT 8 | // @include /https?:\/\/(www\.)?ixirc\.com\/\?(q|cid)=.*/ 9 | // @grant none 10 | // @require http://code.jquery.com/jquery-3.2.1.min.js 11 | // @require https://cdnjs.cloudflare.com/ajax/libs/jquery.tablesorter/2.28.10/js/jquery.tablesorter.min.js 12 | // @require https://cdnjs.cloudflare.com/ajax/libs/datejs/1.0/date.min.js 13 | // @require https://cdn.rawgit.com/Mottie/tablesorter/master/js/parsers/parser-metric.js 14 | // @require http://cdnjs.cloudflare.com/ajax/libs/mathjs/3.13.1/math.min.js 15 | // @run-at document-idle 16 | // Thanks a lot to Mottie for his help on using DateJs in a custom parser 17 | // @supportURL https://github.com/darkred/Userscripts/issues 18 | // ==/UserScript== 19 | 20 | 21 | 22 | /* global math */ 23 | 24 | // const kbCommified = true; 25 | const kbCommified = false; 26 | 27 | 28 | 29 | // CSS rules in order to show 'up' and 'down' arrows in each table header 30 | var stylesheet = ` 31 | `; 44 | $('head').append(stylesheet); 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | (($) => { 54 | // jQuery fix for tables lacking a thead (http://aaron.jorb.in/blog/2010/03/jquery-fix-for-tables-lacking-a-thead/) 55 | $('#results-table') 56 | .prepend($('') 57 | .append($('#results-table tr:first').remove())); 58 | 59 | 60 | // thanks a lot to Mottie for his help on this custom parser ( https://github.com/Mottie/tablesorter/issues/1402#issuecomment-302744234 ) 61 | $.tablesorter.addParser({ 62 | id: 'datejs', 63 | is: function() { 64 | return false; 65 | }, 66 | format: function(s) { 67 | var str = s 68 | .replace('hr', 'hour') 69 | .replace('min', 'minute') 70 | .replace('sec', 'seconds') 71 | .replace('ago', ''), 72 | date = Date.parse ? Date.parse('-' + str) : s ? new Date(str) : s; 73 | return date instanceof Date && isFinite(date) ? date.getTime() : s; 74 | }, 75 | type: 'numeric' 76 | }); 77 | 78 | 79 | 80 | 81 | // Unneeded because I use parser-metric.js (above) instead of this custom parser "storageUnits" 82 | // 83 | // $.tablesorter.addParser({ 84 | // // set a unique id 85 | // id: 'storageUnits', 86 | // // id: 'storageUnits', 87 | // is: function() { 88 | // return false; // return false so this parser is not auto detected 89 | // }, 90 | // format: function(s) { 91 | // // format your data for normalization 92 | // var str = s; 93 | // var size, unit; 94 | // var regex = /([0-9.]+)\s([A-Z]{1,2})/; // don't use ' ' for space, use \s instead !!! 95 | // size = Number(regex.exec(str)[1]); 96 | // unit = String(regex.exec(str)[2]); 97 | 98 | // if (unit === 'B') { return size * 1; } 99 | // else if (unit === 'KB') { return size * 1000; } 100 | // else if (unit === 'MB') { return size * 1000000; } 101 | // else if (unit === 'GB') { return size * 1000000000; } 102 | // else if (unit === 'TB') { return size * 1000000000000; } 103 | 104 | // }, 105 | // // set type, either numeric or text 106 | // type: 'numeric' 107 | // }); 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | $('th:contains("Size")').addClass('size'); 123 | $('th:contains("Posted")').addClass('posted'); 124 | $('th:contains("Last Activity")').addClass('lastActivity'); 125 | 126 | 127 | 128 | 129 | // Sources: https://mottie.github.io/tablesorter/docs/example-parsers-metric.html , and the file 'parser-metric.js' from: htttps://github.com/Mottie/tablesorter/tree/master/js/parsers 130 | // EITHER: 131 | // use the below line in order to use the option (i.e the parser by Mottie), i.e. line 226 ---> '.size': { sorter:'metric'}, 132 | // OR: 133 | // comment out this line, 134 | // remove the unneeded @require from the top of the file: // @require https://cdn.rawgit.com/Mottie/tablesorter/master/js/parsers/parser-metric.js and 135 | // uncomment line 227: ---> '.size': { sorter:'storageUnits'}, (i.e. YOUR custom parser, see above, lines 71-100) 136 | // and comment out line 226. 137 | $('.size').attr('data-metric-name-abbr','b|B'); 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | // http://stackoverflow.com/questions/6784894/add-commas-or-spaces-to-group-every-three-digits 152 | function commafy(num) { 153 | var str = num.toString().split('.'); 154 | if (str[0].length >= 5) { 155 | str[0] = str[0].replace(/(\d)(?=(\d{3})+$)/g, '$1,'); 156 | } 157 | if (str[1] && str[1].length >= 5) { 158 | str[1] = str[1].replace(/(\d{3})/g, '$1 '); 159 | } 160 | return str.join('.'); 161 | } 162 | 163 | 164 | 165 | if (kbCommified === true){ 166 | 167 | 168 | 169 | var sizes = $("tr td:nth-child(" + ($('th:contains("Size")').index()+1) + ")"); 170 | $(sizes).each(function( index ) { 171 | var temp = $(this).text().replace('B','b').replace('K', 'k').replace(/\s/g,''); 172 | // console.log(temp); 173 | $(this).text(commafy(math.unit(temp).to('kb').toNumber()) + ' KB'); 174 | }); 175 | 176 | 177 | 178 | // $('head').append(stylesheet2); 179 | $('.size').css('cssText', 'text-align: center !important'); 180 | sizes.css('text-align', 'right'); 181 | sizes.attr('width','90px !important;'); 182 | 183 | } 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | // http://stackoverflow.com/a/26343716/3231411 204 | $('#results-table').tablesorter ({ 205 | cssAsc: 'up', 206 | cssDesc: 'down', 207 | headers: { 208 | '.size': { sorter:'metric'}, 209 | // '.size': { sorter:'storageUnits'}, 210 | '.posted': { sorter:'datejs', sortInitialOrder : 'desc' }, 211 | '.lastActivity': { sorter:'datejs', sortInitialOrder : 'desc' } 212 | 213 | } 214 | }); 215 | 216 | })(jQuery.noConflict(true)); 217 | 218 | -------------------------------------------------------------------------------- /ixIRC_-_sortable_search_results/parser-metric.js: -------------------------------------------------------------------------------- 1 | /*! Parser: metric *//* 2 | * Demo: http://jsfiddle.net/Mottie/abkNM/382/ 3 | * Set the metric name in the header (defaults to 'm|meter'), e.g. 4 | * HDD Size 5 | * Distance 6 | */ 7 | /*jshint jquery:true */ 8 | ;( function( $ ) { 9 | 'use strict'; 10 | 11 | var prefixes = { 12 | // 'prefix' : [ base 10, base 2 ] 13 | // skipping IEEE 1541 defined prefixes: kibibyte, mebibyte, etc, for now. 14 | 'Y|Yotta|yotta' : [ 1e24, Math.pow(1024, 8) ], // 1024^8 15 | 'Z|Zetta|zetta' : [ 1e21, Math.pow(1024, 7) ], // 1024^7 16 | 'E|Exa|exa' : [ 1e18, Math.pow(1024, 6) ], // 1024^6 17 | 'P|Peta|peta' : [ 1e15, Math.pow(1024, 5) ], // 1024^5 18 | 'T|Tera|tera' : [ 1e12, Math.pow(1024, 4) ], // 1024^4 19 | 'G|Giga|giga' : [ 1e9, Math.pow(1024, 3) ], // 1024^3 20 | 'M|Mega|mega' : [ 1e6, Math.pow(1024, 2) ], // 1024^2 21 | 'k|Kilo|kilo' : [ 1e3, 1024 ], // 1024 22 | // prefixes below here are rarely, if ever, used in binary 23 | 'h|hecto' : [ 1e2, 1e2 ], 24 | 'da|deka' : [ 1e1, 1e1 ], 25 | 'd|deci' : [ 1e-1, 1e-1 ], 26 | 'c|centi' : [ 1e-2, 1e-2 ], 27 | 'm|milli' : [ 1e-3, 1e-3 ], 28 | 'µ|micro' : [ 1e-6, 1e-6 ], 29 | 'n|nano' : [ 1e-9, 1e-9 ], 30 | 'p|pico' : [ 1e-12, 1e-12 ], 31 | 'f|femto' : [ 1e-15, 1e-15 ], 32 | 'a|atto' : [ 1e-18, 1e-18 ], 33 | 'z|zepto' : [ 1e-21, 1e-21 ], 34 | 'y|yocto' : [ 1e-24, 1e-24 ] 35 | }, 36 | // the \\d+ will not catch digits with spaces, commas or decimals; so use the value from n instead 37 | RegLong = '(\\d+)(\\s+)?([Zz]etta|[Ee]xa|[Pp]eta|[Tt]era|[Gg]iga|[Mm]ega|kilo|hecto|deka|deci|centi|milli|micro|nano|pico|femto|atto|zepto|yocto)(', 38 | RegAbbr = '(\\d+)(\\s+)?(Z|E|P|T|G|M|k|h|da|d|c|m|µ|n|p|f|a|z|y)(', 39 | // make these case-insensitive because we all forget the case for these binary values 40 | byteTest = /^[b|bit|byte|o|octet]/i; 41 | 42 | $.tablesorter.addParser({ 43 | id: 'metric', 44 | is: function() { 45 | return false; 46 | }, 47 | format: function(txt, table, cell, cellIndex) { 48 | var unit, isBinary, nameLong, nameAbbr, 49 | // default base unit name 50 | base = 'm|meter', 51 | // process number here to get a numerical format (us or eu) 52 | num = $.tablesorter.formatFloat( txt.replace(/[^\w,. \-()]/g, ''), table ), 53 | $t = table.config.$headerIndexed[ cellIndex ], 54 | regex = $t.data( 'metric' ); 55 | if ( !regex ) { 56 | // stored values 57 | unit = ( $t.attr('data-metric-name') || base ).split( '|' ); 58 | nameLong = $t.attr( 'data-metric-name-full' ) || ''; 59 | nameAbbr = $t.attr( 'data-metric-name-abbr' ) || ''; 60 | regex = [ nameLong || unit[1] || unit[0].substring(1), nameAbbr || unit[0] ]; 61 | isBinary = byteTest.test( regex.join( '' ) ); 62 | // adding 'data-metric-name-full' which would contain 'byte|BYTE|Byte' etc 63 | regex[2] = new RegExp( RegLong + ( 64 | ( nameLong === '' ? '' : nameLong + '|' + nameAbbr ) || 65 | // with data-metric-name='b|byte', we end up with 'b|B|byte|BYTE' - maybe not the best solution for case-insensitivity 66 | ( ( isBinary ? regex[0].toLowerCase() + '|' + regex[0].toUpperCase() : regex[0] ) + '|' + 67 | ( isBinary ? regex[1].toLowerCase() + '|' + regex[1].toUpperCase() : regex[1] ) ) ) + 68 | ')' ); 69 | // adding 'data-metric-name-abbr' which would contain 'b|B' etc 70 | regex[3] = new RegExp( RegAbbr + ( nameAbbr || 71 | ( ( isBinary ? regex[1].toLowerCase() + '|' + regex[1].toUpperCase() : regex[1] ) ) ) + 72 | ')' ); 73 | $t.data( 'metric', regex ); 74 | } 75 | // find match to full name or abbreviation 76 | unit = txt.match( regex[2] ) || txt.match( regex[3] ); 77 | if ( unit ) { 78 | for ( base in prefixes ) { 79 | if ( unit[3].match( base ) ) { 80 | // exception when using binary prefix 81 | // change base for binary use 82 | isBinary = byteTest.test( unit[4] ) ? 1 : 0; 83 | return num * prefixes[ base ][ isBinary ]; 84 | } 85 | } 86 | } 87 | return num; 88 | }, 89 | type: 'numeric' 90 | }); 91 | 92 | })(jQuery); 93 | -------------------------------------------------------------------------------- /kuehlschrank scripts icon - backup/Bullshit_Filter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darkred/Userscripts/5137627e96d6e06cb0d13cc6ebdc5f4f9917cb0a/kuehlschrank scripts icon - backup/Bullshit_Filter.png -------------------------------------------------------------------------------- /mozillaZine_Forums_-_insert_titles_to_bug_links/3Y8dqYZ.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darkred/Userscripts/5137627e96d6e06cb0d13cc6ebdc5f4f9917cb0a/mozillaZine_Forums_-_insert_titles_to_bug_links/3Y8dqYZ.gif -------------------------------------------------------------------------------- /mozillaZine_Forums_-_insert_titles_to_bug_links/README.md: -------------------------------------------------------------------------------- 1 | This userscript applies to forums.mozillazine.org. 2 | It inserts titles to bug links that are plain URLs, in forums.mozillazine.org 3 | i.e. instead of showing: 4 | [https://bugzilla.mozilla.org/show_bug.cgi?id=1147820](https://bugzilla.mozilla.org/show_bug.cgi?id=1147820) 5 | it shows: [1147820 - [meta] Improve Storage ](https://bugzilla.mozilla.org/show_bug.cgi?id=1147820) 6 | It also converts links with titles like [Bug 1147820](https://bugzilla.mozilla.org/show_bug.cgi?id=1147820). 7 | 8 | Note: the request for each link is done asynchronously, i.e. Firefox UI is not locked and frozen until the request completes. 9 | 10 | v2.0: Script rewrite _(based on johnp\_'s contribution in the userscript 'Firefox for desktop - list fixed bugs in Mercurial')_: 11 | now the REST API is used (one(1) network connection is made for all unique examined bug IDs). 12 | During this procedure, you may open the Web Console (Ctrl+Shift+K) to monitor progress. ([screenshot](https://i.imgur.com/DQjD09A.jpg)) 13 | 14 | v1.1 Now, a spinning icon appears at the end of each bug link during the title request procedure: 15 | During the request : ![](https://i.imgur.com/pQVnJyI.jpg) 16 | After appending title: ![](https://i.imgur.com/9MwgmlB.jpg) -------------------------------------------------------------------------------- /mozillaZine_Forums_-_insert_titles_to_bug_links/mozillaZine_Forums_-_insert_titles_to_bug_links.user.js: -------------------------------------------------------------------------------- 1 | // ==UserScript== 2 | // @name mozillaZine Forums - insert titles to bug links 3 | // @namespace darkred 4 | // @version 2017.11.16 5 | // @description Inserts titles to bug links that are plain URLs, in forums.mozillazine.org 6 | // @author darkred, johnp_ 7 | // @license MIT 8 | // @include http://forums.mozillazine.org/viewtopic.php* 9 | // @grant none 10 | // @require https://code.jquery.com/jquery-2.1.4.min.js 11 | // @supportURL https://github.com/darkred/Userscripts/issues 12 | // ==/UserScript== 13 | 14 | // v2.0: Script rewrite (based on johnp_'s contribution in the userscript 'Firefox for desktop - list fixed bugs in Mercurial'): 15 | // now the REST API is used (one(1) network connection is made for all unique examined bug IDs) 16 | 17 | 18 | /* eslint-disable no-console */ 19 | 20 | 21 | 22 | var silent = false; 23 | var debug = false; 24 | 25 | time('MozillaBugzilla'); 26 | 27 | 28 | var regex = /^https:\/\/bugzilla\.mozilla\.org\/show_bug\.cgi\?id=([0-9]*).*$/; 29 | var base_url = 'https://bugzilla.mozilla.org/rest/bug?include_fields=id,summary,status&id='; 30 | var bugIds = []; 31 | var bugCodes = []; 32 | var bugTitles = []; 33 | var links = document.getElementsByClassName('postlink'); 34 | var len = links.length; 35 | 36 | 37 | for (let i = 0; i < len; i++) { 38 | let n = links[i].href.match(regex); 39 | let n2 = links[i].innerHTML; 40 | if (n !== null && 41 | n2.match(/^#[0-9]*/) === null && 42 | n2.indexOf('-') === -1) { 43 | let id = parseInt(n[1]); 44 | if (bugIds.indexOf(id) === -1) { 45 | bugIds.push(id); 46 | } 47 | } 48 | } 49 | 50 | 51 | 52 | var numBugs = bugIds.length; 53 | var counter = 0; 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | var rest_url = base_url + bugIds.join(); 62 | time('MozillaBugzilla-REST'); 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | // ADDING a spinning icon to the matching links 74 | for (var i = 0; i < links.length; i++) { 75 | if ( links[i].href.match(regex) 76 | && links[i].innerHTML.match(/#[0-9]*/) == null 77 | && links[i].innerHTML.indexOf('-') == -1 ) { 78 | var elem = document.createElement('img'); 79 | // var elem; 80 | //(async function() { 81 | // elem = document.createElement('img'); 82 | // elem.src = GM.getResourceUrl('icon'); 83 | 84 | 85 | var rotatingIcon_base64 = `data:image/gif;base64,R0lGODlhEAAQAPIAAP///8LCwkJCQgAAAGJiYoKCgpKSkgAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQJCgAAACwAAAAAEAAQAAADMwi63P4wyklrC0IEKsYQnAdOmGYFBLExwboQWcG2LlDEgWHQLUsUOd2mBzEUCgZKa+dIAAAh+QQJCgAAACwAAAAAEAAQAAADNAi63P4uCBEgE2MIu7DmikRxAUFUIDEVIFBMRFsWqGwYtXXfrVEUBkAg1xjihkMZsiUkKhIAIfkECQoAAAAsAAAAABAAEAAAAzYIuiESK0oxhpCskFYvBoRTGA70FQ7xSQFRmGtgGPAKzLO9GMWoKwFZ7Rf8AYPDDzKpZBqfvwQAIfkECQoAAAAsAAAAABAAEAAAAzMIulEUK0oiRJHMmFZfhYumBUQRCMMgREZRGBGqRkGw0R8DYlJd8z0fMDgsGo/IpHI5TAAAIfkECQoAAAAsAAAAABAAEAAAAzIIumEWK0rnZAzQlPIKgQwmdoJQXGJElISEuR5oWUEpz4owDAIe6TwfwyYsGo/IpFKSAAAh+QQJCgAAACwAAAAAEAAQAAADMwi6EMGQORfjdMa82l4oGccYoCEuQbadykesYiEIBQsQM2G7sDX3FcFgILAJibufbSlKAAAh+QQJCgAAACwAAAAAEAAQAAADMgi63P7whRDZnFVdmgHummFwVVCInVGc3TSWREFGhCAQUGCbdgEJg4EgEJsxgMLWzpEAACH5BAkKAAAALAAAAAAQABAAAAMyCLrc/jDKSatlIdScKdceCASCII6GcQrDIDCpyrBuQBSBURQGVtolAiB1YhSCnlsRkAAAOw==`; 86 | elem.src = rotatingIcon_base64; 87 | 88 | 89 | 90 | links[i].parentNode.insertBefore(elem, links[i].nextSibling); // For spinning icon AFTER the link 91 | 92 | // })(); 93 | // links[i].parentNode.insertBefore(elem, links[i].previousSibling); // For spinning icon BEFORE the link 94 | } 95 | } 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | $.getJSON(rest_url, function(data) { 110 | timeEnd('MozillaBugzilla-REST'); 111 | 112 | 113 | $.each(data.bugs, function(index) { 114 | let bug = data.bugs[index]; 115 | let status = bug.status; 116 | 117 | log('----------------------------------------------------------------------------------------------------------------------------------'); 118 | log((index + 1) + '/' + numBugs); // Progression counter 119 | 120 | log('BugNo: ' + bug.id + '\nTitle: ' + bug.summary); 121 | 122 | 123 | 124 | bugCodes.push(bug.id); 125 | bugTitles.push(bug.summary); 126 | 127 | 128 | counter++; // increase counter 129 | 130 | let i = bugIds.indexOf(bug.id); 131 | if (i !== -1) {bugIds[i] = null;} 132 | }); 133 | log('==============\nReceived ' + counter + ' of ' + numBugs + ' bugs.'); 134 | 135 | // process remaining bugs one-by-one 136 | var requests = []; 137 | time('MozillaBugzilla-missing'); 138 | $.each(bugIds, function(index) { 139 | let id = bugIds[index]; 140 | if (id !== null) { 141 | time('Requesting missing bug ' + id); 142 | let promise = $.getJSON('https://bugzilla.mozilla.org/rest/bug/' + id, 143 | function(json) { 144 | // I've not end up here yet, so cry if we do 145 | console.error('Request succeeded unexpectedly!'); 146 | console.error('Please submit this information to the script authors:'); 147 | timeEnd('Requesting missing bug ' + id); 148 | console.log(json); 149 | let bug = json.bugs[0]; 150 | console.log(bug); 151 | // TODO: display as much information as possible 152 | }); 153 | // Actually, we usually get an error 154 | promise.error(function(req, status, error) { 155 | timeEnd('Requesting missing bug ' + id); 156 | if (error == 'Authorization Required') { 157 | log('Bug ' + id + ' requires authorization!'); 158 | // log('https://bugzilla.mozilla.org/show_bug.cgi?id=' + id + ' requires authorization!'); 159 | } else { 160 | console.error('Unexpected error encountered (Bug' + id + '): ' + status + ' ' + error); 161 | } 162 | }); 163 | requests.push(promise); 164 | } 165 | }); 166 | // wait for all requests to be settled, then join them together 167 | // Source: https://stackoverflow.com/questions/19177087/deferred-how-to-detect-when-every-promise-has-been-executed 168 | $.when.apply($, $.map(requests, function(p) { 169 | return p.then(null, function() { 170 | return $.Deferred().resolveWith(this, arguments); 171 | }); 172 | })).always(function() { 173 | timeEnd('MozillaBugzilla-missing'); 174 | 175 | // console.log(bugCodes); 176 | 177 | for (let z=0; z < links.length; z++) { 178 | 179 | loop2: 180 | for (let yy=0; yy < bugCodes.length; yy++) { 181 | 182 | if (regex.test(links[z].href) 183 | && links[z].href.match(regex)[1] == bugCodes[yy] 184 | && links[z].innerHTML.indexOf('-') == -1 ) { 185 | 186 | let temp = links[z].innerHTML.match(/([Bb]ug\ [a-zA-Z]*).*[0-9]*/i); 187 | var temp2 = links[z].href.match(/^https:\/\/bugzilla\.mozilla\.org\/show_bug\.cgi\?id=[0-9]*(.*)$/); 188 | // if (temp !== null) { 189 | // links[z].previousSibling.textContent += temp[1] + ' '; 190 | // links[z].innerHTML = bugCodes[yy] + ' - ' + bugTitles[yy] + temp2[1]; 191 | // } else { 192 | // links[z].innerHTML = bugCodes[yy] + ' - ' + bugTitles[yy] + temp2[1]; 193 | // } 194 | if (temp !== null) { 195 | links[z].previousSibling.textContent += temp[1] + ' '; 196 | } 197 | links[z].innerHTML = bugCodes[yy] + ' - ' + bugTitles[yy] + temp2[1]; 198 | 199 | break loop2; 200 | } 201 | 202 | } 203 | 204 | 205 | if (links[z].nextSibling && links[z].nextSibling.src === rotatingIcon_base64){ 206 | links[z].nextSibling.remove(); // For REMOVE spinning icon AFTER the link 207 | // x.previousSibling.previousSibling.remove(); // For REMOVE spinning icon BEFORE the link 208 | if (links[z].innerHTML.indexOf('https://bugzilla.mozilla.org') !== -1 ){ 209 | links[z].innerHTML += '  (requires authorization)'; 210 | } 211 | } 212 | 213 | } 214 | log('ALL IS DONE'); 215 | timeEnd('MozillaBugzilla'); 216 | }); 217 | }); 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | function log(str) { 226 | if (!silent) { 227 | console.log(str); 228 | } 229 | } 230 | 231 | function time(str) { 232 | if (debug) { 233 | console.time(str); 234 | } 235 | } 236 | 237 | function timeEnd(str) { 238 | if (debug) { 239 | console.timeEnd(str); 240 | } 241 | } 242 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "module", 3 | "devDependencies": { 4 | "@biomejs/biome": "*", 5 | "@eslint/config-inspector": "*", 6 | "@eslint/css": "*", 7 | "@eslint/eslintrc": "*", 8 | "@eslint/js": "*", 9 | "@eslint/json": "*", 10 | "@eslint/markdown": "*", 11 | "@eslint/migrate-config": "*", 12 | "@stylistic/eslint-plugin": "*", 13 | "@stylistic/eslint-plugin-js": "*", 14 | "eslint": "^9.10.0", 15 | "eslint-plugin-css": "*", 16 | "eslint-plugin-es-x": "*", 17 | "eslint-plugin-jsdoc": "*", 18 | "eslint-plugin-jsonc": "*", 19 | "eslint-plugin-no-jquery": "*", 20 | "eslint-plugin-regexp": "*", 21 | "eslint-plugin-userscripts": "*", 22 | "eslint-plugin-yml": "*", 23 | "globals": "*" 24 | }, 25 | "dependencies": { 26 | "rescript": "*", 27 | "turbo": "*" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://docs.renovatebot.com/renovate-schema.json", 3 | "extends": [ 4 | "config:recommended" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /thepiratebay_-_add_a_sortable_Ratio_column/README.md: -------------------------------------------------------------------------------- 1 | This script adds a sortable "Ratio" column to torrent search results in thepiratebay. 2 | 3 | Note: it works only in single-line view (not in double line). 4 | -------------------------------------------------------------------------------- /thepiratebay_-_add_a_sortable_Ratio_column/thepiratebay_-_add_a_sortable_Ratio_column.user.js: -------------------------------------------------------------------------------- 1 | // ==UserScript== 2 | // @name thepiratebay - add a sortable Ratio column 3 | // @namespace darkred 4 | // @version 2020.7.29 5 | // @description Adds a sortable "Ratio" column 6 | // @author darkred 7 | // @license MIT 8 | // @include https://thepiratebay.org/search.php* 9 | // @grant none 10 | // @require https://code.jquery.com/jquery-3.5.1.min.js 11 | // This userscript uses jQuery and it's plugin "tablesorter" (forked by Rob Garrison (Mottie)) http://mottie.github.io/tablesorter/docs/index.html 12 | // @supportURL https://github.com/darkred/Userscripts/issues 13 | // ==/UserScript== 14 | 15 | 16 | // For the sortable Ratio column 17 | function appendColumn() { 18 | var se, le, ratio; 19 | if (document.querySelector('span.list-header:nth-child(7)')){ 20 | document.querySelector('span.list-header:nth-child(7)').insertAdjacentHTML('afterend', ''); 21 | } 22 | var entries = document.querySelectorAll('li.list-entry > span:nth-child(7)'); 23 | for (var i = 0; i < entries.length; i++) { 24 | se = parseInt(entries[i].previousElementSibling.innerHTML); // Retrieve the content of the cell of the SE column and store it to variable se 25 | le = parseInt(entries[i].innerHTML); // Retrieve the content of the cell of the LE column and store it to variable le 26 | if (se > 0 && le === 0){ 27 | ratio = se; 28 | } else if (se === 0 || le === 0){ 29 | ratio = 0; 30 | } else { 31 | ratio = se/le; 32 | } 33 | // ratio = (Math.round(10 * ratio) / 10); 34 | ratio = ratio.toFixed(1); 35 | entries[i].insertAdjacentHTML('afterend', '' + ratio + ''); 36 | entries[i].nextSibling.className = 'list-item item-ratio'; 37 | $('.item-ratio').css('text-align', 'right'); 38 | } 39 | } 40 | 41 | appendColumn(); 42 | 43 | 44 | // Select all 'ULed by' values (=all last cells of all rows) and align them to the right 45 | $('.list-item:last-child').css('text-align', 'right'); 46 | -------------------------------------------------------------------------------- /thepiratebay_helper/README.md: -------------------------------------------------------------------------------- 1 | It's a modified version of [PirateBay Time Changer](http://userscripts-mirror.org/scripts/show/164849) 2 | 3 | Additional features: 4 | - Now you may may choose in Settings via a dropdown menu between: 5 | - highlighting trusted, 6 | - hiding non trusted, (optionally combined with the checkbox: `...when toggle, include those non-trusted which have comments`) 7 | - show all 8 | - Added two keyboard shortcuts ( \` and \~ ) to toggle between: 9 | - view trusted only, and view trusted incl. non-trusted with comments 10 | - view all 11 | - Added an option to display torrent timestamps in relative format (and recalculates them for browse/search lists every 10 secs) _(enabled by default)_ 12 | _(the initial timestamps -converted to local timezone's offset- are tooltips: just hover mouse on a relative date to view)_, 13 | - Added to swap the verified icons position with that of the comments _(enabled by default)_, 14 | - Added an option to add a sortable 'Ratio' (seeds/peers) column _(enabled by default)_. 15 | 16 | You may also click on the e.g, `7/30 torrents are currently hidden) - click to toggle` 17 | to toggle highlight/hide *(and this is reflected in GM_config too)*. 18 | - Changes in the relevant texts in the script due to that TPB timezone is `GMT+1` *(and not `GMT` as the site wrongly displays in torrent pages)* 19 | - About the *"enhance the visibility of torrents based off of VIP/Trusted status"* feature: 20 | - Torrents by "Helpers" are now also highlighted. 21 | - Torrents by "Trusted" are now highlighted with this color: #F9D5DB *(initially it was #FECDFE)* 22 | 23 | 24 | Screenshots: 25 | [![](https://i.imgur.com/Q9GincAs.jpg)](https://i.imgur.com/Q9GincA.jpg) [![](https://i.imgur.com/ls5scKys.jpg)](https://i.imgur.com/ls5scKy.jpg) [![](https://s3.amazonaws.com/uso_ss/21237/thumb.jpg?1366305203)](http://s3.amazonaws.com/uso_ss/21237/large.jpg?1366305203) [![](https://i.imgur.com/lAJiCJcs.jpg)](https://i.imgur.com/lAJiCJc.jpg) [![](https://i.imgur.com/wyyJiujs.jpg)](https://i.imgur.com/wyyJiuj.jpg) 26 | 27 |
28 | 29 | 30 | 31 | 32 | 33 | Thanks to emptyparad0x for making a very useful script! 34 | 35 | 36 | --- 37 | 38 | 39 | 40 | 41 | Info for the script in http://userscripts-mirror.org/scripts/show/164849 42 | 43 | - This script changes the times everywhere on thepiratebay except for the comments. It changes the time shown in the browse/search lists and the torrent pages themselves (including the comments). 44 | - At the bottom of the page, you will find the configuration menu for the script. This is where you will enter how you'd like your times displayed. 45 | - The `TPB Timezone` allows for you to adjust the timezone that thepiratebay is currently displaying. As of 4/18/2013 the timezone is GMT+1, therefore its value should be left as it is, i.e. `(GMT+1) + 0`. 46 | - After saving settings, the script will reload the page. 47 | 48 | **Tech Info** 49 | This script uses GM_config and jQuery. It has not been tested for conflicts with other userscripts or languages besides English. 50 | It has been tested with Greasemonkey on Firefox and Tampermonkey on Chrome. 51 |
52 | *It uses [Keypress](https://github.com/dmauro/Keypress/) keyboard input capturing utility and the jQuery plugin [tablesorter](http://mottie.github.io/tablesorter/docs/index.html) (forked by Rob Garrison (Mottie)) .* -------------------------------------------------------------------------------- /userstyles.org_css_highlighter/README.md: -------------------------------------------------------------------------------- 1 | It's modified version of https://greasyfork.org/en/scripts/41-userstyles-org-css-highlighter (by trespassersW) 2 | in order to work with the new userstyles.org layout. 3 | 4 | Notes: 5 | - It uses the [arrive.js](https://github.com/uzairfarooq/arrive) library. 6 | - Thanks to trespassersW for a very useful script! 7 | --------------------------------------------------------------------------------