Focus Mode for Social Media

block time-wasting social media & other

// ==UserScript==
// @name        Focus Mode for Social Media
// @namespace   Violentmonkey Scripts
// @include     https://twitter.com/home
// @include     https://www.youtube.com*
// @include     https://www.instagram.com/
// @include     https://github.com/
// @grant       GM_getValue
// @grant       GM_setValue
// @grant       GM_registerMenuCommand
// @grant       GM_unregisterMenuCommand
// @grant       GM_addStyle
// @grant       GM_xmlhttpRequest
// @version     1.2
// @license     MIT
// @author      KraXen72
// @description block time-wasting social media & other
// ==/UserScript==

// TODO externalize these
const getStylesheetUrl = (hostname) => `https://kraxen72.github.io/focus-stylesheets/${hostname}.css`
const site = window.location.hostname
let styleSheetCSS = "";

class Ref {
  constructor(readValue, title) {
    this.v = readValue
    this.title = title
    this.menuCommandCaption = ""
    this.styleTag = GM_addStyle(this.v ? styleSheetCSS : "")
  }
  toggle() {
    console.log("toggl", this)
    const newValue = !(this.v)
    GM_setValue(site, newValue)
    if (!newValue) GM_setValue('lastDate', new Date().toDateString())
    this.v = newValue
    this.styleTag.innerHTML = this.v ? styleSheetCSS : ""
    try { GM_unregisterMenuCommand(this.menuCommandCaption) } catch(e) {}
    this.registerCommand()
    console.log("toggling", this.menuCommandCaption, "new:", this.v)
  }
  registerCommand(title) {
    console.log("registered ref", this)
    const caption = `${this.title}: ${this.v ? '✅' : '❌'}`
    this.menuCommandCaption = caption
    GM_registerMenuCommand(caption, () => this.toggle.apply(this))
  }
}

function useOption(key, title, defaultValue) {
    if (typeof GM_getValue === 'undefined') {
      return {
        value: defaultValue,
      }
    }

    const ref = new Ref(GM_getValue(key, defaultValue), title)
    ref.registerCommand()

    return ref
}

function sameDay(d1, d2) {
  return d1.getFullYear() === d2.getFullYear() &&
    d1.getMonth() === d2.getMonth() &&
    d1.getDate() === d2.getDate();
}

function zeropad(number, finalWidth, customCharacter) {
    customCharacter = customCharacter || '0';
    number = number + '';
    return number.length >= finalWidth ? number : new Array(finalWidth - number.length + 1).join(customCharacter) + number;
}


new Promise((resolve, reject) => GM_xmlhttpRequest({
  url: getStylesheetUrl(site),
  method: 'GET',
  onabort: () => resolve(GM_getValue("css_"+site, "")),
  onerror: () => resolve(GM_getValue("css_"+site, "")),
  onload: (response) => {
    const resText = response.responseText
    GM_setValue("css_"+site, resText)
    resolve(resText)
  }
})).then(data => {
  let currDate = new Date()
  let lastDate = new Date(GM_getValue("lastDate", new Date().setDate(new Date().getDate() - 1)));

  if (site === "www.youtube.com") {
    console.log("yt override kicking in...")
    data = data.replaceAll("%focus%", (currDate.getHours() <= 6) ? `bro go to sleep please it's ${zeropad(currDate.getHours(), 2)}:${zeropad(currDate.getMinutes(), 2)}am` : "focus")
  }

  styleSheetCSS = data

  const focusMode = useOption(site, `focusMode: ${site}`, true)
  console.log("injected", focusMode, styleSheetCSS)

  if (!sameDay(currDate, lastDate) && !focusMode.v) {
    focusMode.toggle()
    GM_setValue('lastDate', new Date().toDateString())
  }
})