diff --git a/.eslintignore b/.eslintignore [DEPRECATED] similarity index 100% rename from .eslintignore rename to .eslintignore [DEPRECATED] diff --git a/.eslintrc.js b/.eslintrc.js [DEPRECATED] similarity index 91% rename from .eslintrc.js rename to .eslintrc.js [DEPRECATED] index fcea33a..8ebc3c0 100644 --- a/.eslintrc.js +++ b/.eslintrc.js [DEPRECATED] @@ -1,4 +1,8 @@ +/* eslint-disable quotes */ + module.exports = { + "root": true, + "env": { "browser": true, "es6": true, @@ -6,11 +10,25 @@ module.exports = { "jquery": true, // "node": true }, + + "parserOptions": { + // "ecmaVersion": 12, + "ecmaVersion": "latest", + "sourceType": "script", + "ecmaFeatures": { + "globalReturn ": true, + "impliedStrict": true, + // "jsx": true, + }, + }, + // "extends": "eslint:all", // "extends": "eslint:recommended", "extends": [ "eslint:recommended", // "eslint:all", + "plugin:css/recommended", + "plugin:jsonc/recommended-with-json", // "plugin:no-jquery/recommended", "plugin:no-jquery/deprecated", // "plugin:no-jquery/slim", @@ -18,23 +36,16 @@ module.exports = { // "plugin:clean-regex/recommended" "plugin:regexp/recommended", // "plugin:regexp/all", - ], + "plugins": [ + "css", + "jsonc", // "clean-regex", - "regexp", "no-jquery", + "regexp", ], - "parserOptions": { - // "ecmaVersion": 12, - "ecmaVersion": 'latest', - "sourceType": "script", - "ecmaFeatures": { - "globalReturn ": true, - "impliedStrict": true, - // "jsx": true, - }, - }, + "rules": { "complexity": ["warn", 20], "eqeqeq": "warn", @@ -49,6 +60,7 @@ module.exports = { "new-cap": "off", "no-alert": "warn", "no-console": "warn", + "no-dupe-keys": "warn", "no-extra-semi": "warn", "no-inline-comments": "off", "no-magic-numbers": "off", @@ -69,8 +81,8 @@ module.exports = { "space-before-function-paren": "off", // "space-in-parens": ["warn", "always"], "unicode-bom": ["warn", "never"], - }, + "reportUnusedDisableDirectives": true }; diff --git a/.eslintrc.json [DEPRECATED] b/.eslintrc.json [DEPRECATED] new file mode 100644 index 0000000..a34a4d6 --- /dev/null +++ b/.eslintrc.json [DEPRECATED] @@ -0,0 +1,61 @@ +{ + "root": true, + "env": { + "browser": true, + "es6": true, + "greasemonkey": true, + "jquery": true + }, + "parserOptions": { + "ecmaVersion": "latest", + "sourceType": "script", + "ecmaFeatures": { + "globalReturn ": true, + "impliedStrict": true + } + }, + "extends": [ + "eslint:recommended", + "plugin:css/recommended", + "plugin:jsonc/recommended-with-json", + "plugin:no-jquery/deprecated", + "plugin:regexp/recommended" + ], + "plugins": [ + "css", + "jsonc", + "no-jquery", + "regexp" + ], + "rules": { + "complexity": ["warn", 20], + "eqeqeq": "warn", + "func-style": "off", + "indent": ["warn","tab", { "ignoreComments": false, "SwitchCase": 1 } ], + "linebreak-style": ["warn","unix"], + "max-len": "off", + "max-statements-per-line": "off", + "new-cap": "off", + "no-alert": "warn", + "no-console": "warn", + "no-dupe-keys": "warn", + "no-extra-semi": "warn", + "no-inline-comments": "off", + "no-magic-numbers": "off", + "no-misleading-character-class": "warn", + "no-mixed-spaces-and-tabs": "warn", + "no-multiple-empty-lines": "off", + "no-tabs": "off", + "no-unused-labels": "warn", + "no-unused-vars": ["warn", {"vars": "all", "args": "after-used"}], + "no-useless-escape": "warn", + "padded-blocks": "off", + "quotes": ["warn", "single", { "allowTemplateLiterals": true }] , + "require-jsdoc": "off", + "require-unicode-regexp": "off", + "semi": ["warn","always"], + "space-before-function-paren": "off", + "unicode-bom": ["warn", "never"] + }, + "reportUnusedDisableDirectives": true +} diff --git a/.gitattributes b/.gitattributes index bdb0cab..1e78b8c 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,5 +1,5 @@ # Auto detect text files and perform LF normalization -* text=auto +* text=auto eol=lf # Custom for Visual Studio *.cs diff=csharp diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..75d11ec --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,16 @@ +# To get started with Dependabot version updates, you'll need to specify which +# package ecosystems to update and where the package manifests are located. +# Please see the documentation for all configuration options: +# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates + +version: 2 +updates: + - package-ecosystem: "npm" # See documentation for possible values + directory: "/" # Location of package manifests + schedule: + interval: "daily" + + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly" # Check for updates to GitHub Actions every week diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml deleted file mode 100644 index e610910..0000000 --- a/.github/workflows/codeql-analysis.yml +++ /dev/null @@ -1,71 +0,0 @@ -# For most projects, this workflow file will not need changing; you simply need -# to commit it to your repository. -# -# You may wish to alter this file to override the set of languages analyzed, -# or to provide custom queries or build logic. -# -# ******** NOTE ******** -# We have attempted to detect the languages in your repository. Please check -# the `language` matrix defined below to confirm you have the correct set of -# supported CodeQL languages. -# -name: "CodeQL" - -on: - push: - branches: [ master ] - pull_request: - # The branches below must be a subset of the branches above - branches: [ master ] - schedule: - - cron: '23 10 * * 6' - -jobs: - analyze: - name: Analyze - runs-on: ubuntu-latest - permissions: - actions: read - contents: read - security-events: write - - strategy: - fail-fast: false - matrix: - language: [ 'javascript' ] - # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ] - # Learn more: - # https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed - - steps: - - name: Checkout repository - uses: actions/checkout@v2 - - # Initializes the CodeQL tools for scanning. - - name: Initialize CodeQL - uses: github/codeql-action/init@v1 - with: - languages: ${{ matrix.language }} - # If you wish to specify custom queries, you can do so here or in a config file. - # By default, queries listed here will override any specified in a config file. - # Prefix the list here with "+" to use these queries and those in the config file. - # queries: ./path/to/local/query, your-org/your-repo/queries@main - - # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). - # If this step fails, then you should remove it and run the build manually (see below) - - name: Autobuild - uses: github/codeql-action/autobuild@v1 - - # â„šī¸ Command-line programs to run using the OS shell. - # 📚 https://git.io/JvXDl - - # âœī¸ If the Autobuild fails above, remove it and uncomment the following three lines - # and modify them (or add more) to build your code if your project - # uses a compiled language - - #- run: | - # make bootstrap - # make release - - - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v1 diff --git a/.github/workflows/dependency-review.yml b/.github/workflows/dependency-review.yml new file mode 100644 index 0000000..b9d6d20 --- /dev/null +++ b/.github/workflows/dependency-review.yml @@ -0,0 +1,14 @@ +name: 'Dependency Review' +on: [pull_request] + +permissions: + contents: read + +jobs: + dependency-review: + runs-on: ubuntu-latest + steps: + - name: 'Checkout Repository' + uses: actions/checkout@v4 + - name: 'Dependency Review' + uses: actions/dependency-review-action@v4 diff --git a/.github/workflows/evergreen.yml b/.github/workflows/evergreen.yml new file mode 100644 index 0000000..57eb768 --- /dev/null +++ b/.github/workflows/evergreen.yml @@ -0,0 +1,22 @@ +name: Weekly dependabot checks + +on: + workflow_dispatch: + schedule: + - cron: '3 2 1 * *' + +permissions: + issues: write + pull-requests: write + +jobs: + evergreen: + name: evergreen + runs-on: ubuntu-latest + + steps: + - name: Run evergreen action + uses: github/evergreen@v1 + env: + GH_TOKEN: ${{ secrets.EVERGREEN_ACTION }} + REPOSITORY: darkred diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 45705e4..f2415f5 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -24,7 +24,7 @@ jobs: lint: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Install modules run: npm install - name: Run ESLint diff --git a/Blabbermouth_-_generate_timestamps_and_add_link_to_the_FB_comments_area/Blabbermouth_-_generate_timestamps_and_add_link_to_the_FB_comments_area.user.js b/Blabbermouth_-_generate_timestamps_and_add_link_to_the_FB_comments_area/Blabbermouth_-_generate_timestamps_and_add_link_to_the_FB_comments_area.user.js index 7d18c7c..d28f711 100644 --- a/Blabbermouth_-_generate_timestamps_and_add_link_to_the_FB_comments_area/Blabbermouth_-_generate_timestamps_and_add_link_to_the_FB_comments_area.user.js +++ b/Blabbermouth_-_generate_timestamps_and_add_link_to_the_FB_comments_area/Blabbermouth_-_generate_timestamps_and_add_link_to_the_FB_comments_area.user.js @@ -1,18 +1,18 @@ // ==UserScript== // @name Blabbermouth - generate timestamps and add link to the fb comments area // @namespace darkred -// @version 1.3 -// @date 2022.1.8 +// @version 2.0 +// @date 2022.5.14 // @description Generates missing timestamps or converts the existing ones in relative format, and adds link to the fb comments area // @author darkred // @license MIT -// @include /^(https?:)?\/\/(www\.)?blabbermouth\.net\/(news|cdreviews|dvdreviews)?/ -// @exclude /^(https?:)?\/\/(www\.)?blabbermouth\.net\/(cdreviews|dvdreviews)(\/page|$)/ +// @include /^(https?:)?\/\/(www\.)?blabbermouth\.net\/(news|reviews)?/ +// @exclude /^(https?:)?\/\/(www\.)?blabbermouth\.net\/reviews(\/page|$)/ // @include https://www.facebook.com/plugins/feedback.php* // @grant none // @require https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.24.0/moment.min.js // @supportURL https://github.com/darkred/Userscripts/issues -// @icon https://www.blabbermouth.net/assets/favicon-309148577f1b67c003487c069cccf8731e6f68e4d847c5576d6f5453b083c27a.png +// @icon https://drnizx3otcofi.cloudfront.net/b64e6010-2ac1-4e95-b545-1a2994bbbd04/img/favicon/favicon-32x32.png // ==/UserScript== @@ -43,11 +43,12 @@ moment.updateLocale('en', { function convertToLocalTimezone(timestamp) { // (the timestamp is in ISO 8601 format and its trailing Z means that it's in UTC ) - // 2020-03-05T15:40:38.000Z + // 2020-03-05T15:40:38.000Z old + // 2022-05-11T12:16:05+00:00 new let initialTimestamp = timestamp; if (moment(initialTimestamp, moment.ISO_8601, true).isValid()) { // let convertedToLocalTimezone = moment(initialTimestamp.replace('Z','') + '-05:00', 'YYYY-MM-DDTHH:mm:ssZ'); // the server's timezone is GMT-5 - let convertedToLocalTimezone = moment(initialTimestamp.replace('Z','') + '-03:47', 'YYYY-MM-DDTHH:mm:ssZ'); // the server's timezone is GMT-4 plus 13 min, in order to sync with the relevant post timestamps in both Facebook and Twitter(TW is 1 min later than FB) blabbbermouth pages + let convertedToLocalTimezone = moment(initialTimestamp + '-03:47', 'YYYY-MM-DDTHH:mm:ss+Z'); // the server's timezone is GMT-4 plus 13 min, in order to sync with the relevant post timestamps in both Facebook and Twitter(TW is 1 min later than FB) blabbbermouth pages publishedTimeLTZ = convertedToLocalTimezone.fromNow(); let format = 'YYYY-MM-DD HH:mm:ss'; publishedTimeLTZtitle = convertedToLocalTimezone.format(format); @@ -65,6 +66,11 @@ function recalc(existingTimestampElement, format, notitle) { } +function onClick(){ + document.querySelector('iframe[title="fb:comments Facebook Social Plugin"]').scrollIntoView(); +} + + // 1. IF ON NEWS PAGES LISTINGS (convertTolocal + apply to pagination) if ( window.location.href.endsWith('blabbermouth.net/') || @@ -87,8 +93,8 @@ if ( if (entry.isIntersecting && !entry.target.classList.contains('in-viewport') ) { entry.target.classList.add('in-viewport'); - var xhr = new XMLHttpRequest(); - var url = entry.target.parentElement.parentElement.firstElementChild.firstElementChild.href; + const xhr = new XMLHttpRequest(); + const url = entry.target.parentElement.parentElement.firstElementChild.firstElementChild.href; xhr.open('GET', url, true); // XMLHttpRequest.open(method, url, async) xhr.onload = function () { @@ -114,7 +120,7 @@ if ( let observer = new IntersectionObserver(callback, options); - var allTimestamps = document.querySelectorAll('span.date-time'); + let allTimestamps = document.querySelectorAll('.news-single span.date'); allTimestamps.forEach((element) => { observer.observe(element); }); @@ -122,13 +128,13 @@ if ( // ---------------------------------------- // Watch for pagination events (when new '.article' children are added inside the '.infinite_scroll' element) - const targetNode2 = document.querySelector('.infinite_scroll'); + const targetNode2 = document.querySelector('.infinite-scroll-component'); const config2 = { attributes: false, childList: true, subtree: false }; const callback2 = function(mutationsList) { for(const mutation of mutationsList) { if (mutation.type === 'childList') { - var allTimestamps = document.querySelectorAll('span.date-time'); + let allTimestamps = document.querySelectorAll('.news-single span.date'); allTimestamps.forEach((element) => { observer.observe(element); }); @@ -140,13 +146,13 @@ if ( observer2.observe(targetNode2, config2); // ---------------------------------------- -// 2+3. ELSE IF ON CD/DVD PAGE REVIEWS ((convertTolocal + generate timestamp) -} else if -(( window.location.href.includes('blabbermouth.net/cdreviews/') || - window.location.href.includes('blabbermouth.net/dvdreviews/') || - window.location.href.includes('blabbermouth.net/news/') ) - && !window.location.href.includes('/page/')) -{ + + // /blabbermouth\.net/\(reviews|news)/i.test(window.location.href) + +// 2+3. ELSE IF ON CD/DVD REVIEWS OR NEWS PAGES ((convertTolocal + generate timestamp) +} else if ( /blabbermouth\.net\/(reviews|news)/i.test(window.location.href) && + !window.location.href.includes('/page/') ) { + //--- Double-check that this iframe is on the expected domain: if (/blabbermouth\.net/i.test(location.host)) { console.log('Userscript is in the MAIN page.'); @@ -154,8 +160,9 @@ if ( // 2019-10-17T15:32:18.000Z + let publishedTimestamp; if (document.querySelector('meta[property="article:published_time"]') !== null) { - var publishedTimestamp = document.querySelector('meta[property="article:published_time"]').content; + publishedTimestamp = document.querySelector('meta[property="article:published_time"]').content; } console.log('publishedTimestamp: ' + publishedTimestamp); @@ -167,7 +174,7 @@ if ( convertToLocalTimezone(publishedTimestamp); - let existingTimestampElement = document.querySelector('.date-time'); + let existingTimestampElement = document.querySelector('div > h1+span.date'); existingTimestampElement.textContent = publishedTimeLTZ; existingTimestampElement.title = publishedTimeLTZtitle; @@ -183,56 +190,50 @@ if ( - if (!window.location.href.includes('blabbermouth.net/news/')){ - - - var currentURL = window.location.href; + if (!window.location.href.includes('blabbermouth.net/news/page/')){ convertToLocalTimezone(publishedTimestamp); var commentcount = '0'; + var datePart = !window.location.href.includes('blabbermouth.net/news/') ? `${publishedTimeLTZ}` : ''; + var HTML = ` -

-${publishedTimeLTZ} - -${commentcount} - -Comments - +${datePart} +

+ +${commentcount} Comments -

+
`; + const refSelector = '.reviews-single-article > div > .reviews-rate-comments,div > h1+span.date'; - if (document.querySelector('.entry-content') !== null) { - document - .querySelector('.entry-content') - .insertAdjacentHTML('beforebegin', HTML); - document.querySelector('.date-time').title = publishedTimeLTZtitle; + if (document.querySelector(refSelector) !== null) { + document.querySelector(refSelector).insertAdjacentHTML('afterend', HTML); + document.querySelector(refSelector).title = publishedTimeLTZtitle; - let newDateTimeElement = document.querySelector('.date-time'); + document.getElementById('commentCount').addEventListener('click', onClick, false); + + let newDateTimeElement = document.querySelector('span.date'); recalc(newDateTimeElement, 'YYYY-MM-DD HH:mm:ss'); } } // Wait for messages [commentcount] (from iframe) - window.addEventListener( - 'message', - function addFbCounter(e) { - // something from an unknown domain, or doesn't contain the string "Comment" let's ignore it - // console.log('Received message: ' + e.data); - if (e.origin !== 'https://www.facebook.com' || e.data.indexOf(' Comment') === -1) { - return; - } - console.log('Received message: ' + e.data); - document.querySelector( - '#main > article > p > span.date-comments > a:nth-child(1), #main header > p > span.date-comments > a:nth-child(1)' - ).innerText = e.data.replace(/ Comments?/i,''); - window.removeEventListener('message', addFbCounter); - }, - false + window.addEventListener('message', function addFbCounter(e) { + // something from an unknown domain, or doesn't contain the string "Comment" let's ignore it + console.log('Received message: ' + e.data); + if (e.origin !== 'https://www.facebook.com' || e.data.indexOf(' Comment') === -1) { + return; + } + console.log('Received message: ' + e.data); + // document.querySelector('#commentCount').innerText = e.data.replace(/ Comments?/i,''); + document.querySelector('#commentCount').innerText = e.data; + window.removeEventListener('message', addFbCounter); + }, + false ); console.log('Waiting for Message 1, from iframe...'); } @@ -245,10 +246,10 @@ if (window.location.href.includes('facebook.com')) { console.log('Userscript is in the FRAMED page.'); - var selector = '._50f7'; + const selector = '._50f7'; // Send commentcount to MAIN page window.parent.postMessage( document.querySelector(selector).innerText, - 'https://www.blabbermouth.net/cdreviews/' + 'https://blabbermouth.net/reviews/' ); } diff --git a/Google_youtube_search_link/Google_youtube_search_link.user.js b/Google_youtube_search_link/Google_youtube_search_link.user.js index f0118d8..e998740 100644 --- a/Google_youtube_search_link/Google_youtube_search_link.user.js +++ b/Google_youtube_search_link/Google_youtube_search_link.user.js @@ -4,7 +4,7 @@ // @author wOxxOm, darkred // @license MIT // @description Adds a YouTube search link next to the Videos link (e.g. Web, Images, Videos, YouTube, News, Maps, Shopping, ...) -// @version 2022.2.11 +// @version 2022.5.27 // @include https://www.google.com/* // @include /https?:\/\/(www\.)?google\.(com|(?:com?\.)?\w\w)\/.*/ // @grant none @@ -27,17 +27,17 @@ function process(mutations) { if (youtube) return; - // var menu = document.querySelector('#hdtb'); // selector for the element that contains all the links (Web, Images, Videos, News, Maps, Shopping, ...) - var menu = document.querySelector('#hdtb, .ndYZfc'); // .ndYZfc is for when Images tab is selected + // Selectors for the bar element that contains all the links (Web, Images, Videos, News, Maps, Shopping, ...) + // '.ndYZfc', is for when the 'Images' tab is selected. The other, '#hdtb', is for all other cases. + var menu = document.querySelector('#hdtb, .ndYZfc'); if (!menu) return; - // var menuContainer = menu.querySelector('#hdtb-msb').parentNode; - var menuContainer = menu.querySelector('#hdtb-msb, .tAcEof').parentNode; // .tAcEof is for when Images tab is selected + 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. if (!youtube) { var q = '', - queryElement = document.querySelector('input[name="q"]'); // selector for the Google search input textbox + queryElement = document.querySelector('input[name="q"]'); // The google search input textbox if (queryElement) { if (queryElement.value) q = encodeURIComponent(queryElement.value); @@ -79,14 +79,16 @@ function process(mutations) { '' + svg + 'YouTube' + ''; - var node = document.querySelector(`a[href*='tbm=vid']`) || document.querySelector('path[d^="M10 16.5l6-4.5-6-4.5"]').closest('span'); + const isVideosTabSelected = !!document.querySelector('.hdtb-mitem.hdtb-msel path[d^="M10 16.5l6-4.5-6-4.5"]'); + 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; - // select the 'Images' selected tab svg icon by its path[d] attribute - var imagesTabElement = document.querySelector('path[d^="M14 13l"]').closest('span.rQEFy'); - if (imagesTabElement) { - text = '' + svg + 'YouTube'; - // select the 'Videos' tab svg icon by its path[d] attribute + // select the (next, non-selected/non-active) 'Videos' tab svg icon by its path[d] attribute node = document.querySelector('path[d^="M10 16.5l6-4.5-6-4.5"]').closest('span'); } diff --git a/Instagram_-_visible_images_counter/Instagram_-_visible_images_counter.user.js b/Instagram_-_visible_images_counter/Instagram_-_visible_images_counter.user.js index 93df7cc..3c5be12 100644 --- a/Instagram_-_visible_images_counter/Instagram_-_visible_images_counter.user.js +++ b/Instagram_-_visible_images_counter/Instagram_-_visible_images_counter.user.js @@ -1,7 +1,7 @@ // ==UserScript== // @name Instagram - visible images counter // @namespace darkred -// @version 2022.2.13 +// @version 2024.2.23 // @description Shows in instagram profile pages how many images out of total (as a number and as a percentage) are currently visible, as you scroll down the page. // @author darkred // @license MIT @@ -14,6 +14,14 @@ /* eslint-disable no-console */ +const escapeHTMLPolicy = (({ trustedTypes }, policy) => + trustedTypes + ? trustedTypes.createPolicy('myEscapePolicy', policy) + : policy)(window, { + createHTML: (str) => str, +}); + + var stylesheet = `