RoadToSoftwareFactory / SWI-2019

SWI 1/2 2019/2020
0 stars 19 forks source link

User Script suggestions #66

Open ZitaNemeckova opened 4 years ago

ZitaNemeckova commented 4 years ago

A liitle info https://openuserjs.org/about/Userscript-Beginners-HOWTO

Any suggestion what you'd like to write as a User Script, please write in comments below. Thanks 😺

himdel commented 4 years ago
// ==UserScript==
// @name         wiki test
// @match        https://en.wikipedia.org/wiki/Userscript
// ==/UserScript==

// change document title
document.title = '!@#$%^&*()';

// change element text (article name)
document.querySelector('#firstHeading').innerText = 'Magic';

// change element style (wikipedia logo)
document.querySelector('.mw-wiki-logo').style.backgroundImage = 'url(https://placekitten.com/160/160)';

// remove element (table of contents)
document.querySelector('#toc').remove();
himdel commented 4 years ago

Add CSS (mdn docs):

// ==UserScript==
// @name         wiki test2
// @match        https://en.wikipedia.org/wiki/Userscript
// ==/UserScript==

var sheet = document.styleSheets[0];
sheet.insertRule('#firstHeading { color: blue; }', sheet.cssRules.length);

Or using greasemonkey extensions (note that @grant - tampermonkey docs)..

// ==UserScript==
// @name         wiki test3
// @match        https://en.wikipedia.org/wiki/Userscript
// @grant        GM_addStyle
// ==/UserScript==

// change document style
GM_addStyle(`
  body {
    background-color: red;
  }
`);
himdel commented 4 years ago

More extensions - copy first paragraph of any wikipedia article to clipboard and pop up a notification.. also see @match.

// ==UserScript==
// @name         wiki test4
// @match        https://*.wikipedia.org/wiki/*
// @grant        GM_notification
// @grant        GM_setClipboard
// ==/UserScript==

const text = document.querySelector('.mw-parser-output p').innerText;

GM_setClipboard(text, 'text');
GM_notification(text, 'Copied to clipboard');
himdel commented 4 years ago

Browser APIs - mutation observer - perform action on infiniscroll

// ==UserScript==
// @name         youtube opacity by length
// @match        https://www.youtube.com/watch?v=*
// ==/UserScript==

const playlistSelector = 'ytd-watch-next-secondary-results-renderer';
const itemSelector = 'ytd-compact-video-renderer';

// wait for an element to appear
const waitFor = (selector, callback) => {
  let present = !! document.querySelector(selector);
  if (present) {
    callback();
  } else {
    setTimeout(() => waitFor(selector, callback), 1000);
  }
};

const updateElement = (element) => {
  console.log('video', element.data.videoId, element.data.lengthText.simpleText);

  let short = element.data.lengthText.simpleText.match(/^(\d+):(\d+)$/);
  let long = element.data.lengthText.simpleText.match(/^(\d+):(\d+):(\d+)$/);

  let opacity = 0.1;
  if (short && short[1] == '0') { // under a minute
    opacity = 1;
  } else if (! long) { // less than an hour
    opacity = 1 / Math.sqrt(Number(short[1])); // 1 / sqrt(minutes)
  }

  element.style.opacity = opacity;
};

// wait for inital load
waitFor(playlistSelector, () => {
  // run on load..
  document.querySelectorAll(itemSelector).forEach(updateElement);

  // set up lazy load watching
  const targetNode = document.querySelector(playlistSelector);
  const observerOptions = {
    childList: true,
    subtree: true,
  };
  const callback = function(mutationList, observer) {
    mutationList.forEach((mutation) => {
      const matchingElements = Array.from(mutation.addedNodes || []).filter((e) => e.matches && e.matches(itemSelector));
      matchingElements.forEach(updateElement);
    });
  };

  const observer = new MutationObserver(callback);
  observer.observe(targetNode, observerOptions);
});

(mention console.dir, native web components)

himdel commented 4 years ago

Add own elements, actions..

// ==UserScript==
// @name         youtube seen
// @match        https://www.youtube.com/watch?v=*
// ==/UserScript==

const playlistSelector = 'ytd-watch-next-secondary-results-renderer';
const itemSelector = 'ytd-compact-video-renderer';

// wait for an element to appear
const waitFor = (selector, callback) => {
  let present = !! document.querySelector(selector);
  if (present) {
    callback();
  } else {
    setTimeout(() => waitFor(selector, callback), 1000);
  }
};

const updateElement = (element) => {
  const seen = new Set(JSON.parse(window.localStorage.seen || '[]'));
  if (seen.has(element.data.videoId)) {
    // element.remove();
    element.style.opacity = 0.5;
  }
};

