/operate/ - Endchan Operations

Let us know what's up

Posting mode: Reply

Check to confirm you're not a robot
Name
Email
Subject
Comment
Password
Drawing x size canvas
File(s)

Board Rules

Max file size: 350.00 MB

Max files: 5

Max message length: 4096

Manage Board | Moderate Thread

Return | Magrathea | Catalog | Bottom

Expand All Images


(39.59 KB 1280x720 js.jpg)
Userscripts for Endchan Anonymous 08/27/2025 (Wed) 03:12 [Preview] No. 29379
Userscripts are a way to add extra functionality to a site using Javascript.
To use them, add either the Violentmonkey or Tampermonkey extension to your browser.
https://violentmonkey.github.io/
https://www.tampermonkey.net/

>Where To Get Userscripts
GitHub Gists: https://gist.github.com/search?q=%3D%3DUserScript%3D%3D (Search for UserScript)
Greasy Fork: https://greasyfork.org/en

>Userscript Development Resources
How To Write A Userscript: https://simply-how.com/enhance-and-fine-tune-any-web-page-the-complete-user-scripts-guide
GM_* API: https://violentmonkey.github.io/api/gm/


Anonymous 08/27/2025 (Wed) 03:52 [Preview] No.29380 del
(3.53 MB 576x1024 stikstikstik.mp4)
This is a userscript that lets you view images and videos on hover. It needs a few usability improvements, but it mostly works.
// ==UserScript==
// @name        endchan.org media on hover
// @namespace   Violentmonkey Scripts
// @match       https://endchan.org/*/res/*.html*
// @grant       none
// @version     1.1
// @author      -
// @description Display media by hovering over it.
// ==/UserScript==

function createHoverImageContainer() {
  const div = document.createElement("div")
  div.id = "hoverImage"
  const img = document.createElement("img")
  div.appendChild(img)
  return div
}

function createHoverVideoContainer() {
  const div = document.createElement("div")
  div.id = "hoverVideo"
  return div
}

function deriveVideoSrc(imgSrc) {
  const m = imgSrc.match(RegExp("/.media/(t_)(.*)-video(.*)"))
  const videoSrc = `/.media/${m[2]}-video${m[3]}.${m[3]}`
  return { src: videoSrc, type: `video/${m[3]}` }
}

function displayOnHover(ev) {
  const target = ev.target
  const parent = target.parentElement
  const hi = document.getElementById("hoverImage")
  const hii = hi.querySelector("img")
  const hv = document.getElementById("hoverVideo")

  //console.log(target, parent)
  if (target.tagName == "IMG" && parent.classList.contains("imgLink")) {
    hii.src = parent.href
    hi.classList.add("enabled")
  }
  if (target.tagName == "IMG" && parent.tagName == "SPAN") {
    hv.classList.add("enabled")
    const hvv = document.createElement("video")
    hvv.setAttribute("controls", "true")
    hvv.setAttribute("autoplay", "true")
    hv.appendChild(hvv)
    const r = deriveVideoSrc(target.src)
    hvvs = document.createElement("source")
    hvvs.type = r.type
    hvvs.src = `https://endchan.org${r.src}`
    hvv.append(hvvs)
    hvv.play()
  }
}

function hideOnLeave(ev) {
  const target = ev.target
  const parent = target.parentElement
  const hi = document.getElementById("hoverImage")
  const hii = hi.querySelector("img")
  const hv = document.getElementById("hoverVideo")

  //console.log(target, parent)
  if (target.tagName == "IMG" && parent.classList.contains("imgLink")) {
    hii.src = parent.href
    hi.classList.remove("enabled")
  }
  if (target.tagName == "IMG" && parent.tagName == "SPAN") {
    //hv.classList.remove("enabled")
    hvv = hv.querySelector("video")
    hv.classList.remove("enabled")
    hvv.remove()
  }
}

