Greasy Fork is available in English.

how long ago

replaces all dates with the time from that date

// ==UserScript==
// @name         how long ago
// @version      3
// @description  replaces all dates with the time from that date
// @run-at       document-end
// @author       You
// @license      GPLv3
// @match        *://*/*
// @exclude      /livereload.net\/files\/ffopen\/index.html$/
// @icon         data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEgAAABICAMAAABiM0N1AAAAAXNSR0IB2cksfwAAAAlwSFlzAAAOxAAADsQBlSsOGwAAAHJQTFRFAAAAEIijAo2yAI60BYyuF4WaFIifAY6zBI2wB4usGIaZEYigIoiZCIyrE4igG4iYD4mjEomhFoedCoqpDIqnDomlBYyvE4efEYmiDYqlA42xBoytD4mkCYqqGYSUFYidC4qoC4upAo6yCoupDYqmCYur4zowOQAAACZ0Uk5TAO////9vr////1+/D/+/L+/Pf/////+f3///////H4////////+5G91rAAACgUlEQVR4nM2Y22KjIBCGidg1264liZqDadK03X3/V2wNKHMC7MpF/xthHD5mgERAqZhWhfYqH6K+Qf2qNNf625hCoFj9/gblMUi5q5jLkXLCKudgyiRm0FMK82cWJp1fLbV5VmvJbCIc0GCYaFqqlDJgADdBjncqAXYobm1xh72aFMflbysteFfdy2Yi1XGOm5HGBzQ1dq7TzEoxjeNTjQZb7VA3e1c7+ImgasAgQ9+xusNVNZIo5xmOMgihIS2PbCQIiHEUdTvhxCcS/kPomfFI2zHy2PkWmA6aNatIJpKFJyekyy02xh5Y3DI9T4aOT6VhIUrsNTFp1pf79Z4SIIVDegl6IJO6cHiL/GimIZDhgTu/BlYWCQzHMl0zBWT/T3KAhtxOuUB9FtBrpsz0RV4xsjHmW+UCaffcSy/5viMGer0/6HdFNMZBq/vjJL38H9Dqx4Fuy0Em12DbZy+9pGtiDijbglwAehyj11n0tRD3WUBm+lwulE/8h4BuA+iWAQQnteg2Xm63WQLTpnMnpjdge0Mgu/GRPsV4xdjQ94Lfi624fabhDkfUqIKNrM64Q837v8yL0prasepCgrtvw1sJpoqanGEX7b5mQboNW8eawXaWXTMfMGxub472hzWzHSn6Sg2G9+6TAyRruE71s+zAzjWaknoyJCQzwxrghH2k5FDT4eqWunuNxyN9QCGcxVod5oADbYnIUkDTGZEf1xDJnSFteQ3KdsT8zYDMQXcHxsevcLH1TrsABzkNPyA/L7b0jg704viMMlpQI96WsHknCt/3YH0kOEo9zcGkwrFK39ck72rmoehmKqo2RKlilzSy/nJKEV45CT38myJp456fezktHjN5aeMAAAAASUVORK5CYII=
// @grant        none
// @namespace https://greasyfork.org/users/1184528
// ==/UserScript==
const a = loadlib("allfuncs")
const newelem = loadlib("newelem")
a(function (elem) {
  if (elem.title && !elem.title.includes("\u202e\u202d")) {
    let x = elem.title && getdate(elem.title)
    if (x) elem.title = elem.title.replace(x.string, getstr(x))
  }
  if (elem.tagName.toLowerCase() == "relative-time") {
    if (!elem.shadowRoot || elem.shadowRoot.innerHTML.includes("\u202e\u202d"))
      return
    elem = elem.shadowRoot
    let x = getdate(elem.innerHTML)
    if (!x) return
    replaceall(
      new RegExp(regescape(x.string)),
      (e) =>
        newelem("timediff", {
          innerHTML: getstr(x),
        }),
      elem,
      ["script", "style", "timediff", "input", "textarea"]
    )
    return
  }

  if (!elem.innerHTML.includes("\u202e\u202d")) {
    let x = getdate(elem.innerHTML)
    if (!x) return
    replaceall(
      new RegExp(regescape(x.string)),
      (e) =>
        newelem("timediff", {
          innerHTML: getstr(x),
        }),
      elem,
      ["script", "style", "timediff", "input", "textarea"]
    )
  }
  function getstr(x) {
    return `[${howlongago(
      x.ms,
      -3,
      true
    )} ${howlongago(x.ms, -3, true) == "today" ? "" : x.isago ? "ago" : "until"} ${x.string}\u202e\u202d]`
  }
}).runonallelems()
function regescape(reg) {
  return reg.replaceAll(/[.*+?^${}()|[\]\\]/g, "\\$&")
}
function replaceall(regex, getelem, node = document.body, ignores = []) {
  var search, newelement, splitnode, splittext, i, childnode
  if (node.nodeType == 3) {
    search = node.data.search(regex)
    if (search >= 0) {
      splitnode = node.splitText(search)
      splittext = splitnode.splitText(RegExp.lastMatch.length)
      newelement = getelem(splitnode.data)
      if (!ignores.includes(newelement.tagName.toLowerCase()))
        ignores.push(newelement.tagName.toLowerCase())
      splitnode.innerHTML = splitnode.textContent = ""
      newelement.appendChild(splitnode)
      splittext.parentNode.insertBefore(newelement, splittext)
    }
  } else if (
    node.nodeType == 11 ||
    (node.tagName && !ignores.includes(node.tagName.toLowerCase()))
  )
    for (i = 0; (childnode = node.childNodes[i]); ++i)
      replaceall(regex, getelem, childnode, ignores)
}

