# My Google Chrome Extensions.md
# Copyright (c) 2022-2024 Evandro Coan
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
-
chrome://discards/
-
chrome://settings/?search=memory+saver
-
chrome://flags/#modal-memory-saver
-
chrome://flags/#probabilistic-memory-saver
-
chrome://flags/#memory-saver-multi-state-mode
-
- Stops Chrome from suspending tabs, and reloading them when you switch to them.
-
- https://www.chanhvuong.com/3954/disable-annoying-chrome-media-control-key-extension-to-windows-10-volume-osd/
- Using Chrome, browse to “chrome://flags/” to access the experimental hidden settings.
- Search for the “Hardware Media Key Handling” function.
- Disable it by changing the dropdown selection from Default to Disabled.
- Click the “Relaunch Now” button on the popup at the bottom.
-
Read Aloud: A Text to Speech Voice Reader
- lsdsoftware.com: Read aloud the current web-page article with one click, using text to speech (TTS). Supports 40+ languages.
-
Lazy Tabs
- Discard all inactive tabs (except pinned) at startup or by clicking an icon
-
NordVPN - VPN proxy for privacy and security
- Connect to the fastest VPN out there — NordVPN. Hide your IP, block ads, and be safe online with our VPN proxy extension for Chrome.
-
Enhancer for Netflix, Crunchyroll
- Show trailers, IMDb/Simkl ratings, secret categories and much more, on the Netflix page. Sync Netflix or Crunchyroll to Simkl.
-
Postman
- Postman is an American application that allows the testing of web APIs.
-
YouTube Auto HD + FPS
- Automatically set the video quality on YouTube according to its FPS!
-
Web Scrobbler
- Scrobble music all around the web!
-
- A Chrome extension which can perform per-tab/per-origin/per-path zooming
-
- Shows notifications of all added discourse forum sites. Version 1.1.4
- https://meta.discourse.org/t/discourse-push-notifications-for-desktop/86941
-
- Open Drive files directly from your browser in compatible applications installed on your computer.
-
- Capture a screenshot of your current page in entirety and reliably—without requesting any extra permissions!
-
- Automatically adds repository size to GitHub's repository summary
- Stop Backspace returning to previous page
- Get things done offline with the Google Docs family of products.
- Renders an isometric pixel view of GitHub contribution graphs.
- Displays your GitHub notifications unread count
- Open links in new tab for a list of specified domains. Useful for sites such as hackernews
- Restores the 'Mute Tab' functionality of versions prior to Chrome 71.
- Pocket Extension for Chrome - The best way to save articles, videos and more
- Custom keyboard shortcuts for your browser
- A speed dial functionally similar to the one used in Opera.
- Ultra light new tab with bookmark navigator
- Scrobble music all around the web!
- Manage Browser Tabs and Bookmarks with Ease
- Passively highlights occurrences of selected text. Maintains current text selection.
- Disable autoplay and preloading of HTML5 video and audio players.
- Multiple label and account notifier for Google Mail (Gmail)
- Easily change your timezone to a desired value and protect your privacy.
- Make scroll behavior smooth, ease-in-out manner, customizable with dynamically plotted curve. With bouncy edge feature.
- Adiciona uma tabela com informações adicionais e a hora estimada de saída do trabalho na pagina de batidas de ponto do ahgora.
- See your next events, get meeting notifications and snooze events without opening the Google Calendar page!
- Inject jQuery into all frames on any page. jQuery Injector allows you to inject jQuery into every frame on a page so that you can use jQuery in the dev console.
- View source code of Chrome extensions, Firefox addons or Opera extensions (crx/nex/xpi) from the Chrome web store and elsewhere.
- Utilities to create and open lists of tabs.
- Quickly copy tabs to the clipboard
- Simplifies the GitHub interface and adds useful features
- Features to disable, by filename:
shorten-links add- move-marketplace-link-to-profile-dropdown set-default-repositories-type-to-sources infinite-scroll hide-useless-comments hide-watch-and-fork-count fit-textareas
- Custom CSS ```css / fix GitHub Actions console output last line being half-cut */ body { line-height: 150%; }
/* Stop adding scroll bar on quoted blocks/images */
/* https://github.com/sindresorhus/refined-github/issues/2491 */
.comment-body blockquote,
.comment-body pre {
max-height: none !important;
overflow-y: visible !important;
}
/* How to remove the sticky issues top bar? */
/* https://github.com/sindresorhus/refined-github/issues/3086 */
.Box-header#js-issues-toolbar,
.Box#js-issues-toolbar > .Box-header {
position: relative;
}
```
-
- The world's most popular userscript manager
- https://github.com/CertainPerformance/Stack-Exchange-Userscripts/raw/master/Preview-Antifocus/StackPreviewAntifocus.user.js
- https://github.com/CertainPerformance/Stack-Exchange-Userscripts/raw/master/Three-Columns/dist/StackThreeColumns.user.js
- https://stackapps.com/questions/4486/the-stack-overflow-unofficial-patch-soup
-
// ==UserScript== // @name Auto scroll gitlab ci log // @namespace * // @version 0.1 // @description ... // @author Evandro Coan // // @include http*://gitlab* // // @require http://code.jquery.com/jquery-3.4.1.min.js // ==/UserScript== // // https://gitlab.com/gitlab-org/gitlab/-/issues/37313 - Job Log Page is no longer auto scrolling to the bottom // https://stackoverflow.com/questions/3898130/check-if-a-user-has-scrolled-to-the-bottom/3898152 // (function() { 'use strict'; function getDocHeight() { var D = document; return Math.max( D.body.scrollHeight, D.documentElement.scrollHeight, D.body.offsetHeight, D.documentElement.offsetHeight, D.body.clientHeight, D.documentElement.clientHeight ); } setInterval(function(){ if($(window).scrollTop() + $(window).height() > getDocHeight() - 300) { $('button[data-testid="job-controller-scroll-bottom"]').click(); } }, 1000); })();
-
// ==UserScript== // @name Fix chatgpt auto-scrolling by always adding 500px at the bottom // @namespace http://tampermonkey.net/ // @version 0.1 // @description Modify the height of the last HTML element with a data-testid attribute // @author You // @match https://chat.openai.com/* // @grant none // ==/UserScript== (function() { 'use strict'; function setElementHeight() { //let elements = document.querySelectorAll('[data-role="assistant"]'); // use for superpower chatgpt chrome extension let elements = document.querySelectorAll('[data-testid^="conversation-turn"]'); // use for chatgpt vanilla let heightJump = 500; let jumpTimeoutInSeconds = 30; let lastElement = elements[elements.length - 1]; if (lastElement) { let height = lastElement.scrollHeight || -1; let setMinHeight = parseInt(lastElement.style.minHeight, 10) || -1; let lastHeight = parseInt(lastElement.getAttribute("data-last-scrool"), 10) || height; let lastHeightCount = parseInt(lastElement.getAttribute("data-last-scrool-count"), 10) || 0; // console.log(`height ${height}, lastHeight ${lastHeight}, setMinHeight ${setMinHeight}, lastHeightCount ${lastHeightCount}.`) if (height > lastHeight) { height += heightJump; lastElement.style.minHeight = `${height}px`; } if( height == lastHeight ) { if(lastHeightCount > jumpTimeoutInSeconds) { // console.log(`Reseting height ${height} ${lastHeightCount}.`) lastElement.style.minHeight = `auto`; } lastHeightCount += 1; } else { lastHeightCount = 0; } lastElement.setAttribute("data-last-scrool", height); lastElement.setAttribute("data-last-scrool-count", lastHeightCount); } let penultiLastElement = elements[elements.length - 2]; let penultiLastElement2 = elements[elements.length - 3]; if (penultiLastElement) { penultiLastElement.style.minHeight = `auto`; } if (penultiLastElement2) { penultiLastElement2.style.minHeight = `auto`; } let chatTypeHeaders = document.querySelectorAll('header.sticky.top-0'); if(chatTypeHeaders) { chatTypeHeaders.forEach((chatTypeHeader) => { chatTypeHeader.className = ""; }); } } setInterval(setElementHeight, 1000); })();
-
// ==UserScript== // @name Fix GitHub snippet edit small size // @namespace http://tampermonkey.net/ // @version 0.1 // @description try to take over the world! // @author You // @match https://gist.github.com/evandrocoan/* // @require http://code.jquery.com/jquery-3.4.1.min.js // ==/UserScript== (function() { 'use strict'; let keepclosing = async () => { let viewedbar = $('div[class="CodeMirror cm-s-github-light CodeMirror-wrap"]').not('span[data-donot-process-this-again]'); // console.log('running'); // console.log(viewedbar); if(viewedbar.length) { viewedbar.css("height", "700px"); viewedbar.attr('data-donot-process-this-again', true); } setTimeout(keepclosing, 500); } setTimeout(keepclosing, 500); })();
-
// ==UserScript== // @name Force GMail Archive button to go to back after clicking on it // @namespace * // @version 0.1 // @description Force GMail Archive button to go to back after clicking on it // @author Evandro Coan // // @include https://mail.google.com/* // @require http://code.jquery.com/jquery-3.4.1.min.js // ==/UserScript== (function() { 'use strict'; let keepclosing = async () => { let viewedbar = $('div[data-tooltip="Archive"][tabindex="0"]').not('span[data-donot-process-this-again]'); // console.log('running'); // console.log(viewedbar); if(viewedbar.length) { let previousItem = function() { // let viewedbar = $('div[data-tooltip][tabindex="0"][role="button"]').filter(function() { // return $(this).attr('data-tooltip').match(/.*Back.*/); // }); let viewedbar = $('div[data-tooltip="All Mail"]'); if(viewedbar.length) { viewedbar.click(); } return false; }; viewedbar.on('click', previousItem); viewedbar.attr('data-donot-process-this-again', true); } setTimeout(keepclosing, 500); } setTimeout(keepclosing, 500); let keepopening = async () => { let expandbutton = $('div[data-tooltip="Show trimmed content"][aria-expanded="false"]'); setTimeout(keepopening, 500); if( expandbutton.length ) { expandbutton.click(); } } setTimeout(keepopening, 500); let keepremovingsearchbar = async () => { let expandbutton = $('div[aria-label="search refinement"]'); let divsizetofix = $('div[gh="tm"]'); setTimeout(keepremovingsearchbar, 500); divsizetofix.css("height", "30px"); expandbutton.remove(); } setTimeout(keepremovingsearchbar, 500); })();
-
// ==UserScript== // @name Force GMail Archive refresh page every 5 seconds // @namespace * // @version 0.1 // @description This is because on Linux the page some times takes long time to refresh // @author Evandro Coan // // @include https://mail.google.com/* // @require http://code.jquery.com/jquery-3.4.1.min.js // ==/UserScript== (function() { 'use strict'; let keepclosing = async () => { let viewedbar = $('div[aria-label="Refresh"]'); if(viewedbar.length) { console.log('Clicking refresh'); viewedbar.click(); } else { console.log(viewedbar); } } setInterval(keepclosing, 5000); })();
-
// ==UserScript== // @name Remove youtube channels main image // @namespace * // @version 0.1 // @description https://stackoverflow.com/questions/60480918/how-to-simulate-click-in-react-app-using-tampermonkey // @author You // // @include https://*youtube.com/* // @require http://code.jquery.com/jquery-3.4.1.min.js // ==/UserScript== (function() { 'use strict'; let keepclosing = async () => { let menubuttons = $('tp-yt-paper-tab'); if( menubuttons.length ) { let background_div = $('div[id=background]'); if(background_div.length) { background_div.remove(); } let topbardiv = $('div[class="style-scope tp-yt-app-header"]'); if(topbardiv.length) { topbardiv.css("padding-top", "0px"); } let topbardiv2 = $('div[id="contents"]div[class="style-scope ytd-section-list-renderer"]'); if(topbardiv2.length) { topbardiv2.css("padding-top", "50px"); // topbardiv2.css("padding-top", "0px"); } let topbardivbanner = $('div[class="banner-visible-area style-scope ytd-c4-tabbed-header-renderer"]'); if(topbardivbanner.length) { topbardivbanner.remove(); } let topbardivsize = $('div[id=header][class="style-scope ytd-browse"]'); if(topbardivsize.length) { topbardivsize.css("height", "150px"); // topbardivsize.css("height", "0px"); } let topbardivjoinbar = $('ytd-recognition-shelf-renderer[class="style-scope ytd-item-section-renderer"]'); if(topbardivjoinbar.length) { topbardivjoinbar.hide(); } let topghostdiv = $('div[id=contentContainer][class="style-scope tp-yt-app-header-layout"]'); if(topghostdiv.length) { topghostdiv.hide(); } // Unpin the main big bar (by putting it inside the main body) // use 5 seconds to avoid delay to avoid unfocusing the search button type field each second //if( $('div[id="contents"]div[class="style-scope ytd-section-list-renderer"] > div[class="style-scope tp-yt-app-header"]').length < 0 ) { //} } setTimeout(keepclosing, 5000); } setTimeout(keepclosing, 5000); })();
-
// ==UserScript== // @name Remove youtube channels logo and always show all videos // @namespace * // @version 0.1 // @description https://stackoverflow.com/questions/60480918/how-to-simulate-click-in-react-app-using-tampermonkey // @author You // // @include https://*youtube.com/* // @exclude https://*youtube.com/*/TucaLoretti/* // @exclude https://*youtube.com/*/UC1__NTyvkBZElGBK1qmtoMg/* // @require http://code.jquery.com/jquery-3.4.1.min.js // ==/UserScript== (function() { 'use strict'; let keepclosing = async () => { let menubuttons = $('tp-yt-paper-tab'); if( menubuttons.length ) { // console.log("removing running..."); let videosButton = menubuttons[1]; let ariaSelected = $(videosButton).attr('aria-selected'); // console.log(`ariaSelected ${ariaSelected}`); if( ariaSelected == 'false' ) { menubuttons[1].click(); } // delete youtube useless top bar/logo let topbar = $('.style-scope.ytd-c4-tabbed-header-renderer'); if(topbar.length) { topbar.hide(); } } setTimeout(keepclosing, 1000); } setTimeout(keepclosing, 1000); })();
-
// ==UserScript== // @name Always click youtube show more (channels button) // @namespace * // @version 0.1 // @description https://stackoverflow.com/questions/60480918/how-to-simulate-click-in-react-app-using-tampermonkey // @author You // // @include https://*youtube.com/* // @exclude https://*youtube.com/*/TucaLoretti/* // @exclude https://*youtube.com/*/UC1__NTyvkBZElGBK1qmtoMg/* // @require http://code.jquery.com/jquery-3.4.1.min.js // ==/UserScript== (function() { 'use strict'; let showmoreregex = new RegExp("Show \\d+ more"); // expression here let keepclosing = async () => { let showmorebutton = $('yt-formatted-string[class="title style-scope ytd-guide-entry-renderer"]').filter(function () { return showmoreregex.test($(this).text()); }); // console.log(`showmorebutton ${showmorebutton.text()}`); if( showmorebutton.length ) { showmorebutton[0].click(); showmorebutton.remove(); } setTimeout(keepclosing, 1000); } setTimeout(keepclosing, 1000); })();
-
// ==UserScript== // @name Remove genius lyrics side bars (to copy lyrics without their text) // @namespace * // @version 0.1 // @description https://webapps.stackexchange.com/questions/145612/how-to-stop-the // @author You // // @include https://genius.com/* // @require http://code.jquery.com/jquery-3.4.1.min.js // ==/UserScript== (function() { 'use strict'; let keepclosing = async () => { let viewedbar = $('.RightSidebar__Container-pajcl2-0'); if(viewedbar.length) { // console.log("removing running..."); // use hide instead of remove to avoid mass flickering of the page viewedbar.hide(); } // console.log("running"); setTimeout(keepclosing, 500); } setTimeout(keepclosing, 500); })();
-
// ==UserScript== // @name Remove youtube viewed videos // @namespace * // @version 0.1 // @description https://webapps.stackexchange.com/questions/145612/how-to-stop-the // @author You // // @include https://*youtube.com/* // @require http://code.jquery.com/jquery-3.4.1.min.js // ==/UserScript== (function() { 'use strict'; let keepclosing = async () => { let viewedbar = $('.style-scope.ytd-thumbnail-overlay-resume-playback-renderer'); if(viewedbar.length) { // console.log("removing running..."); let parent = viewedbar.closest('.style-scope.ytd-rich-grid-renderer'); if(parent.length) { // use hide instead of remove to avoid mass flickering of the page parent.hide(); } } // console.log("running"); setTimeout(keepclosing, 500); } setTimeout(keepclosing, 500); })();
-
// ==UserScript== // @name Remove crunchyroll simulcastcalendar dub videos // @namespace * // @version 0.1 // @description https://webapps.stackexchange.com/questions/145612/how-to-stop-the // @author You // // @include https://*crunchyroll*/simulcastcalendar* // @require http://code.jquery.com/jquery-3.4.1.min.js // ==/UserScript== (function() { 'use strict'; let keepclosing = async () => { let viewedbar = $('cite:contains(" Dub)")'); if(viewedbar.length) { // console.log("removing running..."); let parent = viewedbar.closest('li'); if(parent.length) { // use hide instead of remove to avoid mass flickering of the page parent.hide(); } } // console.log("running"); // setTimeout(keepclosing, 500); } setTimeout(keepclosing, 1500); })();
-
// ==UserScript== // @name Close GitHub Notifications bar // @namespace * // @version 0.1 // @description https://github.com/sindresorhus/refined-github/issues/3061 // https://gist.github.com/evandrocoan/0e25dd233f3f99352a8147041809ba8d // // @author You // @include http://*github.com/* // @include https://*github.com/* // @require http://code.jquery.com/jquery-3.4.1.min.js // ==/UserScript== (function() { 'use strict'; clickButton('button[aria-label="Close notification controls"].js-flash-close'); deleteElement('.js-sticky.js-sticky-offset-scroll.top-0.gh-header-sticky.is-stuck'); // http://en.enisozgen.com/hide-github-academic-discount-coupon-error/ deleteElement('.flash.flash-full.js-notice.flash-error'); function deleteElement(selector) { let delayed = () => { let element = $(String(selector)); if(element.length) { console.log(`Deleting '${element.text().replace(/\s+/g, ' ').trim()}' button`); element.remove(); } setTimeout(delayed, 2000); } setTimeout(delayed, 2000); } function clickButton(selector) { let delayed = () => { let element = $(String(selector)); if(element.length) { console.log(`Closing element '${element.html()}' button`); element.click(); } setTimeout(delayed, 2000); } setTimeout(delayed, 2000); } })();
-
// ==UserScript== // @name Close Stackexchange Up Vote Notifications bar // @namespace * // @version 0.1 // @description https://github.com/sindresorhus/refined-github/issues/3061 // @author You // https://meta.stackexchange.com/questions/81379/can-we-have-a-list-of-all // @description https://github.com/sindresorhus/refined-github/issues/3061 // @include https://*askubuntu.com/* // @include https://*mathoverflow.net/* // @include https://*blogoverflow.com/* // @include https://*serverfault.com/* // @include https://*stackoverflow.com/* // @include https://*stackexchange.com/* // @include https://*stackapps.com/* // @include https://*stackmod.blog/* // @include https://*stackoverflow.blog/* // @include https://*stackoverflowbusiness.com/* // @include https://*superuser.com/* // @include https://*tex-talk.net/* // @include https://*thesffblog.com/* // @require http://code.jquery.com/jquery-3.4.1.min.js // ==/UserScript== (function() { 'use strict'; let keepclosing = async () => { let closebutton = $('#overlay-header'); if(closebutton.length) { console.log('Close Stackexchange Up Vote Notifications bar'); closebutton.remove(); setTimeout(keepclosing, 2000); } let begteampromotion = $('.teams-promo.overflow-hidden.z-active.bs-md.bg-black-750.fc-white.fs-body2.js-teams-promo'); if(begteampromotion.length) { console.log('Close Stackexchange Team Bag Notifications bar'); begteampromotion.remove(); } let beg_banner_bookmark = $('aside[class="s-notice s-notice__success"]'); if(beg_banner_bookmark.length) { console.log('Close Stackexchange Bookmark Notifications bar'); beg_banner_bookmark.hide(); setTimeout(keepclosing, 2000); } } setTimeout(keepclosing, 2000); })();
-
// ==UserScript== // @name Close Lastfm player bar // @namespace * // @version 0.1 // @description https://github.com/sindresorhus/refined-github/issues/3061 // @author You // https://meta.stackexchange.com/questions/81379/can-we-have-a-list-of-all // @include https://*last.fm/* // @require http://code.jquery.com/jquery-3.4.1.min.js // ==/UserScript== let things = ` // https://stackoverflow.com/questions/7474354/include-jquery-in-the-javascript-console var jq = document.createElement('script'); jq.src = "https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"; document.getElementsByTagName('head')[0].appendChild(jq); // ... give time for script to load, then type (or see below for non wait option) jQuery.noConflict(); `; (function() { 'use strict'; deleteElement('div[data-more-string="More…"].navlist.navlist--more.masthead-nav.hidden-xs'); deleteElement('.masthead-logo'); deleteElement('.top-bar'); function deleteElement(selector) { let delayed = () => { // Avoid reprocessing when on background/not focused if (document.hasFocus()) { // console.log('Tab is active'); } else { // console.log('Tab is not active'); setTimeout(delayed, 1000); return; } let element = $(String(selector)); if(element.length) { console.log(`Deleting element '${element.text().replace(/\s+/g, ' ').trim()}' button`); element.remove(); } setTimeout(delayed, 2000); } setTimeout(delayed, 200); } $('#content').css({'padding-top': '0px'}); if( String(window.location.href).toLowerCase().includes('ironhead4life') ) { setTimeout(fixScrobleLink, 1000); } function fixScrobleLink() { // Avoid reprocessing when on background/not focused if (document.hasFocus()) { // console.log('Tab is active'); } else { // console.log('Tab is not active'); setTimeout(fixScrobleLink, 1000); return; } $('.chartlist-name>a').each(function(index, item) { // console.log(index) let newitem = $(item).attr('href'); if( ! String(newitem).includes('IronHead4Life') ) { let newitemsrc = String(newitem).replace('/music/', '/user/IronHead4Life/library/music/'); // console.log(newitemsrc); $(item).attr('href', newitemsrc); $(item).attr ('target', '_blank'); } }); setTimeout(fixScrobleLink, 1000); } })();
-
// ==UserScript== // @name Force all short videos to open as a normal video! // @namespace * // @version 0.1 // @description https://stackoverflow.com/questions/60480918/how-to-simulate-click-in-react-app-using-tampermonkey // @author You // // @include https://*youtube.com/* // @require http://code.jquery.com/jquery-3.4.1.min.js // ==/UserScript== (function() { 'use strict'; let keepclosing = async () => { let viewedbar = $('a[href*="/shorts"]'); // console.log('running'); // console.log(viewedbar); if(viewedbar.length) { $(viewedbar).each(function(index, item) { // console.log(index) let newitem = $(item).attr('href'); let newitemsrc = String(newitem).replace('/shorts/', '/watch?v='); // console.log(newitemsrc); $(item).attr('rel', `noopener noreferrer`); //$(item).attr('target', `_blank`); $(item).attr('onclick', ` if( '${newitemsrc}' != this.getAttribute('href')) return; window.open('${newitemsrc}', ''); setTimeout(function(){ history.back(); }, 500); return false; `); $(item).removeAttr('href'); $(item).attr('href', newitemsrc); //$(item).attr('data-saferedirecturl', newitemsrc); }) } setTimeout(keepclosing, 500); } setTimeout(keepclosing, 500); })();
-
// ==UserScript== // @name jisho add copy button to meanings-wrapper elements // @namespace your-namespace // @version 1 // @description Add a button to all elements with the class "meanings-wrapper" // @match *://jisho.org/* // @grant none // ==/UserScript== (function() { 'use strict'; function copyToClipboard(docCopy) { const meaningTags = docCopy.querySelectorAll('.meaning-tags'); for (let i = 0; i < meaningTags.length; i++) { const tagContent = meaningTags[i].textContent; if (tagContent) { const newTag = document.createElement('span'); newTag.style.color = 'rgb(0, 128, 0)'; newTag.innerHTML = tagContent + ') '; newTag.classList = meaningTags[i].classList; meaningTags[i].parentNode.insertBefore(newTag, meaningTags[i]); meaningTags[i].parentNode.removeChild(meaningTags[i]); } } const meaningDefinitions = docCopy.querySelectorAll('.meaning-definition'); for (let i = 0; i < meaningDefinitions.length; i++) { const meaningDefinition = meaningDefinitions[i]; // remove `class="meaning-definition-section_divider"` and its contents const sectionDivider = meaningDefinition.querySelector('.meaning-definition-section_divider'); if (sectionDivider) { sectionDivider.parentNode.removeChild(sectionDivider); } } // before the `class="supplemental_info"` and after `class="meaning-meaning` span tag closes, add `: ` const spanElements = docCopy.querySelectorAll('span'); for (let i = 0; i < spanElements.length; i++) { const spanElement = spanElements[i]; if( !spanElement.parentNode ) { continue; } // remove <span class="hit">円</span> but keep the contents const hitElement = spanElement.querySelector('.hit'); if(hitElement) { const textNode = document.createTextNode(hitElement.textContent); hitElement.parentNode.replaceChild(textNode, hitElement); } if (spanElement.textContent === '') { const textNode = document.createTextNode(': '); spanElement.parentNode.replaceChild(textNode, spanElement); } } // replace `ul class="japanese` and its contents with new formating using `<ruby><rb>kanji</rb><rt>furigana</rt></ruby>` const japaneseLists = docCopy.querySelectorAll('.japanese'); for (let i = 0; i < japaneseLists.length; i++) { const japaneseListItems = japaneseLists[i].querySelectorAll('li'); for (let j = 0; j < japaneseListItems.length; j++) { const japaneseListItem = japaneseListItems[j]; const kanji = japaneseListItem.querySelector('.unlinked'); const furigana = japaneseListItem.querySelector('.furigana'); if (kanji && furigana) { const ruby = document.createElement('ruby'); const rt = document.createElement('rt'); rt.innerHTML = furigana.innerHTML; if(kanji.innerHTML != kanji.textContent) { throw new Error(`${kanji.innerHTML} != ${kanji.textContent}`); } // fix jisho bug where kanji is not separated from kana let kanaList = []; let kanjiList = []; for (let i = 0; i < kanji.textContent.length; i++) { const character = kanji.textContent.charAt(i); if (/[\u3040-\u309F\u30A0-\u30FF]/g.test(character)) { kanaList.push(character); } else { kanjiList.push(character); } } ruby.insertAdjacentHTML('beforeend', kanjiList.join('')); ruby.appendChild(rt); ruby.insertAdjacentHTML('beforeend', kanaList.join('')); japaneseListItem.innerHTML = ''; japaneseListItem.appendChild(ruby); } else if(kanji) { const ruby = document.createElement('ruby'); const rt = document.createElement('rt'); ruby.insertAdjacentHTML('beforeend', kanji.innerHTML) ruby.appendChild(rt); japaneseListItem.innerHTML = ''; japaneseListItem.appendChild(ruby); } } } // add `<br/>` after `class="meaning-wrapper"` contents but not if it is the last one const meaningWrappers = docCopy.querySelectorAll('.meaning-wrapper'); for (let i = 0; i < meaningWrappers.length; i++) { const meaningWrapper = meaningWrappers[i]; const contents = meaningWrapper.innerHTML; if (i < meaningWrappers.length - 1) { meaningWrapper.insertAdjacentElement('afterEnd', document.createElement('br')); } // remove ul and li but keep its contents const sentences = meaningWrapper.querySelector('.sentences'); if(!sentences) { continue; } const japanese = sentences.querySelector('.japanese'); const japaneseListItems = japanese.childNodes; const japaneseListItemContents = []; for(let i = 0; i < japaneseListItems.length; i++) { const japaneseListItem = japaneseListItems[i]; if(japaneseListItem.nodeType === Node.TEXT_NODE) { japaneseListItemContents.push(japaneseListItem.textContent); } else { japaneseListItemContents.push(japaneseListItem.innerHTML); } }; const newHtml = document.createElement('span'); newHtml.innerHTML = japaneseListItemContents.join(''); newHtml.classList = 'japanese-chars'; japanese.parentElement.replaceChild(newHtml, japanese); } // move `class="english"` contents from inside `class="sentence"` to after it const sentences = docCopy.querySelectorAll('.sentence'); for (let i = 0; i < sentences.length; i++) { const sentence = sentences[i]; const english = sentence.querySelector('.english'); if (english) { const englishText = english.textContent; sentence.removeChild(english); const newSpan = document.createElement('span'); newSpan.classList.add('japanese-english'); newSpan.textContent = englishText; sentence.parentNode.appendChild(newSpan); } } // replace all `div` tags by `span`, except the class="meaning-tags" div let divs = docCopy.querySelectorAll('div'); while (divs.length > 0) { for (let i = 0; i < divs.length; i++) { const div = divs[i]; const span = document.createElement('span'); span.innerHTML = div.innerHTML; div.parentNode.replaceChild(span, div); } divs = docCopy.querySelectorAll('div'); } // prefix href=/search with 'https://jisho.org/' const links = docCopy.querySelectorAll('[href^="/"]'); links.forEach(function(link) { const href = link.getAttribute('href'); link.setAttribute('href', 'https://jisho.org' + href); }); const removeButtons = docCopy.querySelectorAll('.remove-this-button'); removeButtons.forEach(button => { button.remove(); }); const html = docCopy.innerHTML; navigator.clipboard.writeText(html) .then(() => { if (Notification.permission === 'granted') { const notification = new Notification('HTML copied to clipboard', { body: 'The HTML has been copied to the clipboard.', }); setTimeout(() => { notification.close(); }, 3000); } else if (Notification.permission !== 'denied') { Notification.requestPermission().then(permission => { if (permission === 'granted') { const notification = new Notification('HTML copied to clipboard', { body: 'The HTML has been copied to the clipboard.', }); setTimeout(() => { notification.close(); }, 3000); } else { alert('Clipboard copy notification show denied'); } }); } }) .catch(err => { alert('Failed to copy HTML: ', err); }); } let keepclosing = async () => { const meaningsWrappers = document.querySelectorAll('.meanings-wrapper:not(.remove-this-button)'); meaningsWrappers.forEach(meaningsWrapper => { meaningsWrapper.classList.add('remove-this-button'); const button = document.createElement('button'); button.innerText = 'Copy'; button.classList = 'remove-this-button'; button.addEventListener('click', ()=> copyToClipboard(meaningsWrapper.cloneNode(true))); meaningsWrapper.appendChild(button); }); setTimeout(keepclosing, 500); } setTimeout(keepclosing, 500); })();
-
// ==UserScript== // @name Move weather.com real feel temperature side-by-side with temperature // @namespace http://tampermonkey.net/ // @version 2024-01-10 // @description try to take over the world! // @author You // @match https://weather.com/weather/hourbyhour/* // @icon https://www.google.com/s2/favicons?sz=64&domain=weather.com // @require http://code.jquery.com/jquery-3.4.1.min.js // @grant none // ==/UserScript== (function() { 'use strict'; setInterval(function(){ let temperatures = $('span[data-testid="TemperatureValue"]'); if( temperatures.length && temperatures[0].textContent.includes('/') ) { temperatures = temperatures.not('span[data-donot-process-this-again]'); } for (let index = 0; index < temperatures.length; index+=2) { let main_temperature = $(temperatures[index]); let real_feel = $(temperatures[index+1]); main_temperature.append(` / ${real_feel.text()}`) real_feel.attr('data-donot-process-this-again', true); main_temperature.attr('data-donot-process-this-again', true); } let percentages = $('span[data-testid="PercentageValue"]').not('span[data-donot-process-this-again]'); for (let index = 0; index < percentages.length; index+=3) { let rain_probability = $(percentages[index]); let humidity_percentage = $(percentages[index+1]); let cloud_clover = $(percentages[index+2]); rain_probability.append(` ${humidity_percentage.text()} ${cloud_clover.text()}`) rain_probability.attr('data-donot-process-this-again', true); humidity_percentage.attr('data-donot-process-this-again', true); cloud_clover.attr('data-donot-process-this-again', true); } }, 1000); })();