const css = `
#hoverImage {
  display: none;
  position: fixed;
  top: 0;
  right: 0;
}

#hoverImage.enabled {
  display: block;
}

#hoverImage img {
  max-width: 100vw;
  max-height: 100vh;
}

#hoverVideo {
  display: none;
  position: fixed;
  top: 0;
  right: 0;
}

#hoverVideo.enabled {
  display: block;
}

#hoverVideo video {
  max-width: 100vw;
  max-height: 100vh;
}
`

// Add CSS
let style = document.createElement("style");
style.type = "text/css";
style.appendChild(document.createTextNode(css));
document.head.appendChild(style);

// setup container for image
document.body.append(createHoverImageContainer())
document.body.append(createHoverVideoContainer())

// setup event handlers
document.addEventListener('mouseover', displayOnHover)
document.addEventListener('mouseout', hideOnLeave)


Anonymous 08/27/2025 (Wed) 03:55 [Preview] No.29381 del
>>29380
In my experience, the autoplay for the videos needs to be nudged a little bit to work. Play a video normally by clicking on it. Then, autoplay on hove will work for the remainder of the videos on the page.


Anonymous 08/27/2025 (Wed) 04:28 [Preview] No.29382 del
(2.20 MB 1303x1199 hover.webm)
Demo


Anonymous 08/27/2025 (Wed) 11:43 [Preview] No.29383 del
Version 1.2
- Works on both endchan.org and endchan.net.
- Fixed bug when overlapping hovered elements confused the script.

// ==UserScript==
// @name        endchan.org media on hover
// @namespace   Violentmonkey Scripts
// @match       https://endchan.*/*/res/*.html
// @match       https://endchan.*/*/
// @grant       none
// @version     1.2
// @author      -
// @description Display media by hovering over it.
// ==/UserScript==

function createHoverImageContainer() {
  const div = document.createElement("div")
  div.id = "hoverImage"
  const img = document.createElement("img")
  div.appendChild(img)
  return div
}

function createHoverVideoContainer() {
  const div = document.createElement("div")
  div.id = "hoverVideo"
  return div
}

function deriveVideoSrc(imgSrc) {
  const m = imgSrc.match(RegExp("/.media/(t_)(.*)-video(.*)"))
  const videoSrc = `/.media/${m[2]}-video${m[3]}.${m[3]}`
  return { src: videoSrc, type: `video/${m[3]}` }
}

function displayOnHover(ev) {
  const target = ev.target
  const parent = target.parentElement
  const hi = document.getElementById("hoverImage")
  const hii = hi.querySelector("img")
  const hv = document.getElementById("hoverVideo")

  //console.log(target, parent)
  if (target.tagName == "IMG" && parent.classList.contains("imgLink")) {
    hii.src = parent.href
    hi.classList.add("enabled")
  }
  if (target.tagName == "IMG" && parent.tagName == "SPAN") {
    hv.classList.add("enabled")
    const hvv = document.createElement("video")
    hvv.setAttribute("controls", "true")
    hvv.setAttribute("autoplay", "true")
    hv.appendChild(hvv)
    const r = deriveVideoSrc(target.src)
    hvvs = document.createElement("source")
    hvvs.type = r.type
    hvvs.src = `${r.src}`
    hvv.append(hvvs)
    hvv.play()
  }
}

function hideOnLeave(ev) {
  const target = ev.target
  const parent = target.parentElement
  const hi = document.getElementById("hoverImage")
  const hii = hi.querySelector("img")
  const hv = document.getElementById("hoverVideo")

  //console.log(target, parent)
  if (target.tagName == "IMG" && parent.classList.contains("imgLink")) {
    hii.src = parent.href
    hi.classList.remove("enabled")
  }
  if (target.tagName == "IMG" && parent.tagName == "SPAN") {
    //hv.classList.remove("enabled")
    hvv = hv.querySelector("video")
    hv.classList.remove("enabled")
    hvv.remove()
  }
}