function howlongago(ms, remove = 0, showweeks) {
  remove--
  var time = ["year", "day", "hour", "minute", "second", "milisecond"]
  var x = Object.values(a(ms).fromms().val)
  x = x.slice(0, remove)
  if (x.find((e) => e !== 0)) {
    time.splice(0, x.indexOf(x.find((e) => e !== 0)))
    x.splice(0, x.indexOf(x.find((e) => e !== 0)))
    var temp = x.map((e, i) => `${e} ${time[i]}${e == 1 ? "" : "s"}`).join(" ")
    if (showweeks)
      temp = temp.replace(
        /(\d+) days?/,
        (_, days) =>
          `${
            Math.floor(days / 7)
              ? `${Math.floor(days / 7)} week${days >= 14 ? "s" : ""}`
              : ""
          }${
            days / 7 == Math.floor(days / 7)
              ? ""
              : ` ${days % 7} day${days % 7 == 1 ? "" : "s"}`
          }`
      )
    return temp
  }
  window.x = [...x]
  return (
    //`0 ${time[x.length - 1]}s` ||
    "today"
  )
}
function getdate(date) {
  const tonum = {
    january: 1,
    february: 2,
    march: 3,
    april: 4,
    may: 5,
    june: 6,
    july: 7,
    august: 8,
    september: 9,
    october: 10,
    november: 11,
    december: 12,
    jan: 1,
    feb: 2,
    mar: 3,
    apr: 4,
    jun: 6,
    jul: 7,
    aug: 8,
    sep: 9,
    oct: 10,
    nov: 11,
    dec: 12,
  }

  function f(reg) {
    reg = String(reg).replaceAll(/^\/|\/[gimsueyx]*$/g, "")
    ;[
      ["d2", "\\d{2}(?:rd|th|nd|st)?"],
      ["d4", "\\d{4}(?:rd|th|nd|st)?"],
      ["d12", "\\d{1,2}(?:rd|th|nd|st)?"],
      [
        "monthname",
        "(?:jan(?:uary)?|feb(?:ruary)?|Mar(?:ch)?|Apr(?:il)?|may|june?|july?|Aug(?:ust)?|Sep(?:tember)?|Oct(?:ober)?|Nov(?:ember)?|Dec(?:ember)?)",
      ],
      ["space", "[^a-z0-9.]"],
      ["start", "(?<![\\d\\w/])"],
      ["end", "(?![\\d\\w])"],
    ].forEach(([a, s]) => {
      reg = reg.replaceAll(a, s)
    })
    return new RegExp(reg, "i")
  }

  function d({ day, month, year, string }) {
    day = Number(day.match(/\d+/)[0])
    month = tonum[month?.toLowerCase?.()] || Number(month)
    if (!month) return
    if (day > 31) return
    year = Number(
      year.length == 2
        ? String(new Date().getFullYear()).substring(0, 2) + year
        : year
    )
    var today = new Date()
    today.setHours(0, 0, 0, 0)
    var ms = today - new Date(year, month - 1, day)
    return {
      day,
      month,
      year,
      string,
      ms: Math.abs(ms),
      isago: ms > 0,
    }
  }
  var temp
  if (
    (temp = date.match(f(/start(monthname|d12)space+(d12)sapce*'(d4|d2)end/)))
  )
    return d({
      day: temp[2],
      month: temp[1],
      year: temp[3],
      string: temp[0],
    })
  if ((temp = date.match(f(/start(d12)([\/\-])(d12)\2(d4|d2)end/))))
    return d({
      day: temp[3],
      month: temp[1],
      year: temp[4],
      string: temp[0],
    })

  if ((temp = date.match(f(/start(d12)([\/\-])(d12)\2(d4|d2)end/))))
    return d({
      day: temp[3],
      month: temp[1],
      year: temp[4],
      string: temp[0],
    })

  if ((temp = date.match(f(/start(d4)([\/\-])(d12)\2(d12)end/))))
    return d({
      day: temp[4],
      month: temp[3],
      year: temp[1],
      string: temp[0],
    })

  if ((temp = date.match(f(/start(monthname)space*(d12)space+(d4)end/))))
    return d({
      day: temp[2],
      month: temp[1],
      year: temp[3],
      string: temp[0],
    })

  if ((temp = date.match(f(/start(monthname)(d12)(d4)end/))))
    return d({
      day: temp[2],
      month: temp[1],
      year: temp[3],
      string: temp[0],
    })

  if ((temp = date.match(f(/start(d12)(monthname)(d4)end/))))
    return d({
      day: temp[1],
      month: temp[2],
      year: temp[3],
      string: temp[0],
    })

  if ((temp = date.match(f(/start(d4)(monthname)(d12)end/))))
    return d({
      day: temp[3],
      month: temp[2],
      year: temp[1],
      string: temp[0],
    })

  if ((temp = date.match(f(/start(d12)space*(monthname)space*(d4)end/))))
    return d({
      day: temp[1],
      month: temp[2],
      year: temp[3],
      string: temp[0],
    })
  if ((temp = date.match(f(/start(d4)space*(monthname)space*(d12)end/))))
    return d({
      day: temp[3],
      month: temp[2],
      year: temp[1],
      string: temp[0],
    })
  if ((temp = date.match(f(/start(monthname)space*(d12)end/))))
    return d({
      day: temp[2],
      month: temp[1],
      year: new Date().getFullYear(),
      string: temp[0],
    })
}