const markSeen = (video) => {
  const seen = JSON.parse(window.localStorage.seen || '[]');
  seen.push(video);
  window.localStorage.seen = JSON.stringify(seen);
};

const addButton = () => {
  const params = window.location.search.substring(1).split('&').map((str) => str.split('=').map((s) => decodeURIComponent(s))).map(([a, b]) => ({[a]: b})).reduce((o,r) => ({...r, ...o}), {});

  const title = document.querySelector('.title.ytd-video-primary-info-renderer');
  const button = document.createElement('button');
  button.textContent = "Mark as seen";
  button.onclick = () => {
    markSeen(params.v);
    button.disabled = true;
  };

  // already seen
  if ((new Set(JSON.parse(window.localStorage.seen || '[]'))).has(params.v)) {
    button.textContent = "(seen)";
    button.disabled = true;
  }

  title.append(button);
};

waitFor('ytd-video-primary-info-renderer', addButton);

// wait for inital load
waitFor(playlistSelector, () => {
  // run on load..
  document.querySelectorAll(itemSelector).forEach(updateElement);

  // set up lazy load watching
  const targetNode = document.querySelector(playlistSelector);
  const observerOptions = {
    childList: true,
    subtree: true,
  };
  const callback = function(mutationList, observer) {
    mutationList.forEach((mutation) => {
      const matchingElements = Array.from(mutation.addedNodes || []).filter((e) => e.matches && e.matches(itemSelector));
      matchingElements.forEach(updateElement);
    });
  };

  const observer = new MutationObserver(callback);
  observer.observe(targetNode, observerOptions);
});

(diff:

--- a   2020-03-23 23:11:04.031747349 +0000
+++ b   2020-03-23 23:11:17.167840372 +0000
@@ -1,5 +1,5 @@
 // ==UserScript==
-// @name         youtube opacity by length
+// @name         youtube seen
 // @match        https://www.youtube.com/watch?v=*
 // ==/UserScript==

@@ -17,21 +17,41 @@
 };

 const updateElement = (element) => {
-  console.log('video', element.data.videoId, element.data.lengthText.simpleText);
-
-  let short = element.data.lengthText.simpleText.match(/^(\d+):(\d+)$/);
-  let long = element.data.lengthText.simpleText.match(/^(\d+):(\d+):(\d+)$/);
-
-  let opacity = 0.1;
-  if (short && short[1] == '0') { // under a minute
-    opacity = 1;
-  } else if (! long) { // less than an hour
-    opacity = 1 / Math.sqrt(Number(short[1])); // 1 / sqrt(minutes)
-  }
-
-  element.style.opacity = opacity;
+  const seen = new Set(JSON.parse(window.localStorage.seen || '[]'));
+  if (seen.has(element.data.videoId)) {
+    // element.remove();
+    element.style.opacity = 0.5;
+  }
 };

+const markSeen = (video) => {
+  const seen = JSON.parse(window.localStorage.seen || '[]');
+  seen.push(video);
+  window.localStorage.seen = JSON.stringify(seen);
+};
+
+const addButton = () => {
+  const params = window.location.search.substring(1).split('&').map((str) => str.split('=').map((s) => decodeURIComponent(s))).map(([a, b]) => ({[a]: b})).reduce((o,r) => ({...r, ...o}), {});
+
+  const title = document.querySelector('.title.ytd-video-primary-info-renderer');
+  const button = document.createElement('button');
+  button.textContent = "Mark as seen";
+  button.onclick = () => {
+    markSeen(params.v);
+    button.disabled = true;
+  };
+
+  // already seen
+  if ((new Set(JSON.parse(window.localStorage.seen || '[]'))).has(params.v)) {
+    button.textContent = "(seen)";
+    button.disabled = true;
+  }
+ 
+  title.append(button);
+};
+
+waitFor('ytd-video-primary-info-renderer', addButton);
+
 // wait for inital load
 waitFor(playlistSelector, () => {
   // run on load..

)

himdel commented 4 years ago

More examples..

damejidlo - Resort restaurant by reddit order (more votes is more important than better votes): https://github.com/himdel/dotfiles/blob/master/userjs/damejidlo.sort.js

flickr - Download button: https://github.com/himdel/dotfiles/blob/master/userjs/flickr.user.js

chrome - skip Redirect Notice on google lucky: https://github.com/himdel/dotfiles/blob/master/userjs/google%20lucky%20fix.user.js

xkcd - use keys, show caption : https://github.com/himdel/dotfiles/blob/master/userjs/xkcd_next.user.js