// https://stackoverflow.com/a/47460565
const css = `
#hoverImage {
  display: none;
  pointer-events: none;
  position: fixed;
  top: 0;
  right: 0;
}

#hoverImage.enabled {
  display: block;
}

#hoverImage img {
  max-width: 100vw;
  max-height: 100vh;
}

#hoverVideo {
  display: none;
  pointer-events: none;
  position: fixed;
  top: 0;
  right: 0;
}

#hoverVideo.enabled {
  display: block;
}

#hoverVideo video {
  max-width: 100vw;
  max-height: 100vh;
}
`

// Add CSS
let style = document.createElement("style");
style.type = "text/css";
style.appendChild(document.createTextNode(css));
document.head.appendChild(style);

// setup container for image
document.body.append(createHoverImageContainer())
document.body.append(createHoverVideoContainer())

// setup event handlers
document.addEventListener('mouseover', displayOnHover)
document.addEventListener('mouseout', hideOnLeave)


Anonymous 08/27/2025 (Wed) 11:59 [Preview] No.29384 del
>>29381
It might just be autoplay on mp4 files that's slightly buggy.

>>29380
This mp4 doesn't autoplay on first try. I have to manually click it once. Then, every subsequent hover will autoplay.

>>29382
This webm autoplays every time. No nudging needed.


Anonymous 08/27/2025 (Wed) 15:14 [Preview] No.29385 del
(34.36 KB 509x375 image.png)
(27.72 KB 519x255 image.png)
Userscript to add hoverable images / videos, post inlining, clipboard image pasting, keyboard shortcuts for spoiler, bold text, etc.
Adds various other things as well, and fixes some bugs on endchan (which might since have been fixed), such as posts by certain IDs not updating correctly, and post hiding
https://github.com/JacobSvenningsen/endchan-script


Anonymous 08/27/2025 (Wed) 16:25 [Preview] No.29386 del
>>29384
Videos with different codecs might behave differently.

>>29384
Cheers.


Anonymous 08/27/2025 (Wed) 23:21 [Preview] No.29388 del
>>29385
If I knew this existed, I wouldn't have written
>>29383
.

It was a good little learning exercise, I guess.


Anonymous 08/27/2025 (Wed) 23:28 [Preview] No.29389 del
>>29385
- It's interesting that we both decided to position the hovered media in the same spot (the top right).
- More interesting is that autoplay on the mp4 works for your script on the first try.
- I have to look into that to see what you did differently.
- I like the settings UI, too.
- I've never made a settings UI for any of my userscripts, but it's something that would be nice to have sometimes.


Anonymous 08/29/2025 (Fri) 11:21 [Preview] No.29390 del
>>29381
I tried this in Brave, and autoplay seems to be fine from the start. No nudging needed.


Anonymous 08/29/2025 (Fri) 13:40 [Preview] No.29391 del
>>29388
You learned something new. That's the most important part of it.
And next time you find something annoying about a website, you'll have a much easier time fixing it with a userscript too.

>>29389
If new posts are loaded throug page auto refreshing, the script isn't applied, as it only runs once. That's what the MutationObserver handles.
Moreover, posts present on the page when you load the thread, and posts which gets added during auto-refresh, varies slightly.


Anonymous 09/17/2025 (Wed) 23:31 [Preview] No.29425 del
I made a rough proof-of-concept that tries to fix tiktok embeds here. The code is too long to post, so you can find it here:

https://git.vern.cc/gg/endchan-scripts

Example
>>>/jp/1507
https://www.tiktok.com/@mina14504/video/7546151220046613776 [Embed]

It's really rough, but it does manage to successfully embed tiktok videos.


Anonymous Admin 09/22/2025 (Mon) 10:42 [Preview] No.29443 del
>>29425
Thanks, I pass it on.


Anonymous 10/20/2025 (Mon) 10:29 [Preview] No.29485 del
Скрипт на скрытие Капсодауна

Работает на Tampermonkey (как минимум).
Распространяется на основной домен, на magrathea, а также .onion'ы.

Ссылка::
https://pastebin.com/XcCnMUru

Спасибо bb-мочуху за бездействие ^^



Top | Catalog | Post a reply | Magrathea | Return